【问题标题】:Programmatically start moving a form以编程方式开始移动表单
【发布时间】:2009-01-11 19:47:02
【问题描述】:

我正在尝试通过单击按钮来移动表单(使用标题栏)。

我认为使用 SendMessage 会很简单:

Const WM_LBUTTONDOWN As Integer = &H201

Button1.Capture = False
Cursor.Position = Me.Location + New Size(50, 8)

SendMessage(Me.Handle, WM_LBUTTONDOWN, CType(1, IntPtr), IntPtr.Zero)

但是,尽管如果光标位于表单客户端区域中,这会发送消息,但它似乎不会将其发送到表单标题栏(表单以某种方式捕获事件,尽管光标位于标题栏而不是客户端区域)。

我已经在按钮上的 mousedown 和 click 事件中尝试了上面的代码,移动光标然后按下 button1。

有什么建议吗?

【问题讨论】:

    标签: c# vb.net winforms sendmessage


    【解决方案1】:

    您需要WM_NCLBUTTONDOWN(并将HTCAPTION 传递为wParam)。不过,我仍然不能完全确定这会完成你想要做的事情。

    通常,允许用户在单击标题栏以外的位置时移动表单的方法是处理 WM_NCHITTEST 消息并在光标位于您想要移动的区域上时返回 HTCAPTION开始移动。但是,如果该区域被子控件占用,则还必须处理子控件中的WM_NCHITTEST 并返回HTTRANSPARENT


    顺便说一句,完成此操作的更简单(如果稍微不太正确)的方法是像 Mehrdad Afshari suggested 一样,只需设置表单的 Location 属性。你对他说“它需要随着鼠标移动而移动”,而这正是你可以而且应该做的。

    class MyForm : Form{
        Point downAt;
    
        MyForm(){
            Label lbl      = new Label();
            lbl.AutoSize   = true;
            lbl.BackColor  = Color.Blue;
            lbl.ForeColor  = Color.White;
            lbl.Location   = new Point(50, 50);
            lbl.Text       = "Drag me to move this form.";
            lbl.Parent     = this;
            lbl.MouseDown += (s, e)=>downAt = e.Location;
            lbl.MouseMove += (s, e)=>{if(lbl.Capture) Location += (Size)e.Location - (Size)downAt;};
        }
    }
    

    这种方法的问题在于它绕过了 Windows 用于移动顶级窗口的代码。这意味着如果用户没有在“显示属性”对话框中选择“拖动时显示窗口内容”选项,这将有效地忽略该设置(它不会显示拖动轮廓)。可能还有其他我没有想到的缺点。

    不过,总的来说,这是一种简单易行的实现方式,它是一个完全 .NET 的解决方案,不依赖于任何平台调用(因此它应该可以移植到 Unix 上的 Mono)。


    哎呀。我刚刚意识到我给了你 C# 示例代码,但你的代码似乎是 VB.NET。我猜你需要的是:

    Sub New()
        Dim lbl As New Label
        lbl.AutoSize  = True
        lbl.BackColor = Color.Blue
        lbl.ForeColor = Color.White
        lbl.Location  = New Point(50, 50)
        lbl.Text      = "Drag me to move this form."
        lbl.Parent    = Me
        AddHandler lbl.MouseDown, Function(ByVal s As Object, ByVal e As MouseEventArgs)
            Me.downAt = e.Location
        End Function
        AddHandler lbl.MouseMove, Function(ByVal s As Object, ByVal e As MouseEventArgs)
            If lbl.Capture Then
                Me.Location = Me.Location + DirectCast(e.Location, Size) - DirectCast(Me.downAt, Size)
            End If
        End Function
    End Sub
    

    这可能不是在 VB.NET 中表达这一点的最简洁的方式。我用Reflector帮我翻译了。

    【讨论】:

    • 别担心,我将问题标记为 c# 和 vb.net,因为我不介意任何一个答案:)
    【解决方案2】:

    wm_LButtonDown 消息的LParam 值接收鼠标在客户端 坐标中的位置。标题栏在非客户区,所以使用wm_NCLButtonDown message。我之前已经看到该消息作为此问题的答案,但我希望有一条更直接的方法可以工作:将wm_SysCommand message 发送到窗口,并指定sc_Move 标志。

    【讨论】:

      【解决方案3】:

      Mehrdad 是对的,没必要这么做。鼠标被捕获,因此您永远不能太快移动它。示例代码:

      Point mLastPos;
      private void button1_MouseMove(object sender, MouseEventArgs e) {
        if (e.Button == MouseButtons.Left) {
          this.Location = new Point(this.Location.X + e.X - mLastPos.X,
            this.Location.Y + e.Y - mLastPos.Y);
        }
        // NOTE: else is intentional!
        else mLastPos = e.Location;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-20
        • 2018-07-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多