Программно начать перемещение формы - PullRequest
0 голосов
/ 11 января 2009

Я пытаюсь сделать движение формы (используя заголовок) одним нажатием кнопки.

Я думал, что это будет просто, используя 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 ]

3 голосов
/ 11 января 2009

Вам потребуется WM_NCLBUTTONDOWN (и передать HTCAPTION как wParam). Я все еще не совсем уверен, что это достигнет того, что вы пытаетесь сделать.

Как правило, способ, позволяющий пользователю перемещать вашу форму при щелчке мышью где-либо, кроме строки заголовка, - это обрабатывать сообщение WM_NCHITTEST и возвращать HTCAPTION, когда курсор находится над областью, из которой вы хотите начать движение. Однако, если эта область занята дочерним элементом управления, вы также должны обработать WM_NCHITTEST из дочернего элемента управления и вернуть HTTRANSPARENT.


Кстати, более простой, хотя и несколько менее правильный, способ сделать это - сделать так, как Мехрдад Афшари предложил , и просто установить свойство формы 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-решением, которое не зависит от вызова любой платформы (поэтому оно должно быть переносимым на Mono в Unix).


К сожалению. Я только что понял, что дал вам пример кода на 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. Я использовал Отражатель , чтобы помочь мне перевести его.

2 голосов
/ 11 января 2009

Мердад прав, нет необходимости делать это. Мышь захвачена, поэтому вы никогда не сможете переместить ее слишком быстро. Пример кода:

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;
}
2 голосов
/ 11 января 2009

Значение LParam для сообщения wm_LButtonDown получает положение мыши в клиентских координатах. Строка заголовка находится не в клиентской области, поэтому используйте сообщение wm_NCLButtonDown . Я видел это сообщение как ответ на этот вопрос раньше, но я ожидал, что есть более прямой маршрут: отправьте wm_SysCommand сообщение в окно и укажите sc_Move флаг.

...