【转  http://blog.csdn.net/ronotian/article/details/3159595

 

本文我们实现一个简单的通过拖动鼠标来增加控件的方法。

在我们使用vs2005来开发WinForm应用程序的时候,我们通过选择左边“工具箱”中的某个控件,然后在我们自己的窗体上通过拖动鼠标,一个我们需要的控件就出现了,觉得很爽!其实vs2005中已经有这方面的组件,我们通过简单的代码就可以直接使用,这个你可以用“窗体设计器”Google一下,已经有人做了这方面的介绍。

所以我要说的是,难道除了使用vs2005中提供的这个标准组件,就不能自己弄出一个来?即使不够强大,但是最终都是自己折腾出来的,所以也会很爽。下面我就这个功能点做一个介绍,实现效果图如下:

 

 

实现关键点:

1、动态加载控件:

vs2005中,在某个容器控件上增加新的子控件相当的简单,语法如下,如,增加一个TextBox

Control.Controls.Add(new TextBox());

 

2、选择要添加的控件:

通过一个全局的单件类来实现。

 

3、捕获窗体(或者容器控件,比如PanelGroupBox等)上鼠标的移动区域,并绘制选择框,如上图中黑色的框。

 

对于1,是很容易实现的,所以不是我们讨论的重点,我主要讨论23点。

 

第2点:选择需要添加的控件,为了尽量的使Winform中的代码简洁,以及和其它的部分解耦,我们尽量不要考虑在WinForm中使用全局变量或者与其它模块通信的接口。所以我们使用一个单件类SettingService来作为Winform和其它部分通信的中介。

  1. public class SettingService
  2. {
  3.     private static SettingService _Instance;
  4.     private System.Windows.Forms.Control _SelectedToolBoxControl;
  5.     /// <summary>
  6.     /// 在Form中,选择了某个要添加的控件后,这里保存这个控件的一个新实例
  7.     /// </summary>
  8.     public System.Windows.Forms.Control SelectedToolBoxControl
  9.     {
  10.         get { return this._SelectedToolBoxControl; }
  11.         set { this._SelectedToolBoxControl = value; }
  12.     }
  13.     private SettingService()
  14.     { }
  15.     /// <summary>
  16.     /// 这里使用单件
  17.     /// </summary>
  18.     public static SettingService Instance
  19.     {
  20.         get
  21.         {
  22.             if (_Instance == null)
  23.             {
  24.                 _Instance = new SettingService();
  25.             }
  26.             return _Instance;
  27.         }
  28.     }
  29. }

3点:因为这里涉及到捕获鼠标的选择区域,并且在按照这个区域的起始以及大小绘制控件。要捕获鼠标,我们需要实现容器控件(Winform也是一个Control,所以这里称的容器控件包括WinForm)的Control_ MouseDown,Control_ MouseMove,Control_ MouseUp,Control_ MouseEnter这几个事件。

