【发布时间】:2010-12-08 06:01:15
【问题描述】:
有没有办法让没有边框(FormBorderStyle 设置为“none”)的表单在鼠标在表单上单击时像有边框一样可移动?
【问题讨论】:
标签: c# winforms border movable
有没有办法让没有边框(FormBorderStyle 设置为“none”)的表单在鼠标在表单上单击时像有边框一样可移动?
【问题讨论】:
标签: c# winforms border movable
This 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);
}
}
从窗口管理器的角度来看,这完全与抓取窗口的标题栏完全相同。
【讨论】:
Form1_MouseDown 没有分配给Form1 的实际MouseDown 事件,所以它不起作用。
Main()函数中添加this.MouseDown += ...
我们不要让事情变得比他们需要的更困难。我遇到了很多允许您拖动表单(或另一个控件)的代码 sn-ps。他们中的许多人都有自己的缺点/副作用。尤其是那些他们欺骗 Windows 认为窗体上的控件是实际窗体的那些。
话虽如此,这是我的sn-p。我用它所有的时间。我还要注意你不应该使用 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)如果您的表单上有控件(面板),这将不起作用。我所做的是挂钩表单上大多数控件的事件,除了一些没有意义的按钮,如按钮。
做同样事情的另一种更简单的方法。
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();
【讨论】:
这是经过测试且易于理解的。
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伪装的。
它对我有用。
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);
}
}
【讨论】:
没有任何属性可以翻转来让这一切神奇地发生。查看表单的事件,通过设置this.Top 和this.Left 来实现它变得相当简单。具体来说,您需要查看MouseDown、MouseUp 和MouseMove。
【讨论】:
public Point mouseLocation;
private void frmInstallDevice_MouseDown(object sender, MouseEventArgs e)
{
mouseLocation = new Point(-e.X, -e.Y);
}
private void frmInstallDevice_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point mousePos = Control.MousePosition;
mousePos.Offset(mouseLocation.X, mouseLocation.Y);
Location = mousePos;
}
}
这可以解决你的问题....
【讨论】:
上面链接中的这段代码在我的例子中起到了作用:)
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);
}
}
【讨论】:
由于某些答案不允许子控件可拖动,因此我创建了一个小助手类。 它应该通过顶级表单。如果需要,可以变得更通用。
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; }
}
}
要将拖动应用到控件,只需在 InitializeComponent() 之后插入它
AddDrag(NameOfControl);
【讨论】:
对于 .NET Framework 4,
您可以将this.DragMove() 用于您用于拖动的组件(本例中为mainLayout)的MouseDown 事件。
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
【讨论】:
最简单的方法是:
首先创建一个名为 label1 的标签。 转到 label1 的事件 > 鼠标事件 > Label1_Mouse 移动并写下这些:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
【讨论】:
我试图制作一个可移动的无边框窗口窗体,其中包含一个 WPF 元素主机控件和一个 WPF 用户控件。
我最终在我的 WPF 用户控件中使用了一个名为 StackPanel 的堆栈面板,这似乎是尝试单击移动的合乎逻辑的事情。当我缓慢移动鼠标时,尝试 junmats 的代码有效,但如果我更快地移动鼠标,鼠标会从表单上移开,并且表单会卡在移动中间的某个地方。
这改进了他对我使用 CaptureMouse 和 ReleaseCaptureMouse 的情况的回答,现在即使我快速移动鼠标,鼠标在移动时也不会离开表单。
private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
{
_start_point = e.GetPosition(this);
StackPanel.CaptureMouse();
}
private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
StackPanel.ReleaseMouseCapture();
}
private void StackPanel_MouseMove(object sender, MouseEventArgs e)
{
if (StackPanel.IsMouseCaptured)
{
var p = _form.GetMousePositionWindowsForms();
_form.Location = new System.Drawing.Point((int)(p.X - this._start_point.X), (int)(p.Y - this._start_point.Y));
}
}
//Global variables;
private Point _start_point = new Point(0, 0);
【讨论】:
我正在使用另一种方法 ToolStrip1_MouseLeave 扩展 jay_t55 的解决方案,该方法处理鼠标快速移动并离开该区域的事件。
private bool mouseDown;
private Point lastLocation;
private void ToolStrip1_MouseDown(object sender, MouseEventArgs e) {
mouseDown = true;
lastLocation = e.Location;
}
private void ToolStrip1_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 ToolStrip1_MouseUp(object sender, MouseEventArgs e) {
mouseDown = false;
}
private void ToolStrip1_MouseLeave(object sender, EventArgs e) {
mouseDown = false;
}
【讨论】:
此外,如果您需要 DoubleClick 并使您的 Form 更大/更小,您可以使用第一个答案,创建一个全局 int 变量,每次用户单击您用于拖动的组件时添加 1。如果variable == 2 则使您的表单更大/更小。还可以每隔半秒或一秒使用一个计时器来制作您的variable = 0;
【讨论】:
将MouseLeftButtonDown 事件处理程序添加到 MainWindow 对我有用。
在自动生成的事件函数中,添加如下代码:
base.OnMouseLeftButtonDown(e);
this.DragMove();
【讨论】:
Form1():new Moveable(control1, control2, control3);
类:
using System;
using System.Windows.Forms;
class Moveable
{
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();
public Moveable(params Control[] controls)
{
foreach (var ctrl in controls)
{
ctrl.MouseDown += (s, e) =>
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(ctrl.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
// Checks if Y = 0, if so maximize the form
if (ctrl.FindForm().Location.Y == 0) { ctrl.FindForm().WindowState = FormWindowState.Maximized; }
}
};
}
}
}
【讨论】:
我尝试了以下和presto changeo,我的透明窗口不再被冻结但可以移动! (扔掉上面所有其他复杂的解决方案......)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
【讨论】: