在运行时绘制可调整大小的控件
如何在运行时绘制可调整大小的控件

引言
本文将展示如何围绕图形对象绘制边框,并将它们放置在窗体上,以便用户可以通过拖动或调整控件大小来操作这些对象。希望这对某人有所帮助。
背景
我参与一个项目,其中一个小的方面是允许最终用户在窗体上放置各种对象并操作它们的属性。该应用程序是用 Delphi 开发的,我很好奇在 .NET 中实现类似功能需要什么。
Using the Code
首先,定义将出现在控件周围的拖动句柄的大小。
const int DRAG_HANDLE_SIZE = 7;
实际绘制边框和拖动句柄的方法如下
/// <summary>
/// Draw a border and drag handles around the control, on mouse down and up.
/// </summary>
/// <param name=""sender"" ></param >
private void DrawControlBorder(object sender)
{
Control control = (Control)sender;
//define the border to be drawn, it will be offset by DRAG_HANDLE_SIZE / 2
//around the control, so when the drag handles are drawn they will seem to be
//connected in the middle.
Rectangle Border = new Rectangle(
new Point(control.Location.X - DRAG_HANDLE_SIZE / 2,
control.Location.Y - DRAG_HANDLE_SIZE / 2),
new Size(control.Size.Width + DRAG_HANDLE_SIZE,
control.Size.Height + DRAG_HANDLE_SIZE));
//define the 8 drag handles, that has the size of DRAG_HANDLE_SIZE
Rectangle NW = new Rectangle(
new Point(control.Location.X - DRAG_HANDLE_SIZE,
control.Location.Y - DRAG_HANDLE_SIZE),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
Rectangle N = new Rectangle(
new Point(control.Location.X + control.Width / 2 - DRAG_HANDLE_SIZE/2,
control.Location.Y - DRAG_HANDLE_SIZE),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
Rectangle NE = new Rectangle(
new Point(control.Location.X + control.Width,
control.Location.Y - DRAG_HANDLE_SIZE),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
Rectangle W = new Rectangle(
new Point(control.Location.X - DRAG_HANDLE_SIZE,
control.Location.Y + control.Height/2-DRAG_HANDLE_SIZE/2),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
Rectangle E = new Rectangle(
new Point(control.Location.X + control.Width,
control.Location.Y + control.Height / 2 - DRAG_HANDLE_SIZE / 2),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
Rectangle SW = new Rectangle(
new Point(control.Location.X - DRAG_HANDLE_SIZE,
control.Location.Y + control.Height),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
Rectangle S = new Rectangle(
new Point(control.Location.X + control.Width / 2 - DRAG_HANDLE_SIZE/2,
control.Location.Y + control.Height),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
Rectangle SE = new Rectangle(
new Point(control.Location.X + control.Width,
control.Location.Y + control.Height),
new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
//get the form graphic
Graphics g = this.CreateGraphics();
//draw the border and drag handles
ControlPaint.DrawBorder(g, Border, Color.Gray, ButtonBorderStyle.Dotted);
ControlPaint.DrawGrabHandle(g, NW, true, true);
ControlPaint.DrawGrabHandle(g, N, true, true);
ControlPaint.DrawGrabHandle(g, NE, true, true);
ControlPaint.DrawGrabHandle(g, W, true, true);
ControlPaint.DrawGrabHandle(g, E, true, true);
ControlPaint.DrawGrabHandle(g, SW, true, true);
ControlPaint.DrawGrabHandle(g, S, true, true);
ControlPaint.DrawGrabHandle(g, SE, true, true);
g.Dispose();
}
接下来,实现 Control
对象的各种事件,例如,当我单击一个控件时,我希望在它周围绘制边框和拖动句柄,因此在 MouseDown
事件中
private void control_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Invalidate(); //unselect other control
SelectedControl = (Control)sender;
Control control = (Control)sender;
mouseX = -e.X;
mouseY = -e.Y;
control.Invalidate();
DrawControlBorder(sender);
propertyGrid1.SelectedObject = SelectedControl;
}
}
最后,要使用它,请在运行时创建一个控件并让它订阅各种事件,例如创建按钮
Button ctrl = new Button();
ctrl.Text = "New Button";
ctrl.Location = new Point(50, 50);
ctrl.MouseEnter += new EventHandler(control_MouseEnter);
ctrl.MouseLeave += new EventHandler(control_MouseLeave);
ctrl.MouseDown += new MouseEventHandler(control_MouseDown);
ctrl.MouseMove += new MouseEventHandler(control_MouseMove);
ctrl.MouseUp += new MouseEventHandler(control_MouseUp);
Controls.Add(ctrl);
就这样。执行后,您可以移动对象,并可以从所有 8 个方向调整它们的大小。
关注点
如果您下载源代码,您会注意到我使用一个计时器来跟踪光标的移动。我尝试使用窗体的 MouseHover
事件,但它仅在光标在其上方或离开其中一个控件时执行一次,并且随后当光标位于其中一个拖动句柄上时,它将无法识别它。使用计时器可以解决这个问题,但如果您找到了更好的方法,请告诉我!
历史
- 2008/3/4:首次发布