自由resize处理无边框格式C#

我正在尝试制作从工具栏中弹出的无边框表单。 我希望用户能够抓住右下角(“resize句柄”)并能够调整表单大小,但无法以任何其他方式调整表单大小或重新定位。

我听说我可以拦截发送到表单的WM_NCHITTEST消息并将其结果设置为HTBOTTOMRIGHT ,这将让操作系统处理表单的重新resize,就像它有一个相当大的帧一样。 我的想法是检测鼠标指针是否已进入我在角落中定义的框,如果它已经,则返回HTBOTTOMRIGHT结果。

图示说明调整大小手柄

这并不像我预期的那样有效。 我能够拦截消息,但似乎只有当用户将鼠标光标放在窗体的1px粗边框上时才会发送消息。 这意味着它可以按照我想要的方式工作,如果你非常精确地将光标定位在右下角。

这是我的WndProc覆盖:

 protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 HTBOTTOMRIGHT = 17; const int RESIZE_HANDLE_SIZE = 40; bool handled = false; if (m.Msg == WM_NCHITTEST) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Rectangle hitBox = new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE); if (hitBox.Contains(clientPoint)) { m.Result = (IntPtr)HTBOTTOMRIGHT; handled = true; } } if (!handled) base.WndProc(ref m); } 

我做错了什么还是有更好的方法来做我想做的事情?

非常感谢。

我正在寻找类似的东西,安东的代码是一个很好的基础。 这就是我最终要从各方面调整工作量。 我不确定Dictionary是存储命中箱的最佳方式,但我想这并不重要。

而且由于我的表单中填充了使用Fill作为Dock参数的控件,我只需要在Form添加一个5px填充,以便它可以很好地工作。

 protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 WM_MOUSEMOVE = 0x0200; const UInt32 HTLEFT = 10; const UInt32 HTRIGHT = 11; const UInt32 HTBOTTOMRIGHT = 17; const UInt32 HTBOTTOM = 15; const UInt32 HTBOTTOMLEFT = 16; const UInt32 HTTOP = 12; const UInt32 HTTOPLEFT = 13; const UInt32 HTTOPRIGHT = 14; const int RESIZE_HANDLE_SIZE = 10; bool handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Dictionary boxes = new Dictionary() { {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOM, new Rectangle(RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE)}, {HTTOPRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOP, new Rectangle(RESIZE_HANDLE_SIZE, 0, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOPLEFT, new Rectangle(0, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTLEFT, new Rectangle(0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE) } }; foreach (KeyValuePair hitBox in boxes) { if (hitBox.Value.Contains(clientPoint)) { m.Result = (IntPtr) hitBox.Key; handled = true; break; } } } if (!handled) base.WndProc(ref m); } 

只需对您的代码进行一些修改。 我添加了WM_MOUSEMOVE消息处理:

  protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 WM_MOUSEMOVE = 0x0200; const UInt32 HTBOTTOMRIGHT = 17; const int RESIZE_HANDLE_SIZE = 10; bool handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE ) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Rectangle hitBox = new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE); if (hitBox.Contains(clientPoint)) { m.Result = (IntPtr)HTBOTTOMRIGHT; handled = true; } } if (!handled) base.WndProc(ref m); } 

顺便说一句,您可以使用ControlPaint.DrawSizeGrip Method绘制系统特定的窗口大小手柄http://msdn.microsoft.com/en-us/library/2e1yx2sa.aspx

安东塞梅诺夫 ,我不明白你的代码。

无论如何,我对Charles P的第一个代码有疑问
当我最大化窗口,然后尝试改变它的大小 – 它正在resize。
之后,我无法将其再次修复到正常大小,也无法使用正常的最大按钮再次将其重新设置。

我解决这个问题的方法是在底部的’foreach’循环中添加条件:

  protected override void WndProc(ref Message m) { const UInt32 WM_NCHITTEST = 0x0084; const UInt32 WM_MOUSEMOVE = 0x0200; const UInt32 HTLEFT = 10; const UInt32 HTRIGHT = 11; const UInt32 HTBOTTOMRIGHT = 17; const UInt32 HTBOTTOM = 15; const UInt32 HTBOTTOMLEFT = 16; const UInt32 HTTOP = 12; const UInt32 HTTOPLEFT = 13; const UInt32 HTTOPRIGHT = 14; const int RESIZE_HANDLE_SIZE = 10; bool handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE) { Size formSize = this.Size; Point screenPoint = new Point(m.LParam.ToInt32()); Point clientPoint = this.PointToClient(screenPoint); Dictionary boxes = new Dictionary() { {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOM, new Rectangle(RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)}, {HTRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE)}, {HTTOPRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOP, new Rectangle(RESIZE_HANDLE_SIZE, 0, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTTOPLEFT, new Rectangle(0, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) }, {HTLEFT, new Rectangle(0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE) } }; foreach (KeyValuePair hitBox in boxes) { if (this.WindowState != FormWindowState.Maximized && hitBox.Value.Contains(clientPoint)) { m.Result = (IntPtr)hitBox.Key; handled = true; break; } } } if (!handled) base.WndProc(ref m); } 

基于Charles P.解决方案对它进行了一些修改,希望它也能帮助其他人:)小的检查和改进,以便在每次调用windows消息时都不声明额外的变量。 当窗口状态最大化时,还检查不绘制握柄锚。 我想用它创建一个自定义控件,但不幸的是我最终用这个代码填充了表单。

构造函数或在设计器文件中:

 this.DoubleBuffered = true; this.ResizeRedraw = true; 

覆盖窗口function:

  const uint WM_NCHITTEST = 0x0084, WM_MOUSEMOVE = 0x0200, HTLEFT = 10, HTRIGHT = 11, HTBOTTOMRIGHT = 17, HTBOTTOM = 15, HTBOTTOMLEFT = 16, HTTOP = 12, HTTOPLEFT = 13, HTTOPRIGHT = 14; Size formSize; Point screenPoint; Point clientPoint; Dictionary boxes; const int RHS = 10; // RESIZE_HANDLE_SIZE bool handled; protected override void WndProc(ref Message m) { if (this.WindowState == FormWindowState.Maximized) { base.WndProc(ref m); return; } handled = false; if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE) { formSize = this.Size; screenPoint = new Point(m.LParam.ToInt32()); clientPoint = this.PointToClient(screenPoint); boxes = new Dictionary() { {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RHS, RHS, RHS)}, {HTBOTTOM, new Rectangle(RHS, formSize.Height - RHS, formSize.Width - 2*RHS, RHS)}, {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RHS, formSize.Height - RHS, RHS, RHS)}, {HTRIGHT, new Rectangle(formSize.Width - RHS, RHS, RHS, formSize.Height - 2*RHS)}, {HTTOPRIGHT, new Rectangle(formSize.Width - RHS, 0, RHS, RHS) }, {HTTOP, new Rectangle(RHS, 0, formSize.Width - 2*RHS, RHS) }, {HTTOPLEFT, new Rectangle(0, 0, RHS, RHS) }, {HTLEFT, new Rectangle(0, RHS, RHS, formSize.Height - 2*RHS) } }; foreach (var hitBox in boxes) { if (hitBox.Value.Contains(clientPoint)) { m.Result = (IntPtr)hitBox.Key; handled = true; break; } } } if (!handled) base.WndProc(ref m); } protected override void OnPaint(PaintEventArgs e) { if (this.WindowState != FormWindowState.Maximized) { ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, this.ClientSize.Width - 16, this.ClientSize.Height - 16, 16, 16); } base.OnPaint(e); }