代码如下:

  1. public class MouseHook
  2. {
  3.     Control _Owner;
  4.    
  5.     private int _CLickAtX;
  6.     private int _ClickAtY;
  7.     private int _MoveAtX;
  8.     private int _MoveAtY;
  9.     private bool _BeginDrag;
  10.     private bool _BeginDrawControl;
  11.     /// <summary>
  12.     /// 这里Owner使用的是Control类型,是因为我们不仅仅需要在Winform上增加控件,
  13.     /// 也需要在其它容器,比如Panel,GroupBox等上面增加容器
  14.     /// </summary>
  15.     /// <param name="Owner"></param>
  16.     public MouseHook(System.Windows.Forms.Control Owner)
  17.     {
  18.         this._Owner = Owner;
  19.         this._Owner.MouseDown += new MouseEventHandler(this.Control_MouseDown);
  20.         this._Owner.MouseMove += new MouseEventHandler(this.Control_MouseMove);
  21.         this._Owner.MouseUp += new MouseEventHandler(this.Control_MouseUp);
  22.         this._Owner.MouseEnter += new EventHandler(this.Control_MouseEnter);
  23.         this._BeginDrawControl = false;
  24.     }
  25.     #region Control上的鼠标事件
  26.     void Control_MouseDown(object sender, MouseEventArgs e)
  27.     {
  28.         //如果没有选择控件,那么退出
  29.         if (SettingService.Instance.SelectedToolBoxControl == null)
  30.         {
  31.             return;
  32.         }
  33.         this._CLickAtX = e.X;
  34.         this._ClickAtY = e.Y;
  35.         this._MoveAtX = e.X;
  36.         this._MoveAtY = e.Y;
  37.         this._BeginDrag = true;
  38.         if (SettingService.Instance.SelectedToolBoxControl != null)
  39.         {
  40.             this._BeginDrawControl = true;
  41.         }
  42.         else
  43.         {
  44.             this._BeginDrawControl = false;
  45.         }
  46.     }
  47.     void Control_MouseMove(object sender, MouseEventArgs e)
  48.     {
  49.         if (SettingService.Instance.SelectedToolBoxControl == null)
  50.         {
  51.             return;
  52.         }
  53.         if (this._BeginDrag)
  54.         {
  55.             //取消上次绘制的选择框
  56.             int iLeft, iTop, iWidth, iHeight;
  57.             Pen pen;
  58.             Rectangle rect;
  59.             pen = new Pen(this._Owner.BackColor);
  60.             if (this._BeginDrawControl == true)
  61.             {
  62.                 pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
  63.                 pen.Width = 2;
  64.             }
  65.             else
  66.             {
  67.                 pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
  68.             }
  69.             iLeft = this._CLickAtX < this._MoveAtX ? this._CLickAtX : this._MoveAtX;
  70.             iTop = this._ClickAtY < this._MoveAtY ? this._ClickAtY : this._MoveAtY;
  71.             iWidth = Math.Abs(this._MoveAtX - this._CLickAtX);
  72.             iHeight = Math.Abs(this._MoveAtY - this._ClickAtY);
  73.             rect = new Rectangle(iLeft, iTop, iWidth, iHeight);
  74.             this._Owner.CreateGraphics().DrawRectangle(pen, rect);
  75.             //重新绘制选择框
  76.             this._MoveAtX = e.X;
  77.             this._MoveAtY = e.Y;
  78.             pen = new Pen(Color.Black);
  79.             if (this._BeginDrawControl == true)
  80.             {
  81.                 pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
  82.                 pen.Width = 2;
  83.             }
  84.             else
  85.             {
  86.                 pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
  87.             }
  88.             iLeft = this._CLickAtX < this._MoveAtX ? this._CLickAtX : this._MoveAtX;
  89.             iTop = this._ClickAtY < this._MoveAtY ? this._ClickAtY : this._MoveAtY;
  90.             iWidth = Math.Abs(this._MoveAtX - this._CLickAtX);
  91.             iHeight = Math.Abs(this._MoveAtY - this._ClickAtY);
  92.             rect = new Rectangle(iLeft, iTop, iWidth, iHeight);
  93.             this._Owner.CreateGraphics().DrawRectangle(pen, rect);
  94.         }
  95.     }
  96.     void Control_MouseUp(object sender, MouseEventArgs e)
  97.     {
  98.         this._BeginDrag = false;
  99.         this._Owner.SuspendLayout();
  100.         if (SettingService.Instance.SelectedToolBoxControl == null)
  101.         {
  102.             return;
  103.         }
  104.         //取消上次绘制的选择框
  105.         int iLeft, iTop, iWidth, iHeight;
  106.         Pen pen;
  107.         Rectangle rect;
  108.         pen = new Pen(this._Owner.BackColor);
  109.         pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
  110.         iLeft = this._CLickAtX < this._MoveAtX ? this._CLickAtX : this._MoveAtX;
  111.         iTop = this._ClickAtY < this._MoveAtY ? this._ClickAtY : this._MoveAtY;
  112.         iWidth = Math.Abs(this._MoveAtX - this._CLickAtX);
  113.         iHeight = Math.Abs(this._MoveAtY - this._ClickAtY);
  114.         rect = new Rectangle(iLeft, iTop, iWidth, iHeight);
  115.         this._Owner.CreateGraphics().DrawRectangle(pen, rect);
  116.         if (SettingService.Instance.SelectedToolBoxControl != null)
  117.         {
  118.             AddControl(SettingService.Instance.SelectedToolBoxControl, rect);
  119.         }
  120.         else
  121.         {
  122.             //这里是拖动鼠标,选择控件,这里将会在后续的介绍中给出
  123.         }
  124.         this._Owner.Refresh();
  125.         this._Owner.ResumeLayout();
  126.     }
  127.     void Control_MouseEnter(object sender, EventArgs e)
  128.     {
  129.         if (SettingService.Instance.SelectedToolBoxControl != null)
  130.         {
  131.             this._Owner.Cursor = Cursors.Cross;
  132.         }
  133.         else
  134.         {
  135.             this._Owner.Cursor = Cursors.Default;
  136.         }
  137.     }
  138.     private void AddControl(System.Windows.Forms.Control control, Rectangle rect)
  139.     {
  140.         try
  141.         {
  142.             control.Location = rect.Location;
  143.             control.Size = rect.Size;
  144.             control.Name = GetControlName(control);
  145.             //因为对于DataTimePiker控件来说不能设置.Text为非日期型,所以忽略错误
  146.             try
  147.             {
  148.                 control.Text = GetControlType(control);
  149.             }
  150.             catch { }
  151.             this._Owner.Controls.Add(control);
  152.             control.Visible = true;
  153.             this._Owner.Cursor = Cursors.Default;
  154.             SettingService.Instance.SelectedToolBoxControl = null;
  155.         }
  156.         catch (Exception e)
  157.         {
  158.             this._Owner.Cursor = Cursors.Default;
  159.             SettingService.Instance.SelectedToolBoxControl = null;
  160.         }
  161.     }
  162.     private string GetControlType(System.Windows.Forms.Control ctrl)
  163.     {
  164.         string strType = ctrl.GetType().ToString();
  165.         string strControlType;
  166.         string[] strArr = strType.Split(".".ToCharArray());
  167.         strControlType = strArr[strArr.Length - 1].Trim();
  168.         return strControlType;
  169.     }
  170.     private string GetControlName(System.Windows.Forms.Control control)
  171.     {
  172.         //这里简单返回控件名,如果需要,可以通过修改这个函数做特殊处理
  173.         return control.GetType().Name;
  174.     }
  175.     #endregion
  176. }

