我正在我的应用程序中实现屏幕截图,用户可以选择要捕获的部分,为此,我使用此链接中提供的示例创建了一个控件来覆盖图片框: 创建带有可拖动和可调整大小的选择窗口的自定义图片框
该控件运行良好,做了需要做的事情,但我实现起来遇到困难的是,当用户单击控件外部的按钮时,它将不再移动,将其光标从 SizeAll 更改为 Arrow,但是仍然可以调整大小。
我如何执行这样的任务?
这是我现在用来创建控件的代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ControlSizable
{
public partial class FrameControl: UserControl
{
public FrameControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
DoubleBuffered = true;
ResizeRedraw = true;
BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var p = new Pen(Color.White , 3))
{
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
e.Graphics.DrawRectangle(p, 0, 0, Width - 1, Height - 1);
}
}
const int WM_NCHITTEST = 0x84;
const int WM_SETCURSOR = 0x20;
const int WM_NCLBUTTONDBLCLK = 0xA3;
protected override void WndProc(ref Message m)
{
int borderWidth = 10;
if (m.Msg == WM_SETCURSOR) /*Setting cursor to SizeAll*/
{
if ((m.LParam.ToInt32() & 0xffff) == 0x2 /*Move*/)
{
Cursor.Current = Cursors.SizeAll;
m.Result = (IntPtr)1;
return;
}
}
if ((m.Msg == WM_NCLBUTTONDBLCLK)) /*Disable Mazimiz on Double click*/
{
m.Result = (IntPtr)1;
return;
}
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
{
var pos = PointToClient(new Point(m.LParam.ToInt32() & 0xffff,
m.LParam.ToInt32() >> 16));
if (pos.X <= ClientRectangle.Left + borderWidth &&
pos.Y <= ClientRectangle.Top + borderWidth)
m.Result = new IntPtr(13); //TOPLEFT
else if (pos.X >= ClientRectangle.Right - borderWidth &&
pos.Y <= ClientRectangle.Top + borderWidth)
m.Result = new IntPtr(14); //TOPRIGHT
else if (pos.X <= ClientRectangle.Left + borderWidth &&
pos.Y >= ClientRectangle.Bottom - borderWidth)
m.Result = new IntPtr(16); //BOTTOMLEFT
else if (pos.X >= ClientRectangle.Right - borderWidth &&
pos.Y >= ClientRectangle.Bottom - borderWidth)
m.Result = new IntPtr(17); //BOTTOMRIGHT
else if (pos.X <= ClientRectangle.Left + borderWidth)
m.Result = new IntPtr(10); //LEFT
else if (pos.Y <= ClientRectangle.Top + borderWidth)
m.Result = new IntPtr(12); //TOP
else if (pos.X >= ClientRectangle.Right - borderWidth)
m.Result = new IntPtr(11); //RIGHT
else if (pos.Y >= ClientRectangle.Bottom - borderWidth)
m.Result = new IntPtr(15); //Bottom
else
m.Result = new IntPtr(2); //Move
}
}
}
}
我想做的是,当用户单击箭头按钮时,控件不再在屏幕上移动,只是按边缘调整大小,我可以在绘图本身中绘制箭头(绘制箭头的过程箭头,我已经可以做到了)
向自定义控件添加公共
bool
属性,此处名为 CanMove
,默认为 true
。
然后,在 WndProc 重写中,当消息为
WM_SETCURSOR
时,您评估 CanMove
:如果它是默认值 (true
),则将光标设置为 Cursors.SizeAll
,否则设置为 Cursors.Arrow
(或其他值)你觉得合适)
当消息为
WM_NCHITTEST
时,在最后一个 if
条件下,如果 CanMove 为 true
,则返回 (IntPtr)2
,否则 IntPtr.Zero
。
在 FrameControl 类文件顶部添加
using System.ComponentModel;
。
当
CanMove
为 false
时,控件仍可调整大小。
因此,当您单击该按钮时,只需将 Framecontrol 的
CanMove
属性设置为 false
。
using System.ComponentModel;
public class FrameControl : Control {
public FrameControl() { // [...]}
[DefaultValue(true)]
public bool CanMove { get; set; } = true;
// [...]
protected override void WndProc(ref Message m) {
if (m.Msg == WM_SETCURSOR) /*Setting cursor to SizeAll*/
{
if ((m.LParam.ToInt32() & 0xffff) == 0x2 /*Move*/) {
Cursor.Current = CanMove ? Cursors.SizeAll : Cursors.Arrow;
m.Result = (IntPtr)1;
return;
}
}
// [...]
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST) {
// [...]
if (pos.X <= ClientRectangle.Left + borderWidth &&
pos.Y <= ClientRectangle.Top + borderWidth)
m.Result = new IntPtr(13); //TOPLEFT
// [...]
else
m.Result = CanMove ? new IntPtr(2) : IntPtr.Zero;
}
}
}