有没有办法在表单的边框设置为“无”(FormBorderStyle被设置为“none”)时,使其像有边框一样在鼠标按下时能够移动?
这篇 CodeProject 上的文章详细介绍了一种技术。基本上归结为:
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
从窗口管理器的角度来看,这基本上与抓取窗口标题栏完全相同。
让我们不要把事情弄得比必要的更难。我已经遇到了很多代码片段,允许你拖动一个表单(或其他控件)。其中许多都有自己的缺点/副作用。特别是那些骗过Windows认为表单上的控件是实际表单的控件。
话虽如此,这里是我的代码片段。我经常使用它。我还想指出,你不应该像其他人一样使用this.Invalidate();,因为在某些情况下会导致窗体闪烁。有些情况下,this.Refresh也会闪烁。使用this.Update,我没有遇到任何闪烁问题:
private bool mouseDown;
private Point lastLocation;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
lastLocation = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if(mouseDown)
{
this.Location = new Point(
(this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
this.Update();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
e.Clicks == 1
时才设置 mouseDown = true
。2)如果您的窗体上有控件(面板),则此方法无效。 我会挂钩表单上大多数控件的事件,除了某些没有意义的控件,如按钮。 - Dave Cousineau另一个更简单的方法来做同样的事情。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// set this.FormBorderStyle to None here if needed
// if set to none, make sure you have a way to close the form!
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
m.Result = (IntPtr)(HT_CAPTION);
}
private const int WM_NCHITTEST = 0x84;
private const int HT_CLIENT = 0x1;
private const int HT_CAPTION = 0x2;
}
使用MouseDown(鼠标按下),MouseMove(鼠标移动)和MouseUp(鼠标松开)事件,可以设置一个变量标志。我有一个示例,但我认为您需要进行修改。
我正在将鼠标操作编码到面板中。一旦你点击面板,你的窗体就会随之移动。
//Global variables;
private bool _dragging = false;
private Point _offset;
private Point _start_point=new Point(0,0);
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
_dragging = true; // _dragging is your variable flag
_start_point = new Point(e.X, e.Y);
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
_dragging = false;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if(_dragging)
{
Point p = PointToScreen(e.Location);
Location = new Point(p.X - this._start_point.X,p.Y - this._start_point.Y);
}
}
仅适用于WPF。
我手头没有确切的代码,但在最近的项目中,我认为我使用了MouseDown事件,并简单地将其放置在此处:
frmBorderless.DragMove();
它适用于我。
private Point _mouseLoc;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
_mouseLoc = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.Location.X - _mouseLoc.X;
int dy = e.Location.Y - _mouseLoc.Y;
this.Location = new Point(this.Location.X + dx, this.Location.Y + dy);
}
}
这是经过测试并易于理解的。
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x84:
base.WndProc(ref m);
if((int)m.Result == 0x1)
m.Result = (IntPtr)0x2;
return;
}
base.WndProc(ref m);
}
WM_NCHITTEST
的东西。 - Andreas RejbrandWndProc
是低级API中的一种,它控制所有事件,例如窗体创建、控件添加、删除等。因此,他只需编辑WndProc
即可。 - Gray Programmerz由于某些答案不允许子控件可拖动,因此我创建了一个小的辅助类。应该将顶级表单传递给它。如果需要,可以更加通用。
class MouseDragger
{
private readonly Form _form;
private Point _mouseDown;
protected void OnMouseDown(object sender, MouseEventArgs e)
{
_mouseDown = e.Location;
}
protected void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.Location.X - _mouseDown.X;
int dy = e.Location.Y - _mouseDown.Y;
_form.Location = new Point(_form.Location.X + dx, _form.Location.Y + dy);
}
}
public MouseDragger(Form form)
{
_form = form;
MakeDraggable(_form);
}
private void MakeDraggable(Control control)
{
var type = control.GetType();
if (typeof(Button).IsAssignableFrom(type))
{
return;
}
control.MouseDown += OnMouseDown;
control.MouseMove += OnMouseMove;
foreach (Control child in control.Controls)
{
MakeDraggable(child);
}
}
}
我发现的最好方法(当然进行了修改)
// This adds the event handler for the control
private void AddDrag(Control Control) { Control.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DragForm_MouseDown); }
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
private void DragForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
// Checks if Y = 0, if so maximize the form
if (this.Location.Y == 0) { this.WindowState = FormWindowState.Maximized; }
}
}
AddDrag(NameOfControl);
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
this.Capture = false;
Message msg = Message.Create(this.Handle, 0XA1, new IntPtr(2), IntPtr.Zero);
this.WndProc(ref msg);
}
}
Form1_MouseDown
没有分配到Form1
的实际MouseDown
事件。 - Remon RamyMain()
函数中添加this.MouseDown += ...
。 - Richard Peck