模拟拖动窗口标题栏的控件

发布于 2024-08-24 03:10:56 字数 108 浏览 3 评论 0原文

我已经构建了一个自定义控件,我希望允许人们单击并拖动我的控件,就像在窗口标题栏上拖动一样。最好的方法是什么?

到目前为止,我未能成功地利用鼠标向下、向上和移动事件来破译何时需要移动窗口。

I've built a custom control, and I'd like to allow people to click and drag on my control just as if they were dragging on the window title bar. What is the best way to do this?

So far I've been unsuccessful at leveraging the mouse down, up, and move events to decipher when the window needs to be moved.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

枉心 2024-08-31 03:10:56

除了我的其他答案之外,您还可以在控件中手动执行此操作,如下所示:

Point dragOffset;

protected override void OnMouseDown(MouseEventArgs e) {
    base.OnMouseDown(e);
    if (e.Button == MouseButtons.Left) {
        dragOffset = this.PointToScreen(e.Location);
        var formLocation = FindForm().Location;
        dragOffset.X -= formLocation.X;
        dragOffset.Y -= formLocation.Y;
    }
}

protected override void OnMouseMove(MouseEventArgs e) {
    base.OnMouseMove(e);

    if (e.Button == MouseButtons.Left) {
        Point newLocation = this.PointToScreen(e.Location);

        newLocation.X -= dragOffset.X;
        newLocation.Y -= dragOffset.Y;

        FindForm().Location = newLocation;
    }
}

编辑:已测试并修复 - 现在实际上有效。

In addition to my other answer, you can do this manually in a Control like this:

Point dragOffset;

protected override void OnMouseDown(MouseEventArgs e) {
    base.OnMouseDown(e);
    if (e.Button == MouseButtons.Left) {
        dragOffset = this.PointToScreen(e.Location);
        var formLocation = FindForm().Location;
        dragOffset.X -= formLocation.X;
        dragOffset.Y -= formLocation.Y;
    }
}

protected override void OnMouseMove(MouseEventArgs e) {
    base.OnMouseMove(e);

    if (e.Button == MouseButtons.Left) {
        Point newLocation = this.PointToScreen(e.Location);

        newLocation.X -= dragOffset.X;
        newLocation.Y -= dragOffset.Y;

        FindForm().Location = newLocation;
    }
}

EDIT: Tested and fixed - this now actually works.

像你 2024-08-31 03:10:56

最有效的方法是处理 <代码>WM_NCHITTEST通知。

重写表单的 WndProc 方法并添加以下代码:

if (m.Msg == 0x0084) {              //WM_NCHITTEST
    var point = new Point((int)m.LParam);
    if(someRect.Contains(PointToClient(point))
        m.Result = new IntPtr(2);   //HT_CAPTION
}

但是,我认为如果此时存在控件,则不会发送消息。

The most effective way to do this is to handle the WM_NCHITTEST notification.

Override the form's WndProc method and add the following code:

if (m.Msg == 0x0084) {              //WM_NCHITTEST
    var point = new Point((int)m.LParam);
    if(someRect.Contains(PointToClient(point))
        m.Result = new IntPtr(2);   //HT_CAPTION
}

However, I don't think the message will be sent if there is a control at that point.

娇妻 2024-08-31 03:10:56

如果您想让表单的一部分表现得像标题一样,那么 SL​​aks 提供的 WM_NCHITTEST 技巧就是最佳选择。但如果你想让子窗口能够拖动窗体,还有另一种方法。

基本上,如果您使用 MOUSE_MOVE 命令 id 向 DefWindowProc 发送 WM_SYSCOMMAND 消息,那么 Windows 将进入拖动模式。这基本上是标题的实现方式,但是通过删除中间人,我们可以从子窗口启动此拖动,并且我们不会获得所有其他标题行为。

public class form1 : Form 
{
  ...

  [DllImport("user32.dll")]
  static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, IntPtr lParam);
  [DllImport("user32.dll")]
  static extern bool ReleaseCapture(IntPtr hwnd);

  const uint WM_SYSCOMMAND = 0x112;
  const uint MOUSE_MOVE = 0xF012;      

  public void DragMe()
  {
     DefWindowProc(this.Handle, WM_SYSCOMMAND, (UIntPtr)MOUSE_MOVE, IntPtr.Zero);
  }


  private void button1_MouseDown(object sender, MouseEventArgs e)
  {
     Control ctl = sender as Control;

     // when we get a buttondown message from a button control
     // the button has capture, we need to release capture so
     // or DragMe() won't work.
     ReleaseCapture(ctl.Handle);

     this.DragMe(); // put the form into mousedrag mode.
  }

If you want to make a part of the form behave like the caption, the WM_NCHITTEST trick that SLaks gave is the way to go. But if you want to make a child window be able to drag the form and there is another way.

Basically if you send a WM_SYSCOMMAND message to DefWindowProc with the MOUSE_MOVE command id, then Windows will go into drag mode. This basically how the caption does it, but by cutting out the middle man, we can initiate this drag from a child window, and we don't get all of the other caption behaviors.

public class form1 : Form 
{
  ...

  [DllImport("user32.dll")]
  static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, IntPtr lParam);
  [DllImport("user32.dll")]
  static extern bool ReleaseCapture(IntPtr hwnd);

  const uint WM_SYSCOMMAND = 0x112;
  const uint MOUSE_MOVE = 0xF012;      

  public void DragMe()
  {
     DefWindowProc(this.Handle, WM_SYSCOMMAND, (UIntPtr)MOUSE_MOVE, IntPtr.Zero);
  }


  private void button1_MouseDown(object sender, MouseEventArgs e)
  {
     Control ctl = sender as Control;

     // when we get a buttondown message from a button control
     // the button has capture, we need to release capture so
     // or DragMe() won't work.
     ReleaseCapture(ctl.Handle);

     this.DragMe(); // put the form into mousedrag mode.
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文