前言:
很多时候我们需要在运行时,动态地改变控件的位置以及大小,以获得更好的布局。比如说实际项目中的可自定义的报表、可自定义的单据等诸如此类。它们有个特点就是允许客户或者二次开发人员设计它们需要的界面设置功能。
本人以前也做过可自定义系统,包括界面和功能,主要为了减少开发人员的工作量以及程序的灵活性和健壮性。
本篇主要讨论下,在运行时如何实现拖拉控件,达到改变控件位置与大小。功能将模拟VS设计界面时的拖拉功能。
(本篇暂不涉及多控件同时操作)
一、技术概述
其实实现运行时控件的拖拉并不难,主要是改变控件的Location与Size即可。动态调整时再捕获MouseDown、MouseMove及MouseUp事件来实时修改上述两个属性就可以实现。
二、功能规划
在此之前,我们先来看下.net设计界面,一旦选中某个控件时,将会出现如下图的边框:
之后就可以通过拖拉出现的边框改变其大小。而改变控件的位置,实际上是当鼠标点击在控件内部拖动时实现的。
所有本例也将功能分为两个部分实现,分别为控件内部拖动改变位置与控件边框拖拉改变大小。
三、具体实现
1.拖动控件改变位置
首先,新建一个项目,然后添加一个类,取名叫MoveControl,该类用来给控件挂载事件实现拖动。
接着在该类中添加字段currentControl,用来保存需要操作的控件,即通过构造函数传递的控件。
接着创建一方法--AddEvents,用来给当前的控件挂载事件。
代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Windows.Forms; 5 using System.Drawing; 6 7 namespace DragControl 8 { 9 public class MoveControl 10 { 11 #region Constructors 12 public MoveControl(Control ctrl) 13 { 14 currentControl = ctrl; 15 AddEvents(); 16 } 17 #endregion 18 19 #region Fields 20 private Control currentControl; //传入的控件 21 #endregion 22 23 #region Properties 24 25 #endregion 26 27 #region Methods 28 /// <summary> 29 /// 挂载事件 30 /// </summary> 31 private void AddEvents() 32 { 33 currentControl.MouseClick += new MouseEventHandler(MouseClick); 34 currentControl.MouseDown += new MouseEventHandler(MouseDown); 35 currentControl.MouseMove += new MouseEventHandler(MouseMove); 36 currentControl.MouseUp += new MouseEventHandler(MouseUp); 37 } 38 #endregion 39 40 #region Events 41 /// <summary> 42 /// 鼠标单击事件:用来显示边框 43 /// </summary> 44 /// <param name="sender"></param> 45 /// <param name="e"></param> 46 void MouseClick(object sender, MouseEventArgs e) 47 { 48 } 49 50 /// <summary> 51 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 52 /// </summary> 53 void MouseDown(object sender, MouseEventArgs e) 54 { 55 56 } 57 58 /// <summary> 59 /// 鼠标移动事件:让控件跟着鼠标移动 60 /// </summary> 61 void MouseMove(object sender, MouseEventArgs e) 62 { 63 } 64 65 /// <summary> 66 /// 鼠标弹起事件:让自定义的边框出现 67 /// </summary> 68 void MouseUp(object sender, MouseEventArgs e) 69 { 70 } 71 #endregion 72 } 73 }
接着我们需要实现MouseDown、MouseMove、MouseUp三个事件。
不过在此之前,我们必须要弄清楚,移动即表示坐标的改变,所以必定要有个起始坐标和终点坐标。
所以我们在MoveControl类中加入两个字段。
private Point pPoint; //上个鼠标坐标 private Point cPoint; //当前鼠标坐标
而且在开始拖动之前,我们肯定需要先单击一次控件。在MouseDown时获取当前光标的位置,保存到pPoint中。
(此处用Cursor获得坐标的好处,就是忽略掉容器的麻烦问题)
1 /// <summary> 2 /// 鼠标单击事件:用来显示边框 3 /// </summary> 4 void MouseClick(object sender, MouseEventArgs e) 5 { 6 pPoint = Cursor.Position; 7 }
接着便实现MouseMove的事件,当鼠标左键按下时,接着移动鼠标后,继续鼠标移动后的坐标,然后与MouseDown时记下的坐标相减,就得到鼠标的位移值,接着控件的Location加上该位移值即可,然后更新pPoint。
1 /// <summary> 2 /// 鼠标移动事件:让控件跟着鼠标移动 3 /// </summary> 4 void MouseMove(object sender, MouseEventArgs e) 5 { 6 Cursor.Current = Cursors.SizeAll; //当鼠标处于控件内部时,显示光标样式为SizeAll 7 //当鼠标左键按下时才触发 8 if (e.Button == MouseButtons.Left) 9 { 10 cPoint = Cursor.Position; //获得当前鼠标位置 11 int x = cPoint.X - pPoint.X; 12 int y = cPoint.Y - pPoint.Y; 13 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 14 pPoint = cPoint; 15 } 16 }
由于此时还没涉及到边框,所以MouseUp暂时不用处理。至此拖动的基本功能已经实现!
目前MoveControl的完整代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Windows.Forms; 5 using System.Drawing; 6 7 namespace DragControl 8 { 9 public class MoveControl 10 { 11 #region Constructors 12 public MoveControl(Control ctrl) 13 { 14 currentControl = ctrl; 15 AddEvents(); 16 } 17 #endregion 18 19 #region Fields 20 private Control currentControl; //传入的控件 21 private Point pPoint; //上个鼠标坐标 22 private Point cPoint; //当前鼠标坐标 23 #endregion 24 25 #region Properties 26 27 #endregion 28 29 #region Methods 30 /// <summary> 31 /// 挂载事件 32 /// </summary> 33 private void AddEvents() 34 { 35 currentControl.MouseDown += new MouseEventHandler(MouseDown); 36 currentControl.MouseMove += new MouseEventHandler(MouseMove); 37 currentControl.MouseUp += new MouseEventHandler(MouseUp); 38 } 39 40 /// <summary> 41 /// 绘制拖拉时的黑色边框 42 /// </summary> 43 public static void DrawDragBound(Control ctrl) 44 { 45 ctrl.Refresh(); 46 Graphics g = ctrl.CreateGraphics(); 47 int width = ctrl.Width; 48 int height = ctrl.Height; 49 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 50 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 51 g.DrawLines(new Pen(Color.Black), ps); 52 } 53 #endregion 54 55 #region Events 56 /// <summary> 57 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 58 /// </summary> 59 void MouseDown(object sender, MouseEventArgs e) 60 { 61 pPoint = Cursor.Position; 62 } 63 64 /// <summary> 65 /// 鼠标移动事件:让控件跟着鼠标移动 66 /// </summary> 67 void MouseMove(object sender, MouseEventArgs e) 68 { 69 Cursor.Current = Cursors.SizeAll; //当鼠标处于控件内部时,显示光标样式为SizeAll 70 //当鼠标左键按下时才触发 71 if (e.Button == MouseButtons.Left) 72 { 73 MoveControl.DrawDragBound(this.currentControl); 74 cPoint = Cursor.Position; //获得当前鼠标位置 75 int x = cPoint.X - pPoint.X; 76 int y = cPoint.Y - pPoint.Y; 77 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 78 pPoint = cPoint; 79 } 80 } 81 82 /// <summary> 83 /// 鼠标弹起事件:让自定义的边框出现 84 /// </summary> 85 void MouseUp(object sender, MouseEventArgs e) 86 { 87 this.currentControl.Refresh(); 88 } 89 #endregion 90 } 91 }
下面我们来测试下拖动的功能。
创建一个Form窗体,可以再界面上添加你要测试的控件类型,此处我只用TextBox左下测试。在Load的中添加以下代码,将Form中的所有控件挂载上拖拉功能。
1 private void Form1_Load(object sender, EventArgs e) 2 { 3 foreach (Control ctrl in this.Controls) 4 { 5 new MoveControl(ctrl); 6 } 7 }
此时,有心人可能会发现VS中拖动控件时,将会出现黑色边框,而处于没有。
这也很简单,我们在MouseMove时加上如下代码即可。
1 /// <summary> 2 /// 绘制拖拉时的黑色边框 3 /// </summary> 4 public static void DrawDragBound(Control ctrl) 5 { 6 ctrl.Refresh(); 7 Graphics g = ctrl.CreateGraphics(); 8 int width = ctrl.Width; 9 int height = ctrl.Height; 10 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 11 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 12 g.DrawLines(new Pen(Color.Black), ps); 13 } 14 15 16 /// <summary> 17 /// 鼠标移动事件:让控件跟着鼠标移动 18 /// </summary> 19 void MouseMove(object sender, MouseEventArgs e) 20 { 21 Cursor.Current = Cursors.SizeAll; //当鼠标处于控件内部时,显示光标样式为SizeAll 22 //当鼠标左键按下时才触发 23 if (e.Button == MouseButtons.Left) 24 { 25 MoveControl.DrawDragBound(this.currentControl); 26 cPoint = Cursor.Position; //获得当前鼠标位置 27 int x = cPoint.X - pPoint.X; 28 int y = cPoint.Y - pPoint.Y; 29 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 30 pPoint = cPoint; 31 } 32 }
同时要在MoveUp的时候,刷新一下自己,让黑色边框消失掉!
1 /// <summary> 2 /// 鼠标弹起事件:让自定义的边框出现 3 /// </summary> 4 void MouseUp(object sender, MouseEventArgs e) 5 { 6 this.currentControl.Refresh(); 7 }
接着用没有边框的控件测试下就会很明显。如下图所示:
2.通过边框拖拉控件改变大小
此处的主要思路为:点击控件的时候,创建一个自定义的用户控件,该用户控件响应区域就是传入控件的边框区域,同时给它画上虚线与8个小圆圈。
第一、创建用户控件--FrameControl(边框控件),然后增加一个字段用来保存传入的控件,还有加载事件,此处类同前面的MoveControl。
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 10 namespace DragControl 11 { 12 public partial class FrameControl : UserControl 13 { 14 #region Constructors 15 public FrameControl(Control ctrl) 16 { 17 baseControl = ctrl; 18 AddEvents(); 19 } 20 #endregion 21 22 #region Fields 23 Control baseControl; //基础控件,即被包围的控件 24 #endregion 25 26 #region Methods 27 /// <summary> 28 /// 加载事件 29 /// </summary> 30 private void AddEvents() 31 { 32 this.Name = "FrameControl" + baseControl.Name; 33 this.MouseDown += new MouseEventHandler(FrameControl_MouseDown); 34 this.MouseMove += new MouseEventHandler(FrameControl_MouseMove); 35 this.MouseUp += new MouseEventHandler(FrameControl_MouseUp); 36 } 37 38 #endregion 39 40 #region Events 41 /// <summary> 42 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 43 /// </summary> 44 void FrameControl_MouseDown(object sender, MouseEventArgs e) 45 { 46 47 } 48 49 /// <summary> 50 /// 鼠标移动事件:让控件跟着鼠标移动 51 /// </summary> 52 void FrameControl_MouseMove(object sender, MouseEventArgs e) 53 { 54 55 } 56 57 /// <summary> 58 /// 鼠标弹起事件:让自定义的边框出现 59 /// </summary> 60 void FrameControl_MouseUp(object sender, MouseEventArgs e) 61 { 62 63 } 64 #endregion 65 } 66 }
做完这些准备工作后,将到了主要的部分,就是给控件画边框。
整个边框分为三个部分:四边框(用来设置可视区域与区域)+四条虚线(只用来显示)+八个小圆圈(用来斜角拖拉)。
所以要建立三个字段,用来分别保存这个数据。
Rectangle[] smallRects = new Rectangle[8];//边框中的八个小圆圈 Rectangle[] sideRects = new Rectangle[4];//四条边框,用来做响应区域 Point[] linePoints = new Point[5];//四条边,用于画虚线
接着就是创建用户控件的可视区域,和上面的三个变量数值。
(以下计算位置的代码,有兴趣的人可以研究下,没有的就直接Copy)
1 #region 创建边框 2 /// <summary> 3 /// 建立控件可视区域 4 /// </summary> 5 private void CreateBounds() 6 { 7 //创建边界 8 int X = baseControl.Bounds.X - square.Width - 1; 9 int Y = baseControl.Bounds.Y - square.Height - 1; 10 int Height = baseControl.Bounds.Height + (square.Height * 2) + 2; 11 int Width = baseControl.Bounds.Width + (square.Width * 2) + 2; 12 this.Bounds = new Rectangle(X, Y, Width, Height); 13 this.BringToFront(); 14 SetRectangles(); 15 //设置可视区域 16 this.Region = new Region(BuildFrame()); 17 g = this.CreateGraphics(); 18 } 19 20 /// <summary> 21 /// 设置定义8个小矩形的范围 22 /// </summary> 23 void SetRectangles() 24 { 25 //左上 26 smallRects[0] = new Rectangle(new Point(0, 0), square); 27 //右上 28 smallRects[1] = new Rectangle(new Point(this.Width - square.Width - 1, 0), square); 29 //左下 30 smallRects[2] = new Rectangle(new Point(0, this.Height - square.Height - 1), square); 31 //右下 32 smallRects[3] = new Rectangle(new Point(this.Width - square.Width - 1, this.Height - square.Height - 1), square); 33 //上中 34 smallRects[4] = new Rectangle(new Point(this.Width / 2 - 1, 0), square); 35 //下中 36 smallRects[5] = new Rectangle(new Point(this.Width / 2 - 1, this.Height - square.Height - 1), square); 37 //左中 38 smallRects[6] = new Rectangle(new Point(0, this.Height / 2 - 1), square); 39 //右中 40 smallRects[7] = new Rectangle(new Point(square.Width + baseControl.Width + 1, this.Height / 2 - 1), square); 41 42 //四条边线 43 //左上 44 linePoints[0] = new Point(square.Width / 2, square.Height / 2); 45 //右上 46 linePoints[1] = new Point(this.Width - square.Width / 2 - 1, square.Height / 2); 47 //右下 48 linePoints[2] = new Point(this.Width - square.Width / 2 - 1, this.Height - square.Height / 2); 49 //左下 50 linePoints[3] = new Point(square.Width / 2, this.Height - square.Height / 2 - 1); 51 //左上 52 linePoints[4] = new Point(square.Width / 2, square.Height / 2); 53 54 //整个包括周围边框的范围 55 ControlRect = new Rectangle(new Point(0, 0), this.Bounds.Size); 56 } 57 58 /// <summary> 59 /// 设置边框控件可视区域 60 /// </summary> 61 /// <returns></returns> 62 private GraphicsPath BuildFrame() 63 { 64 GraphicsPath path = new GraphicsPath(); 65 //上边框 66 sideRects[0] = new Rectangle(0, 0, this.Width - square.Width - 1, square.Height + 1); 67 //左边框 68 sideRects[1] = new Rectangle(0, square.Height + 1, square.Width + 1, this.Height - square.Height - 1); 69 //下边框 70 sideRects[2] = new Rectangle(square.Width + 1, this.Height - square.Height - 1, this.Width - square.Width - 1, square.Height + 1); 71 //右边框 72 sideRects[3] = new Rectangle(this.Width - square.Width - 1, 0, square.Width + 1, this.Height - square.Height - 1); 73 74 path.AddRectangle(sideRects[0]); 75 path.AddRectangle(sideRects[1]); 76 path.AddRectangle(sideRects[2]); 77 path.AddRectangle(sideRects[3]); 78 return path; 79 } 80 #endregion
设置完位置后,接着就是绘制的工作。增加一个Draw的方法用来画,同时设置为Public。此处不用控件的Paint,而是让用户调用,只因为这样方便在不同控件之间切换,也就是一个容器中,只有当前控件有边框。
1 /// <summary> 2 /// 绘图 3 /// </summary> 4 public void Draw() 5 { 6 this.BringToFront(); 7 Pen pen = new Pen(Color.Black); 8 pen.DashStyle = DashStyle.Dot;//设置为虚线,用虚线画四边,模拟微软效果 9 g.DrawLines(pen, linePoints);//绘制四条边线 10 g.FillRectangles(Brushes.White, smallRects); //填充8个小矩形的内部 11 foreach (Rectangle smallRect in smallRects) 12 { 13 g.DrawEllipse(Pens.Black, smallRect); //绘制8个小椭圆 14 } 15 //g.DrawRectangles(Pens.Black, smallRects); //绘制8个小矩形的黑色边线 16 }
做到这里,我们可以去前台看一下效果,不过再此之前,我们需要调用该用户控件。
调用的地方就是在控件上点击的时候,所以在MoveControl中加入MouseClick的事件。
1 /// <summary> 2 /// 鼠标单击事件:用来显示边框 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 protected void MouseClick(object sender, MouseEventArgs e) 7 { 8 this.currentControl.Parent.Refresh();//刷新父容器,清除掉其他控件的边框 9 this.currentControl.BringToFront(); 10 fc = new FrameControl(this.currentControl); 11 this.currentControl.Parent.Controls.Add(fc); 12 fc.Visible = true; 13 fc.Draw(); 14 }
这时有了边框之后会有一个小问题,就是拖动控件的时候,控件移动了,但是边框还留在原地。
所以,这里需要注意的,就是移动的时候,将边框控件隐藏掉,当MouseUp的时候再显示。
此时的完整代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.Windows.Forms; 5 using System.Drawing; 6 7 namespace DragControl 8 { 9 public class MoveControl 10 { 11 #region Constructors 12 public MoveControl(Control ctrl) 13 { 14 currentControl = ctrl; 15 AddEvents(); 16 } 17 #endregion 18 19 #region Fields 20 private Control currentControl; //传入的控件 21 private Point pPoint; //上个鼠标坐标 22 private Point cPoint; //当前鼠标坐标 23 FrameControl fc;//边框控件 24 #endregion 25 26 #region Properties 27 28 #endregion 29 30 #region Methods 31 /// <summary> 32 /// 挂载事件 33 /// </summary> 34 private void AddEvents() 35 { 36 currentControl.MouseClick += new MouseEventHandler(MouseClick); 37 currentControl.MouseDown += new MouseEventHandler(MouseDown); 38 currentControl.MouseMove += new MouseEventHandler(MouseMove); 39 currentControl.MouseUp += new MouseEventHandler(MouseUp); 40 } 41 42 /// <summary> 43 /// 绘制拖拉时的黑色边框 44 /// </summary> 45 public static void DrawDragBound(Control ctrl) 46 { 47 ctrl.Refresh(); 48 Graphics g = ctrl.CreateGraphics(); 49 int width = ctrl.Width; 50 int height = ctrl.Height; 51 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 52 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 53 g.DrawLines(new Pen(Color.Black), ps); 54 } 55 #endregion 56 57 #region Events 58 /// <summary> 59 /// 鼠标单击事件:用来显示边框 60 /// </summary> 61 /// <param name="sender"></param> 62 /// <param name="e"></param> 63 protected void MouseClick(object sender, MouseEventArgs e) 64 { 65 this.currentControl.Parent.Refresh();//刷新父容器,清除掉其他控件的边框 66 this.currentControl.BringToFront(); 67 fc = new FrameControl(this.currentControl); 68 this.currentControl.Parent.Controls.Add(fc); 69 fc.Visible = true; 70 fc.Draw(); 71 } 72 73 /// <summary> 74 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 75 /// </summary> 76 void MouseDown(object sender, MouseEventArgs e) 77 { 78 pPoint = Cursor.Position; 79 } 80 81 /// <summary> 82 /// 鼠标移动事件:让控件跟着鼠标移动 83 /// </summary> 84 void MouseMove(object sender, MouseEventArgs e) 85 { 86 Cursor.Current = Cursors.SizeAll; //当鼠标处于控件内部时,显示光标样式为SizeAll 87 //当鼠标左键按下时才触发 88 if (e.Button == MouseButtons.Left) 89 { 90 MoveControl.DrawDragBound(this.currentControl); 91 if (fc != null) fc.Visible = false; //先隐藏 92 cPoint = Cursor.Position; //获得当前鼠标位置 93 int x = cPoint.X - pPoint.X; 94 int y = cPoint.Y - pPoint.Y; 95 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 96 pPoint = cPoint; 97 } 98 } 99 100 /// <summary> 101 /// 鼠标弹起事件:让自定义的边框出现 102 /// </summary> 103 void MouseUp(object sender, MouseEventArgs e) 104 { 105 this.currentControl.Refresh(); 106 if (fc != null) 107 { 108 fc.Visible = true; 109 fc.Draw(); 110 } 111 } 112 #endregion 113 } 114 }
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Text; 7 using System.Windows.Forms; 8 using System.Drawing.Drawing2D; 9 10 namespace DragControl 11 { 12 public partial class FrameControl : UserControl 13 { 14 #region Constructors 15 public FrameControl(Control ctrl) 16 { 17 baseControl = ctrl; 18 AddEvents(); 19 CreateBounds(); 20 } 21 #endregion 22 23 #region Fields 24 const int Band = 6; //调整大小的响应边框 25 Size square = new Size(Band, Band);//小矩形大小 26 Control baseControl; //基础控件,即被包围的控件 27 Rectangle[] smallRects = new Rectangle[8];//边框中的八个小圆圈 28 Rectangle[] sideRects = new Rectangle[4];//四条边框,用来做响应区域 29 Point[] linePoints = new Point[5];//四条边,用于画虚线 30 Graphics g; //画图板 31 Rectangle ControlRect; //控件包含边框的区域 32 #endregion 33 34 #region Methods 35 /// <summary> 36 /// 加载事件 37 /// </summary> 38 private void AddEvents() 39 { 40 this.Name = "FrameControl" + baseControl.Name; 41 this.MouseDown += new MouseEventHandler(FrameControl_MouseDown); 42 this.MouseMove += new MouseEventHandler(FrameControl_MouseMove); 43 this.MouseUp += new MouseEventHandler(FrameControl_MouseUp); 44 } 45 46 #region 创建边框 47 /// <summary> 48 /// 建立控件可视区域 49 /// </summary> 50 private void CreateBounds() 51 { 52 //创建边界 53 int X = baseControl.Bounds.X - square.Width - 1; 54 int Y = baseControl.Bounds.Y - square.Height - 1; 55 int Height = baseControl.Bounds.Height + (square.Height * 2) + 2; 56 int Width = baseControl.Bounds.Width + (square.Width * 2) + 2; 57 this.Bounds = new Rectangle(X, Y, Width, Height); 58 this.BringToFront(); 59 SetRectangles(); 60 //设置可视区域 61 this.Region = new Region(BuildFrame()); 62 g = this.CreateGraphics(); 63 } 64 65 /// <summary> 66 /// 设置定义8个小矩形的范围 67 /// </summary> 68 void SetRectangles() 69 { 70 //左上 71 smallRects[0] = new Rectangle(new Point(0, 0), square); 72 //右上 73 smallRects[1] = new Rectangle(new Point(this.Width - square.Width - 1, 0), square); 74 //左下 75 smallRects[2] = new Rectangle(new Point(0, this.Height - square.Height - 1), square); 76 //右下 77 smallRects[3] = new Rectangle(new Point(this.Width - square.Width - 1, this.Height - square.Height - 1), square); 78 //上中 79 smallRects[4] = new Rectangle(new Point(this.Width / 2 - 1, 0), square); 80 //下中 81 smallRects[5] = new Rectangle(new Point(this.Width / 2 - 1, this.Height - square.Height - 1), square); 82 //左中 83 smallRects[6] = new Rectangle(new Point(0, this.Height / 2 - 1), square); 84 //右中 85 smallRects[7] = new Rectangle(new Point(square.Width + baseControl.Width + 1, this.Height / 2 - 1), square); 86 87 //四条边线 88 //左上 89 linePoints[0] = new Point(square.Width / 2, square.Height / 2); 90 //右上 91 linePoints[1] = new Point(this.Width - square.Width / 2 - 1, square.Height / 2); 92 //右下 93 linePoints[2] = new Point(this.Width - square.Width / 2 - 1, this.Height - square.Height / 2); 94 //左下 95 linePoints[3] = new Point(square.Width / 2, this.Height - square.Height / 2 - 1); 96 //左上 97 linePoints[4] = new Point(square.Width / 2, square.Height / 2); 98 99 //整个包括周围边框的范围 100 ControlRect = new Rectangle(new Point(0, 0), this.Bounds.Size); 101 } 102 103 /// <summary> 104 /// 设置边框控件可视区域 105 /// </summary> 106 /// <returns></returns> 107 private GraphicsPath BuildFrame() 108 { 109 GraphicsPath path = new GraphicsPath(); 110 //上边框 111 sideRects[0] = new Rectangle(0, 0, this.Width - square.Width - 1, square.Height + 1); 112 //左边框 113 sideRects[1] = new Rectangle(0, square.Height + 1, square.Width + 1, this.Height - square.Height - 1); 114 //下边框 115 sideRects[2] = new Rectangle(square.Width + 1, this.Height - square.Height - 1, this.Width - square.Width - 1, square.Height + 1); 116 //右边框 117 sideRects[3] = new Rectangle(this.Width - square.Width - 1, 0, square.Width + 1, this.Height - square.Height - 1); 118 119 path.AddRectangle(sideRects[0]); 120 path.AddRectangle(sideRects[1]); 121 path.AddRectangle(sideRects[2]); 122 path.AddRectangle(sideRects[3]); 123 return path; 124 } 125 #endregion 126 127 /// <summary> 128 /// 绘图 129 /// </summary> 130 public void Draw() 131 { 132 this.BringToFront(); 133 Pen pen = new Pen(Color.Black); 134 pen.DashStyle = DashStyle.Dot;//设置为虚线,用虚线画四边,模拟微软效果 135 g.DrawLines(pen, linePoints);//绘制四条边线 136 g.FillRectangles(Brushes.White, smallRects); //填充8个小矩形的内部 137 foreach (Rectangle smallRect in smallRects) 138 { 139 g.DrawEllipse(Pens.Black, smallRect); //绘制8个小椭圆 140 } 141 //g.DrawRectangles(Pens.Black, smallRects); //绘制8个小矩形的黑色边线 142 } 143 144 #endregion 145 146 #region Events 147 /// <summary> 148 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 149 /// </summary> 150 void FrameControl_MouseDown(object sender, MouseEventArgs e) 151 { 152 153 } 154 155 /// <summary> 156 /// 鼠标移动事件:让控件跟着鼠标移动 157 /// </summary> 158 void FrameControl_MouseMove(object sender, MouseEventArgs e) 159 { 160 161 } 162 163 /// <summary> 164 /// 鼠标弹起事件:让自定义的边框出现 165 /// </summary> 166 void FrameControl_MouseUp(object sender, MouseEventArgs e) 167 { 168 169 } 170 #endregion 171 } 172 }
测试界面:
到目前为止,还只是有边框,下面将实现拖拉功能。
首先来实现,当鼠标放在响应区域的时候,根据不同的位置显示不同的箭头样子。
为此先创建一个枚举,用来记录当前鼠标的位置,等拖拉的时候根据该枚举值做不同的计算。
1 /// <summary> 2 /// 鼠标在控件中位置 3 /// </summary> 4 enum MousePosOnCtrl 5 { 6 NONE = 0, 7 TOP = 1, 8 RIGHT = 2, 9 BOTTOM = 3, 10 LEFT = 4, 11 TOPLEFT = 5, 12 TOPRIGHT = 6, 13 BOTTOMLEFT = 7, 14 BOTTOMRIGHT = 8, 15 }
创建一个方法,用来改变光标的样子以及枚举值
1 /// <summary> 2 /// 设置光标状态 3 /// </summary> 4 public bool SetCursorShape(int x, int y) 5 { 6 Point point = new Point(x, y); 7 if (!ControlRect.Contains(point)) 8 { 9 Cursor.Current = Cursors.Arrow; 10 return false; 11 } 12 else if (smallRects[0].Contains(point)) 13 { 14 Cursor.Current = Cursors.SizeNWSE; 15 mpoc = MousePosOnCtrl.TOPLEFT; 16 } 17 else if (smallRects[1].Contains(point)) 18 { 19 Cursor.Current = Cursors.SizeNESW; 20 mpoc = MousePosOnCtrl.TOPRIGHT; 21 } 22 else if (smallRects[2].Contains(point)) 23 { 24 Cursor.Current = Cursors.SizeNESW; 25 mpoc = MousePosOnCtrl.BOTTOMLEFT; 26 } 27 else if (smallRects[3].Contains(point)) 28 { 29 Cursor.Current = Cursors.SizeNWSE; 30 mpoc = MousePosOnCtrl.BOTTOMRIGHT; 31 } 32 else if (sideRects[0].Contains(point)) 33 { 34 Cursor.Current = Cursors.SizeNS; 35 mpoc = MousePosOnCtrl.TOP; 36 } 37 else if (sideRects[1].Contains(point)) 38 { 39 Cursor.Current = Cursors.SizeWE; 40 mpoc = MousePosOnCtrl.LEFT; 41 } 42 else if (sideRects[2].Contains(point)) 43 { 44 Cursor.Current = Cursors.SizeNS; 45 mpoc = MousePosOnCtrl.BOTTOM; 46 } 47 else if (sideRects[3].Contains(point)) 48 { 49 Cursor.Current = Cursors.SizeWE; 50 mpoc = MousePosOnCtrl.RIGHT; 51 } 52 else 53 { 54 Cursor.Current = Cursors.Arrow; 55 } 56 return true; 57 }
接着就是处理相关的三大事件MouseDown、MouseMove、MouseUp来实现拖拉。如同MoveControl都要增加以下两个字段。
private Point pPoint; //上个鼠标坐标 private Point cPoint; //当前鼠标坐标
1 /// <summary> 2 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 3 /// </summary> 4 void FrameControl_MouseDown(object sender, MouseEventArgs e) 5 { 6 pPoint = Cursor.Position; 7 } 8 9 /// <summary> 10 /// 鼠标移动事件:让控件跟着鼠标移动 11 /// </summary> 12 void FrameControl_MouseMove(object sender, MouseEventArgs e) 13 { 14 if (e.Button == MouseButtons.Left) 15 { 16 this.Visible = false; 17 MoveControl.DrawDragBound(baseControl); 18 ControlMove(); 19 } 20 else 21 { 22 this.Visible = true; 23 SetCursorShape(e.X, e.Y); //更新鼠标指针样式 24 } 25 } 26 27 /// <summary> 28 /// 鼠标弹起事件:让自定义的边框出现 29 /// </summary> 30 void FrameControl_MouseUp(object sender, MouseEventArgs e) 31 { 32 this.baseControl.Refresh(); //刷掉黑色边框 33 this.Visible = true; 34 CreateBounds(); 35 Draw(); 36 }
在上面的MouseMove中多了一个方法--ControlMove,这个就是根据不同的枚举值,计算控件的移动方式和大小的方法。该方法中同时对控件的最小宽度和高度做了处理。添加如下两个字段。
private int MinWidth = 20; //最小宽度 private int MinHeight = 20;//最小高度
1 /// <summary> 2 /// 控件移动 3 /// </summary> 4 private void ControlMove() 5 { 6 cPoint = Cursor.Position; 7 int x = cPoint.X - pPoint.X; 8 int y = cPoint.Y - pPoint.Y; 9 switch (this.mpoc) 10 { 11 case MousePosOnCtrl.TOP: 12 if (baseControl.Height - y > MinHeight) 13 { 14 baseControl.Top += y; 15 baseControl.Height -= y; 16 } 17 else 18 { 19 baseControl.Top -= MinHeight - baseControl.Height; 20 baseControl.Height = MinHeight; 21 } 22 break; 23 case MousePosOnCtrl.BOTTOM: 24 if (baseControl.Height + y > MinHeight) 25 { 26 baseControl.Height += y; 27 } 28 else 29 { 30 baseControl.Height = MinHeight; 31 } 32 break; 33 case MousePosOnCtrl.LEFT: 34 if (baseControl.Width - x > MinWidth) 35 { 36 baseControl.Left += x; 37 baseControl.Width -= x; 38 } 39 else 40 { 41 baseControl.Left -= MinWidth - baseControl.Width; 42 baseControl.Width = MinWidth; 43 } 44 45 break; 46 case MousePosOnCtrl.RIGHT: 47 if (baseControl.Width + x > MinWidth) 48 { 49 baseControl.Width += x; 50 } 51 else 52 { 53 baseControl.Width = MinWidth; 54 } 55 break; 56 case MousePosOnCtrl.TOPLEFT: 57 if (baseControl.Height - y > MinHeight) 58 { 59 baseControl.Top += y; 60 baseControl.Height -= y; 61 } 62 else 63 { 64 baseControl.Top -= MinHeight - baseControl.Height; 65 baseControl.Height = MinHeight; 66 } 67 if (baseControl.Width - x > MinWidth) 68 { 69 baseControl.Left += x; 70 baseControl.Width -= x; 71 } 72 else 73 { 74 baseControl.Left -= MinWidth - baseControl.Width; 75 baseControl.Width = MinWidth; 76 } 77 break; 78 case MousePosOnCtrl.TOPRIGHT: 79 if (baseControl.Height - y > MinHeight) 80 { 81 baseControl.Top += y; 82 baseControl.Height -= y; 83 } 84 else 85 { 86 baseControl.Top -= MinHeight - baseControl.Height; 87 baseControl.Height = MinHeight; 88 } 89 if (baseControl.Width + x > MinWidth) 90 { 91 baseControl.Width += x; 92 } 93 else 94 { 95 baseControl.Width = MinWidth; 96 } 97 break; 98 case MousePosOnCtrl.BOTTOMLEFT: 99 if (baseControl.Height + y > MinHeight) 100 { 101 baseControl.Height += y; 102 } 103 else 104 { 105 baseControl.Height = MinHeight; 106 } 107 if (baseControl.Width - x > MinWidth) 108 { 109 baseControl.Left += x; 110 baseControl.Width -= x; 111 } 112 else 113 { 114 baseControl.Left -= MinWidth - baseControl.Width; 115 baseControl.Width = MinWidth; 116 } 117 break; 118 case MousePosOnCtrl.BOTTOMRIGHT: 119 if (baseControl.Height + y > MinHeight) 120 { 121 baseControl.Height += y; 122 } 123 else 124 { 125 baseControl.Height = MinHeight; 126 } 127 if (baseControl.Width + x > MinWidth) 128 { 129 baseControl.Width += x; 130 } 131 else 132 { 133 baseControl.Width = MinWidth; 134 } 135 break; 136 137 } 138 pPoint = Cursor.Position; 139 }
到此为止,功能已经基本上实现。
完成代码如下:
1 /****************************************************************** 2 * 创 建 人: SamWang 3 * 创建时间: 2012-5-10 16:06 4 * 描 述: 5 * 移动控件但不改变大小 6 * 原 理: 7 * 版 本: V1.0 8 * 环 境: VS2010 9 ******************************************************************/ 10 using System; 11 using System.Collections.Generic; 12 using System.Linq; 13 using System.Text; 14 using System.Windows.Forms; 15 using System.Drawing; 16 17 namespace DragControl 18 { 19 public class MoveControl 20 { 21 #region Constructors 22 public MoveControl(Control ctrl) 23 { 24 currentControl = ctrl; 25 AddEvents(); 26 } 27 #endregion 28 29 #region Fields 30 private Control currentControl; //传入的控件 31 private Point pPoint; //上个鼠标坐标 32 private Point cPoint; //当前鼠标坐标 33 FrameControl fc;//边框控件 34 #endregion 35 36 #region Properties 37 38 #endregion 39 40 #region Methods 41 /// <summary> 42 /// 挂载事件 43 /// </summary> 44 private void AddEvents() 45 { 46 currentControl.MouseClick += new MouseEventHandler(MouseClick); 47 currentControl.MouseDown += new MouseEventHandler(MouseDown); 48 currentControl.MouseMove += new MouseEventHandler(MouseMove); 49 currentControl.MouseUp += new MouseEventHandler(MouseUp); 50 } 51 52 /// <summary> 53 /// 绘制拖拉时的黑色边框 54 /// </summary> 55 public static void DrawDragBound(Control ctrl) 56 { 57 ctrl.Refresh(); 58 Graphics g = ctrl.CreateGraphics(); 59 int width = ctrl.Width; 60 int height = ctrl.Height; 61 Point[] ps = new Point[5]{new Point(0,0),new Point(width -1,0), 62 new Point(width -1,height -1),new Point(0,height-1),new Point(0,0)}; 63 g.DrawLines(new Pen(Color.Black), ps); 64 } 65 66 #endregion 67 68 #region Events 69 /// <summary> 70 /// 鼠标单击事件:用来显示边框 71 /// </summary> 72 /// <param name="sender"></param> 73 /// <param name="e"></param> 74 protected void MouseClick(object sender, MouseEventArgs e) 75 { 76 this.currentControl.Parent.Refresh();//刷新父容器,清除掉其他控件的边框 77 this.currentControl.BringToFront(); 78 fc = new FrameControl(this.currentControl); 79 this.currentControl.Parent.Controls.Add(fc); 80 fc.Visible = true; 81 fc.Draw(); 82 } 83 84 /// <summary> 85 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 86 /// </summary> 87 void MouseDown(object sender, MouseEventArgs e) 88 { 89 pPoint = Cursor.Position; 90 } 91 92 /// <summary> 93 /// 鼠标移动事件:让控件跟着鼠标移动 94 /// </summary> 95 void MouseMove(object sender, MouseEventArgs e) 96 { 97 Cursor.Current = Cursors.SizeAll; //当鼠标处于控件内部时,显示光标样式为SizeAll 98 //当鼠标左键按下时才触发 99 if (e.Button == MouseButtons.Left) 100 { 101 MoveControl.DrawDragBound(this.currentControl); 102 if(fc != null ) fc.Visible = false; //先隐藏 103 cPoint = Cursor.Position;//获得当前鼠标位置 104 int x = cPoint.X - pPoint.X; 105 int y = cPoint.Y - pPoint.Y; 106 currentControl.Location = new Point(currentControl.Location.X + x, currentControl.Location.Y + y); 107 pPoint = cPoint; 108 } 109 } 110 111 /// <summary> 112 /// 鼠标弹起事件:让自定义的边框出现 113 /// </summary> 114 void MouseUp(object sender, MouseEventArgs e) 115 { 116 this.currentControl.Refresh(); 117 if (fc != null) 118 { 119 fc.Visible = true; 120 fc.Draw(); 121 } 122 } 123 #endregion 124 } 125 }
1 /****************************************************************** 2 * 创 建 人: SamWang 3 * 创建时间: 2012-5-10 17:00 4 * 描 述: 5 * 在控件外部加上边框,用于拖拉,以改变内部控件的大小 6 * 原 理: 7 * 版 本: V1.0 8 * 环 境: VS2010 9 ******************************************************************/ 10 using System; 11 using System.Collections.Generic; 12 using System.Text; 13 using System.Windows.Forms; 14 using System.Drawing; 15 using System.Drawing.Drawing2D; 16 17 namespace DragControl 18 { 19 public class FrameControl : UserControl 20 { 21 #region Constructors 22 /// <summary> 23 /// 构造函数 24 /// </summary> 25 public FrameControl(Control ctrl) 26 { 27 baseControl = ctrl; 28 AddEvents(); 29 CreateBounds(); 30 } 31 #endregion 32 33 #region Fields 34 const int Band = 6; //调整大小的响应边框 35 private int MinWidth = 20; //最小宽度 36 private int MinHeight = 20;//最小高度 37 Size square = new Size(Band, Band);//小矩形大小 38 Control baseControl; //基础控件,即被包围的控件 39 Rectangle[] smallRects = new Rectangle[8];//边框中的八个小圆圈 40 Rectangle[] sideRects = new Rectangle[4];//四条边框,用来做响应区域 41 Point[] linePoints = new Point[5];//四条边,用于画虚线 42 Graphics g; //画图板 43 Rectangle ControlRect; //控件包含边框的区域 44 private Point pPoint; //上个鼠标坐标 45 private Point cPoint; //当前鼠标坐标 46 private MousePosOnCtrl mpoc; 47 #endregion 48 49 #region Properties 50 /// <summary> 51 /// 鼠标在控件中位置 52 /// </summary> 53 enum MousePosOnCtrl 54 { 55 NONE = 0, 56 TOP = 1, 57 RIGHT = 2, 58 BOTTOM = 3, 59 LEFT = 4, 60 TOPLEFT = 5, 61 TOPRIGHT = 6, 62 BOTTOMLEFT = 7, 63 BOTTOMRIGHT = 8, 64 } 65 #endregion 66 67 #region Methods 68 /// <summary> 69 /// 加载事件 70 /// </summary> 71 private void AddEvents() 72 { 73 this.Name = "FrameControl" + baseControl.Name; 74 this.MouseDown += new MouseEventHandler(FrameControl_MouseDown); 75 this.MouseMove += new MouseEventHandler(FrameControl_MouseMove); 76 this.MouseUp += new MouseEventHandler(FrameControl_MouseUp); 77 } 78 79 #region 创建边框 80 /// <summary> 81 /// 建立控件可视区域 82 /// </summary> 83 private void CreateBounds() 84 { 85 //创建边界 86 int X = baseControl.Bounds.X - square.Width - 1; 87 int Y = baseControl.Bounds.Y - square.Height - 1; 88 int Height = baseControl.Bounds.Height + (square.Height * 2) + 2; 89 int Width = baseControl.Bounds.Width + (square.Width * 2) + 2; 90 this.Bounds = new Rectangle(X, Y, Width, Height); 91 this.BringToFront(); 92 SetRectangles(); 93 //设置可视区域 94 this.Region = new Region(BuildFrame()); 95 g = this.CreateGraphics(); 96 } 97 98 /// <summary> 99 /// 设置定义8个小矩形的范围 100 /// </summary> 101 void SetRectangles() 102 { 103 //左上 104 smallRects[0] = new Rectangle(new Point(0, 0), square); 105 //右上 106 smallRects[1] = new Rectangle(new Point(this.Width - square.Width - 1, 0), square); 107 //左下 108 smallRects[2] = new Rectangle(new Point(0, this.Height - square.Height - 1), square); 109 //右下 110 smallRects[3] = new Rectangle(new Point(this.Width - square.Width - 1, this.Height - square.Height - 1), square); 111 //上中 112 smallRects[4] = new Rectangle(new Point(this.Width / 2 - 1, 0), square); 113 //下中 114 smallRects[5] = new Rectangle(new Point(this.Width / 2 - 1, this.Height - square.Height - 1), square); 115 //左中 116 smallRects[6] = new Rectangle(new Point(0, this.Height / 2 - 1), square); 117 //右中 118 smallRects[7] = new Rectangle(new Point(square.Width + baseControl.Width + 1, this.Height / 2 - 1), square); 119 120 //四条边线 121 //左上 122 linePoints[0] = new Point(square.Width / 2, square.Height / 2); 123 //右上 124 linePoints[1] = new Point(this.Width - square.Width / 2 - 1, square.Height / 2); 125 //右下 126 linePoints[2] = new Point(this.Width - square.Width / 2 - 1, this.Height - square.Height / 2); 127 //左下 128 linePoints[3] = new Point(square.Width / 2, this.Height - square.Height / 2 - 1); 129 //左上 130 linePoints[4] = new Point(square.Width / 2, square.Height / 2); 131 132 //整个包括周围边框的范围 133 ControlRect = new Rectangle(new Point(0, 0), this.Bounds.Size); 134 } 135 136 /// <summary> 137 /// 设置边框控件可视区域 138 /// </summary> 139 /// <returns></returns> 140 private GraphicsPath BuildFrame() 141 { 142 GraphicsPath path = new GraphicsPath(); 143 //上边框 144 sideRects[0] = new Rectangle(0, 0, this.Width - square.Width - 1, square.Height + 1); 145 //左边框 146 sideRects[1] = new Rectangle(0, square.Height + 1, square.Width + 1, this.Height - square.Height - 1); 147 //下边框 148 sideRects[2] = new Rectangle(square.Width + 1, this.Height - square.Height - 1, this.Width - square.Width - 1, square.Height + 1); 149 //右边框 150 sideRects[3] = new Rectangle(this.Width - square.Width - 1, 0, square.Width + 1, this.Height - square.Height - 1); 151 152 path.AddRectangle(sideRects[0]); 153 path.AddRectangle(sideRects[1]); 154 path.AddRectangle(sideRects[2]); 155 path.AddRectangle(sideRects[3]); 156 return path; 157 } 158 #endregion 159 160 /// <summary> 161 /// 绘图 162 /// </summary> 163 public void Draw() 164 { 165 this.BringToFront(); 166 //g.FillRectangles(Brushes.LightGray, sideRects); //填充四条边框的内部 167 Pen pen = new Pen(Color.Black); 168 pen.DashStyle = DashStyle.Dot;//设置为虚线,用虚线画四边,模拟微软效果 169 g.DrawLines(pen, linePoints);//绘制四条边线 170 g.FillRectangles(Brushes.White, smallRects); //填充8个小矩形的内部 171 foreach (Rectangle smallRect in smallRects) 172 { 173 g.DrawEllipse(Pens.Black, smallRect); //绘制8个小椭圆 174 } 175 //g.DrawRectangles(Pens.Black, smallRects); //绘制8个小矩形的黑色边线 176 } 177 178 /// <summary> 179 /// 设置光标状态 180 /// </summary> 181 public bool SetCursorShape(int x, int y) 182 { 183 Point point = new Point(x, y); 184 if (!ControlRect.Contains(point)) 185 { 186 Cursor.Current = Cursors.Arrow; 187 return false; 188 } 189 else if (smallRects[0].Contains(point)) 190 { 191 Cursor.Current = Cursors.SizeNWSE; 192 mpoc = MousePosOnCtrl.TOPLEFT; 193 } 194 else if (smallRects[1].Contains(point)) 195 { 196 Cursor.Current = Cursors.SizeNESW; 197 mpoc = MousePosOnCtrl.TOPRIGHT; 198 } 199 else if (smallRects[2].Contains(point)) 200 { 201 Cursor.Current = Cursors.SizeNESW; 202 mpoc = MousePosOnCtrl.BOTTOMLEFT; 203 } 204 else if (smallRects[3].Contains(point)) 205 { 206 Cursor.Current = Cursors.SizeNWSE; 207 mpoc = MousePosOnCtrl.BOTTOMRIGHT; 208 } 209 else if (sideRects[0].Contains(point)) 210 { 211 Cursor.Current = Cursors.SizeNS; 212 mpoc = MousePosOnCtrl.TOP; 213 } 214 else if (sideRects[1].Contains(point)) 215 { 216 Cursor.Current = Cursors.SizeWE; 217 mpoc = MousePosOnCtrl.LEFT; 218 } 219 else if (sideRects[2].Contains(point)) 220 { 221 Cursor.Current = Cursors.SizeNS; 222 mpoc = MousePosOnCtrl.BOTTOM; 223 } 224 else if (sideRects[3].Contains(point)) 225 { 226 Cursor.Current = Cursors.SizeWE; 227 mpoc = MousePosOnCtrl.RIGHT; 228 } 229 else 230 { 231 Cursor.Current = Cursors.Arrow; 232 } 233 return true; 234 } 235 236 /// <summary> 237 /// 控件移动 238 /// </summary> 239 private void ControlMove() 240 { 241 cPoint = Cursor.Position; 242 int x = cPoint.X - pPoint.X; 243 int y = cPoint.Y - pPoint.Y; 244 switch (this.mpoc) 245 { 246 case MousePosOnCtrl.TOP: 247 if (baseControl.Height - y > MinHeight) 248 { 249 baseControl.Top += y; 250 baseControl.Height -= y; 251 } 252 else 253 { 254 baseControl.Top -= MinHeight - baseControl.Height; 255 baseControl.Height = MinHeight; 256 } 257 break; 258 case MousePosOnCtrl.BOTTOM: 259 if (baseControl.Height + y > MinHeight) 260 { 261 baseControl.Height += y; 262 } 263 else 264 { 265 baseControl.Height = MinHeight; 266 } 267 break; 268 case MousePosOnCtrl.LEFT: 269 if (baseControl.Width - x > MinWidth) 270 { 271 baseControl.Left += x; 272 baseControl.Width -= x; 273 } 274 else 275 { 276 baseControl.Left -= MinWidth - baseControl.Width; 277 baseControl.Width = MinWidth; 278 } 279 280 break; 281 case MousePosOnCtrl.RIGHT: 282 if (baseControl.Width + x > MinWidth) 283 { 284 baseControl.Width += x; 285 } 286 else 287 { 288 baseControl.Width = MinWidth; 289 } 290 break; 291 case MousePosOnCtrl.TOPLEFT: 292 if (baseControl.Height - y > MinHeight) 293 { 294 baseControl.Top += y; 295 baseControl.Height -= y; 296 } 297 else 298 { 299 baseControl.Top -= MinHeight - baseControl.Height; 300 baseControl.Height = MinHeight; 301 } 302 if (baseControl.Width - x > MinWidth) 303 { 304 baseControl.Left += x; 305 baseControl.Width -= x; 306 } 307 else 308 { 309 baseControl.Left -= MinWidth - baseControl.Width; 310 baseControl.Width = MinWidth; 311 } 312 break; 313 case MousePosOnCtrl.TOPRIGHT: 314 if (baseControl.Height - y > MinHeight) 315 { 316 baseControl.Top += y; 317 baseControl.Height -= y; 318 } 319 else 320 { 321 baseControl.Top -= MinHeight - baseControl.Height; 322 baseControl.Height = MinHeight; 323 } 324 if (baseControl.Width + x > MinWidth) 325 { 326 baseControl.Width += x; 327 } 328 else 329 { 330 baseControl.Width = MinWidth; 331 } 332 break; 333 case MousePosOnCtrl.BOTTOMLEFT: 334 if (baseControl.Height + y > MinHeight) 335 { 336 baseControl.Height += y; 337 } 338 else 339 { 340 baseControl.Height = MinHeight; 341 } 342 if (baseControl.Width - x > MinWidth) 343 { 344 baseControl.Left += x; 345 baseControl.Width -= x; 346 } 347 else 348 { 349 baseControl.Left -= MinWidth - baseControl.Width; 350 baseControl.Width = MinWidth; 351 } 352 break; 353 case MousePosOnCtrl.BOTTOMRIGHT: 354 if (baseControl.Height + y > MinHeight) 355 { 356 baseControl.Height += y; 357 } 358 else 359 { 360 baseControl.Height = MinHeight; 361 } 362 if (baseControl.Width + x > MinWidth) 363 { 364 baseControl.Width += x; 365 } 366 else 367 { 368 baseControl.Width = MinWidth; 369 } 370 break; 371 372 } 373 pPoint = Cursor.Position; 374 } 375 376 #endregion 377 378 #region Events 379 /// <summary> 380 /// 鼠标按下事件:记录当前鼠标相对窗体的坐标 381 /// </summary> 382 void FrameControl_MouseDown(object sender, MouseEventArgs e) 383 { 384 pPoint = Cursor.Position; 385 } 386 387 /// <summary> 388 /// 鼠标移动事件:让控件跟着鼠标移动 389 /// </summary> 390 void FrameControl_MouseMove(object sender, MouseEventArgs e) 391 { 392 if (e.Button == MouseButtons.Left) 393 { 394 this.Visible = false; 395 MoveControl.DrawDragBound(baseControl); 396 ControlMove(); 397 } 398 else 399 { 400 this.Visible = true; 401 SetCursorShape(e.X, e.Y); //更新鼠标指针样式 402 } 403 } 404 405 /// <summary> 406 /// 鼠标弹起事件:让自定义的边框出现 407 /// </summary> 408 void FrameControl_MouseUp(object sender, MouseEventArgs e) 409 { 410 this.baseControl.Refresh(); //刷掉黑色边框 411 this.Visible = true; 412 CreateBounds(); 413 Draw(); 414 } 415 #endregion 416 } 417 }
四、遗留问题
1.ListBox存在拖拉高度时,存在莫名奇妙的BUG。
2.目前该版本只支持单控件的拖拉,多控件同时拖拉等下次有空再弄。
五、附源代码下载
https://files.cnblogs.com/wangshenhe/DragControl.zip
SamWang
2012-05-14
作者:SamWang
出处:http://wangshenhe.cnblogs.com/
本文版权归作者和博客园共有,欢迎围观转载。转载时请您务必在文章明显位置给出原文链接,谢谢您的合作。