Winforms – Klicken/ziehen Sie an eine beliebige Stelle im Formular, um es zu verschieben, als ob Sie in der Formularbeschriftung darauf klicken würden

StackOverflow https://stackoverflow.com/questions/30184

  •  09-06-2019
  •  | 
  •  

Frage

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 irgendwo im Formular klicken und es ziehen kann, um es auf dem Desktop zu verschieben, während es noch angezeigt wird.

Wie kann ich dieses Verhalten umsetzen?

War es hilfreich?

Lösung

Microsoft KB-Artikel 320687 hat eine ausführliche Antwort auf diese Frage.

Grundsätzlich überschreiben Sie die WndProc-Methode, um HTCAPTION an die WM_NCHITTEST-Nachricht zurückzugeben, wenn sich der getestete Punkt im Clientbereich des Formulars befindet – was Windows im Endeffekt anweist, den Klick genau so zu behandeln, als ob er stattgefunden hätte die Überschrift des Formulars.

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

Andere Tipps

Hier ist eine Möglichkeit, dies 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);
    }
}

Der folgende Code geht davon aus, dass das ProgressBarForm-Formular über ein ProgressBar-Steuerelement verfügt Dock Eigenschaft festgelegt 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;
    }
}

Die akzeptierte Antwort ist ein cooler Trick, der jedoch nicht immer funktioniert, wenn das Formular von einem untergeordneten Steuerelement mit angedockter Füllung wie beispielsweise einem Panel (oder Derivaten) abgedeckt wird, da dieses Steuerelement die meisten Windows-Meldungen verarbeitet.

Hier ist ein einfacher Ansatz, der auch in diesem Fall funktioniert:Leiten Sie das betreffende Steuerelement ab (verwenden Sie diese Klasse anstelle der Standardklasse) und verarbeiten Sie Mausmeldungen wie folgt:

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

VC++ 2010-Version (von FlySwat):

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

    };
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top