2008-08-27 4 views
18

Ich erstelle ein kleines modales Formular, das in der Winforms-Anwendung verwendet wird. Es ist im Grunde eine Art Fortschrittsbalken. Aber ich möchte, dass der Benutzer in der Lage ist, irgendwo in das Formular zu klicken und es zu ziehen, um es auf dem Desktop zu verschieben, während es noch angezeigt wird.Winforms - Klicken Sie auf eine beliebige Stelle im Formular, um sie zu verschieben, als würde sie in der Formularbeschriftung geklickt.

Wie kann ich dieses Verhalten implementieren?

Antwort

23

Microsoft KB Article 320687 hat eine detaillierte Antwort auf diese Frage.

Sie überschreiben die WndProc-Methode, um HTCAPTION an die WM_NCHITTEST-Nachricht zurückzugeben, wenn sich der zu testende Punkt in dem Clientbereich des Formulars befindet - das bedeutet Windows eigentlich, den Klick genauso zu behandeln wie es war auf dem Titel des Formulars aufgetaucht.

private const int WM_NCHITTEST = 0x84; 
private const int HTCLIENT = 0x1; 
private const int HTCAPTION = 0x2; 

protected override void WndProc(ref Message m) 
{ 
    switch(m.Msg) 
    { 
    case WM_NCHITTEST: 
     base.WndProc(ref m); 
     if ((int)m.Result == HTCLIENT) 
     { 
     m.Result = (IntPtr)HTCAPTION; 
     } 

     return; 
    } 

    base.WndProc(ref m); 
} 
+0

Dies macht Kontextmenü nicht verfügbar. –

+0

Das funktioniert, aber wenn der Begrüßungsbildschirm über Steuerelemente verfügt (z. B. eine Beschriftung), wird durch Klicken auf das Label nicht bewegt. Wie man das speziell verwaltet, wenn der Splash mehrere Steuerelemente hat? – supafly

3

Der folgende Code geht davon aus, dass die ProgressBarForm Form ein ProgressBar-Steuerelement mit Dock Eigenschaft auf Füllen

public partial class ProgressBarForm : Form 
{ 
    private bool mouseDown; 
    private Point lastPos; 

    public ProgressBarForm() 
    { 
     InitializeComponent(); 
    } 

    private void progressBar1_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (mouseDown) 
     { 
      int xoffset = MousePosition.X - lastPos.X; 
      int yoffset = MousePosition.Y - lastPos.Y; 
      Left += xoffset; 
      Top += yoffset; 
      lastPos = MousePosition; 
     } 
    } 

    private void progressBar1_MouseDown(object sender, MouseEventArgs e) 
    { 
     mouseDown = true; 
     lastPos = MousePosition; 
    } 

    private void progressBar1_MouseUp(object sender, MouseEventArgs e) 
    { 
     mouseDown = false; 
    } 
} 
12

Hier sind ein Weg, um es mit einem P/Invoke zu tun.

public const int WM_NCLBUTTONDOWN = 0xA1; 
public const int HTCAPTION = 0x2; 
[DllImport("User32.dll")] 
public static extern bool ReleaseCapture(); 
[DllImport("User32.dll")] 
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); 

void Form_Load(object sender, EventArgs e) 
{ 
    this.MouseDown += new MouseEventHandler(Form_MouseDown); 
} 

void Form_MouseDown(object sender, MouseEventArgs e) 
{       
    if (e.Button == MouseButtons.Left) 
    { 
     ReleaseCapture(); 
     SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0); 
    } 
} 
+0

Sie müssen haben: using System.Runtime.InteropServices; damit [DllImport()] funktioniert. –

+1

In meinem Projekt habe ich Code ähnlich wie Timothy Fries verwendet, aber ich mag diesen, weil Sie genau die gleiche Technik verwenden können, um ein Formular zu erstellen, das durch seine Steuerelemente, wie Beschriftungen, verschoben werden kann. Die andere Technik macht die Form schleppbar, aber wenn Sie auf Etiketten klicken, wird es nicht ziehen. – flamey

