以编程方式开始移动表单

时间:2009-01-11 19:47:02

标签: c# vb.net winforms sendmessage

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

我认为使用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事件中尝试了上述代码,移动光标然后按下按钮1。

有什么建议吗?

3 个答案:

答案 0 :(得分:3)

您需要WM_ NC LBUTTONDOWN(并将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来帮助我翻译它。

答案 1 :(得分:2)

LParam消息的wm_LButtonDown值接收 client 坐标中的鼠标位置。标题栏位于非客户区域,因此请使用wm_NCLButtonDown message。我之前看过这个问题作为这个问题的答案给出了,但是我希望有一个更直接的路径:向窗口发送wm_SysCommand message,并指定sc_Move标志。 / p>

答案 2 :(得分:2)

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;
}