本文我们实现一个简单的通过拖动鼠标来增加控件的方法。
在我们使用vs2005来开发WinForm应用程序的时候,我们通过选择左边“工具箱”中的某个控件,然后在我们自己的窗体上通过拖动鼠标,一个我们需要的控件就出现了,觉得很爽!其实vs2005中已经有这方面的组件,我们通过简单的代码就可以直接使用,这个你可以用“窗体设计器”Google一下,已经有人做了这方面的介绍。
所以我要说的是,难道除了使用vs2005中提供的这个标准组件,就不能自己弄出一个来?即使不够强大,但是最终都是自己折腾出来的,所以也会很爽。下面我就这个功能点做一个介绍,实现效果图如下:
实现关键点:
1、动态加载控件:
在vs2005中,在某个容器控件上增加新的子控件相当的简单,语法如下,如,增加一个TextBox:
Control.Controls.Add(new TextBox());
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
2、选择要添加的控件:
通过一个全局的单件类来实现。
3、捕获窗体(或者容器控件,比如Panel,GroupBox等)上鼠标的移动区域,并绘制选择框,如上图中黑色的框。
对于1,是很容易实现的,所以不是我们讨论的重点,我主要讨论2和3点。
第2点:选择需要添加的控件,为了尽量的使Winform中的代码简洁,以及和其它的部分解耦,我们尽量不要考虑在WinForm中使用全局变量或者与其它模块通信的接口。所以我们使用一个单件类SettingService来作为Winform和其它部分通信的中介。
- publicclassSettingService
- {
- privatestaticSettingService_Instance;
- privateSystem.Windows.Forms.Control_SelectedToolBoxControl;
- ///<summary>
- ///在Form中,选择了某个要添加的控件后,这里保存这个控件的一个新实例
- ///</summary>
- publicSystem.Windows.Forms.ControlSelectedToolBoxControl
- {
- get{returnthis._SelectedToolBoxControl;}
- set{this._SelectedToolBoxControl=value;}
- }
- privateSettingService()
- {}
- ///<summary>
- ///这里使用单件
- ///</summary>
- publicstaticSettingServiceInstance
- {
- get
- {
- if(_Instance==null)
- {
- _Instance=newSettingService();
- }
- return_Instance;
- }
- }
- }
第3点:因为这里涉及到捕获鼠标的选择区域,并且在按照这个区域的起始以及大小绘制控件。要捕获鼠标,我们需要实现容器控件(Winform也是一个Control,所以这里称的容器控件包括WinForm)的Control_ MouseDown,Control_ MouseMove,Control_ MouseUp,Control_ MouseEnter这几个事件。
代码如下:
- publicclassMouseHook
- {
- Control_Owner;
- privateint_CLickAtX;
- privateint_ClickAtY;
- privateint_MoveAtX;
- privateint_MoveAtY;
- privatebool_BeginDrag;
- privatebool_BeginDrawControl;
- ///<summary>
- ///这里Owner使用的是Control类型,是因为我们不仅仅需要在Winform上增加控件,
- ///也需要在其它容器,比如Panel,GroupBox等上面增加容器
- ///</summary>
- ///<paramname="Owner"></param>
- publicMouseHook(System.Windows.Forms.ControlOwner)
- {
- this._Owner=Owner;
- this._Owner.MouseDown+=newMouseEventHandler(this.Control_MouseDown);
- this._Owner.MouseMove+=newMouseEventHandler(this.Control_MouseMove);
- this._Owner.MouseUp+=newMouseEventHandler(this.Control_MouseUp);
- this._Owner.MouseEnter+=newEventHandler(this.Control_MouseEnter);
- this._BeginDrawControl=false;
- }
- #regionControl上的鼠标事件
- voidControl_MouseDown(objectsender,MouseEventArgse)
- {
- //如果没有选择控件,那么退出
- if(SettingService.Instance.SelectedToolBoxControl==null)
- {
- return;
- }
- this._CLickAtX=e.X;
- this._ClickAtY=e.Y;
- this._MoveAtX=e.X;
- this._MoveAtY=e.Y;
- this._BeginDrag=true;
- if(SettingService.Instance.SelectedToolBoxControl!=null)
- {
- this._BeginDrawControl=true;
- }
- else
- {
- this._BeginDrawControl=false;
- }
- }
- voidControl_MouseMove(objectsender,MouseEventArgse)
- {
- if(SettingService.Instance.SelectedToolBoxControl==null)
- {
- return;
- }
- if(this._BeginDrag)
- {
- //取消上次绘制的选择框
- intiLeft,iTop,iWidth,iHeight;
- Penpen;
- Rectanglerect;
- pen=newPen(this._Owner.BackColor);
- if(this._BeginDrawControl==true)
- {
- pen.DashStyle=System.Drawing.Drawing2D.DashStyle.Solid;
- pen.Width=2;
- }
- else
- {
- pen.DashStyle=System.Drawing.Drawing2D.DashStyle.Dot;
- }
- iLeft=this._CLickAtX<this._MoveAtX?this._CLickAtX:this._MoveAtX;
- iTop=this._ClickAtY<this._MoveAtY?this._ClickAtY:this._MoveAtY;
- iWidth=Math.Abs(this._MoveAtX-this._CLickAtX);
- iHeight=Math.Abs(this._MoveAtY-this._ClickAtY);
- rect=newRectangle(iLeft,iTop,iWidth,iHeight);
- this._Owner.CreateGraphics().DrawRectangle(pen,rect);
- //重新绘制选择框
- this._MoveAtX=e.X;
- this._MoveAtY=e.Y;
- pen=newPen(Color.Black);
- if(this._BeginDrawControl==true)
- {
- pen.DashStyle=System.Drawing.Drawing2D.DashStyle.Solid;
- pen.Width=2;
- }
- else
- {
- pen.DashStyle=System.Drawing.Drawing2D.DashStyle.Dot;
- }
- iLeft=this._CLickAtX<this._MoveAtX?this._CLickAtX:this._MoveAtX;
- iTop=this._ClickAtY<this._MoveAtY?this._ClickAtY:this._MoveAtY;
- iWidth=Math.Abs(this._MoveAtX-this._CLickAtX);
- iHeight=Math.Abs(this._MoveAtY-this._ClickAtY);
- rect=newRectangle(iLeft,iTop,iWidth,iHeight);
- this._Owner.CreateGraphics().DrawRectangle(pen,rect);
- }
- }
- voidControl_MouseUp(objectsender,MouseEventArgse)
- {
- this._BeginDrag=false;
- this._Owner.SuspendLayout();
- if(SettingService.Instance.SelectedToolBoxControl==null)
- {
- return;
- }
- //取消上次绘制的选择框
- intiLeft,iTop,iWidth,iHeight;
- Penpen;
- Rectanglerect;
- pen=newPen(this._Owner.BackColor);
- pen.DashStyle=System.Drawing.Drawing2D.DashStyle.Dot;
- iLeft=this._CLickAtX<this._MoveAtX?this._CLickAtX:this._MoveAtX;
- iTop=this._ClickAtY<this._MoveAtY?this._ClickAtY:this._MoveAtY;
- iWidth=Math.Abs(this._MoveAtX-this._CLickAtX);
- iHeight=Math.Abs(this._MoveAtY-this._ClickAtY);
- rect=newRectangle(iLeft,iTop,iWidth,iHeight);
- this._Owner.CreateGraphics().DrawRectangle(pen,rect);
- if(SettingService.Instance.SelectedToolBoxControl!=null)
- {
- AddControl(SettingService.Instance.SelectedToolBoxControl,rect);
- }
- else
- {
- //这里是拖动鼠标,选择控件,这里将会在后续的介绍中给出
- }
- this._Owner.Refresh();
- this._Owner.ResumeLayout();
- }
- voidControl_MouseEnter(objectsender,EventArgse)
- {
- if(SettingService.Instance.SelectedToolBoxControl!=null)
- {
- this._Owner.Cursor=Cursors.Cross;
- }
- else
- {
- this._Owner.Cursor=Cursors.Default;
- }
- }
- privatevoidAddControl(System.Windows.Forms.Controlcontrol,Rectanglerect)
- {
- try
- {
- control.Location=rect.Location;
- control.Size=rect.Size;
- control.Name=GetControlName(control);
- //因为对于DataTimePiker控件来说不能设置.Text为非日期型,所以忽略错误
- try
- {
- control.Text=GetControlType(control);
- }
- catch{}
- this._Owner.Controls.Add(control);
- control.Visible=true;
- this._Owner.Cursor=Cursors.Default;
- SettingService.Instance.SelectedToolBoxControl=null;
- }
- catch(Exceptione)
- {
- this._Owner.Cursor=Cursors.Default;
- SettingService.Instance.SelectedToolBoxControl=null;
- }
- }
- privatestringGetControlType(System.Windows.Forms.Controlctrl)
- {
- stringstrType=ctrl.GetType().ToString();
- stringstrControlType;
- string[]strArr=strType.Split(".".ToCharArray());
- strControlType=strArr[strArr.Length-1].Trim();
- returnstrControlType;
- }
- privatestringGetControlName(System.Windows.Forms.Controlcontrol)
- {
- //这里简单返回控件名,如果需要,可以通过修改这个函数做特殊处理
- returncontrol.GetType().Name;
- }
- #endregion
- }
另外Form代码如下,这里为了方便,我直接先使用几个Button来替代实际中的ToolBox:
- //在Form中增加几个Button,分别命名为cmdArrow,cmdLabel,cmdTextBox,cmdComboBox,cmdGroupBox
- publicpartialclassForm1:Form
- {
- privateMouseHook_MouseHook;
- publicForm1()
- {
- InitializeComponent();
- this._MouseHook=newMouseHook(this);
- }
- privatevoidcmdArrow_Click(objectsender,EventArgse)
- {
- SettingService.Instance.SelectedToolBoxControl=null;
- }
- privatevoidcmdLabel_Click(objectsender,EventArgse)
- {
- SettingService.Instance.SelectedToolBoxControl=newLabel();
- }
- privatevoidcmdTextBox_Click(objectsender,EventArgse)
- {
- SettingService.Instance.SelectedToolBoxControl=newTextBox();
- }
- privatevoidcmdComboBox_Click(objectsender,EventArgse)
- {
- SettingService.Instance.SelectedToolBoxControl=newComboBox();
- }
- privatevoidcmdGroupBox_Click(objectsender,EventArgse)
- {
- SettingService.Instance.SelectedToolBoxControl=newGroupBox();
- }
- }
上面就是简单实现拖动增加控件的方法,如果要在GroupBox中增加控件的话,只需要再new 一个MouseHook,如:new MouseHook(GroupBoxControl)这样就可以了的。