+0

Dies ist auch schöner, weil Sie damit immer noch mit Rechtsklick-Ereignissen (für Kontextmenüs) umgehen können. Sie können auch wahlweise Linksklicken wie oben beschrieben verwenden oder Rechts-/Mittelklick statt Linksklick verwenden. Insgesamt viel flexibler. – coderforlife

0

Die akzeptierte Antwort ist ein cooler Trick, aber es funktioniert nicht immer, wenn das Formular von einem Fill-dockt Kind Steuerung wie ein Panel (oder Derivaten) zum Beispiel bedeckt ist, da diese Kontrolle alle essen die meisten Windows-Nachrichten.

ist hier eine einfache Ansatz, der auch in diesem Fall funktioniert: die Kontrolle in Frage ableiten (diese Klasse verwenden, anstatt der Standard) ein Griff Maus-Nachrichten wie folgt aus:

private class MyTableLayoutPanel : Panel // or TableLayoutPanel, etc. 
    { 
     private Point _mouseDown; 
     private Point _formLocation; 
     private bool _capture; 

     // NOTE: we cannot use the WM_NCHITTEST/HTCAPTION trick because the table is in control, not the owning form... 
     protected override void OnMouseDown(MouseEventArgs e) 
     { 
      _capture = true; 
      _mouseDown = e.Location; 
      _formLocation = ((Form)TopLevelControl).Location; 
     } 

     protected override void OnMouseUp(MouseEventArgs e) 
     { 
      _capture = false; 
     } 

     protected override void OnMouseMove(MouseEventArgs e) 
     { 
      if (_capture) 
      { 
       int dx = e.Location.X - _mouseDown.X; 
       int dy = e.Location.Y - _mouseDown.Y; 
       Point newLocation = new Point(_formLocation.X + dx, _formLocation.Y + dy); 
       ((Form)TopLevelControl).Location = newLocation; 
       _formLocation = newLocation; 
      } 
     } 
    } 
0

VC++ 2010 Version (von FlySwat's):

#include <Windows.h> 

namespace DragWithoutTitleBar { 

    using namespace System; 
    using namespace System::Windows::Forms; 
    using namespace System::ComponentModel; 
    using namespace System::Collections; 
    using namespace System::Data; 
    using namespace System::Drawing; 

    public ref class Form1 : public System::Windows::Forms::Form 
    { 
    public: 
     Form1(void) { InitializeComponent(); } 

    protected: 
     ~Form1() { if (components) { delete components; } } 

    private: 
     System::ComponentModel::Container ^components; 
     HWND hWnd; 

#pragma region Windows Form Designer generated code 
     void InitializeComponent(void) 
     { 
      this->SuspendLayout(); 
      this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); 
      this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; 
      this->ClientSize = System::Drawing::Size(640, 480); 
      this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::None; 
      this->Name = L"Form1"; 
      this->Text = L"Form1"; 
      this->Load += gcnew EventHandler(this, &Form1::Form1_Load); 
      this->MouseDown += gcnew System::Windows::Forms::MouseEventHandler(this, &Form1::Form1_MouseDown); 
      this->ResumeLayout(false); 

     } 
#pragma endregion 
    private: System::Void Form1_Load(Object^ sender, EventArgs^ e) { 
        hWnd = static_cast<HWND>(Handle.ToPointer()); 
       } 

    private: System::Void Form1_MouseDown(Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { 
        if (e->Button == System::Windows::Forms::MouseButtons::Left) { 
         ::ReleaseCapture(); 
         ::SendMessage(hWnd, /*WM_NCLBUTTONDOWN*/ 0xA1, /*HT_CAPTION*/ 0x2, 0); 
        } 
       } 

    }; 
} 
Verwandte Themen