另外Form代码如下,这里为了方便,我直接先使用几个Button来替代实际中的ToolBox:

  1. //在Form中增加几个Button,分别命名为cmdArrow,cmdLabel,cmdTextBox,cmdComboBox,cmdGroupBox
  2. public partial class Form1 : Form
  3. {       
  4.     private MouseHook _MouseHook;
  5.     public Form1()
  6.     {
  7.         InitializeComponent();
  8.         this._MouseHook = new MouseHook(this);
  9.     }
  10.    
  11.     private void cmdArrow_Click(object sender, EventArgs e)
  12.     {
  13.         SettingService.Instance.SelectedToolBoxControl = null;
  14.     }
  15.     private void cmdLabel_Click(object sender, EventArgs e)
  16.     {
  17.         SettingService.Instance.SelectedToolBoxControl = new Label();
  18.     }
  19.     private void cmdTextBox_Click(object sender, EventArgs e)
  20.     {
  21.         SettingService.Instance.SelectedToolBoxControl = new TextBox();
  22.     }
  23.     private void cmdComboBox_Click(object sender, EventArgs e)
  24.     {
  25.         SettingService.Instance.SelectedToolBoxControl = new ComboBox();
  26.     }
  27.     private void cmdGroupBox_Click(object sender, EventArgs e)
  28.     {
  29.         SettingService.Instance.SelectedToolBoxControl = new GroupBox();
  30.     }
  31. }

上面就是简单实现拖动增加控件的方法,如果要在GroupBox中增加控件的话,只需要再new 一个MouseHook,如:new MouseHook(GroupBoxControl)这样就可以了的。