Eine randlose Form beweglich machen?


108

Gibt es eine Möglichkeit, ein Formular ohne Rahmen (FormBorderStyle ist auf "Keine" gesetzt) ​​beweglich zu machen, wenn Sie mit der Maus auf das Formular klicken, als ob es einen Rand gäbe?

Antworten:


251

Dieser Artikel über CodeProject beschreibt eine Technik. Im Grunde läuft es darauf hinaus:

public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();

private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{     
    if (e.Button == MouseButtons.Left)
    {
        ReleaseCapture();
        SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
    }
}

Dies gilt im Wesentlichen genau die gleiche wie die Titelleiste eines Fensters greifen, aus der Sicht des Window - Manager.


Das funktioniert bei mir überhaupt nicht. Der Code läuft einwandfrei, alles ist korrekt und mein Fenster sitzt immer noch da. Irgendwelche Ideen?
Dbrree

8
@dbrree Sie haben wahrscheinlich den Code kopiert, der nicht funktioniert, da er Form1_MouseDownnicht dem tatsächlichen MouseDownEreignis von zugewiesen ist Form1.
Remon Ramy

2
Wenn Sie eine Beschriftung oder ein Symbol (oder andere Vordergrundobjekte!) Haben, in die Sie das zu ziehende Formular greifen, fügen Sie diesen Elementen ebenfalls ein Mousedown-Ereignis hinzu. Formularereignisse können nicht durch Formularobjekte sehen.
Paul Nelson

1
Sie müssen this.MouseDown += ...die Main()Funktion für das Formular hinzufügen
Richard Peck

1
Hat wie ein Zauber für mich funktioniert !!!! Ich musste die Ereignisbehandlung auf das Panel verschieben, das ich anstelle des Formulars platzierte, aber es funktionierte
Justin

54

Machen wir die Dinge nicht schwieriger als nötig. Ich bin auf so viele Codeausschnitte gestoßen, mit denen Sie ein Formular (oder ein anderes Steuerelement) verschieben können. Und viele von ihnen haben ihre eigenen Nachteile / Nebenwirkungen. Insbesondere diejenigen, bei denen Windows zu der Annahme verleitet wird, dass ein Steuerelement in einem Formular das eigentliche Formular ist.

Davon abgesehen ist hier mein Ausschnitt. Ich benutze es die ganze Zeit. Ich möchte auch darauf hinweisen, dass Sie dies nicht verwenden sollten.Invalidate (); wie andere es gerne tun, weil es in einigen Fällen dazu führt, dass die Form flackert. Und in einigen Fällen auch. Aktualisieren. Mit this.Update hatte ich keine flackernden Probleme:

private bool mouseDown;
private Point lastLocation;

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        mouseDown = true;
        lastLocation = e.Location;
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if(mouseDown)
        {
            this.Location = new Point(
                (this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);

            this.Update();
        }
    }

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

1
dang winforms ... habe fast zwei Stunden nach dieser Antwort gesucht ... ich bin neu bei c #, aber du hast mir Wunder getan!
PrinceOfRavens

Genau so dachte ich, mein einziges Problem war, dass es verdammt fehlerhaft war, bis ich las, wie du es gemacht hast. Danke Kumpel
EasyBB

Dieser hat für mich besser funktioniert als der erstaunliche winzige Ausschnitt über den Overrides WndProc. Wohlgemerkt, der WndProc hat funktioniert ... er hat nur andere Dinge daran gehindert zu funktionieren. Vielen Dank!
Mmm

Wahrscheinlich die beste Option hier, da es gut funktioniert und nicht auf WndProc basiert (kann mit Mono problemlos auf andere Plattformen portiert werden). Kann verbessert werden, indem der Zustand auf maximiert / normal
geändert wird,

Es funktioniert nicht mit Mono, hat .net 4.5.2 in Mono / Net 4.5 geändert und funktioniert immer noch nicht. Ich versuche jetzt eine Lösung zu finden.
Roger Deep

35

Ein weiterer einfacher Weg, um das Gleiche zu tun.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        // set this.FormBorderStyle to None here if needed
        // if set to none, make sure you have a way to close the form!
    }
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_NCHITTEST)
            m.Result = (IntPtr)(HT_CAPTION);
    }

    private const int WM_NCHITTEST = 0x84;
    private const int HT_CLIENT = 0x1;
    private const int HT_CAPTION = 0x2;
}

1
Jeder, der es möglich macht, dass Sie das Formular verschieben können, indem Sie ein bestimmtes Werkzeug (z. B. ein Etikett) halten.
Thomas W

2
Wenn Sie darauf doppelklicken, wird das Formular maximiert. Lesen Sie auch hier und da, dass dies das Klicken mit der rechten Maustaste bricht.
Sebastiano

19

Verwenden Sie MouseDown, MouseMove und MouseUp. Sie können dafür ein Variablenflag setzen. Ich habe ein Beispiel, aber ich denke, Sie müssen es überarbeiten.

Ich codiere die Mausaktion in ein Panel. Sobald Sie auf das Bedienfeld klicken, wird Ihr Formular mit verschoben.

//Global variables;
private bool _dragging = false;
private Point _offset;
private Point _start_point=new Point(0,0);


private void panel1_MouseDown(object sender, MouseEventArgs e)
{
   _dragging = true;  // _dragging is your variable flag
   _start_point = new Point(e.X, e.Y);
}

private void panel1_MouseUp(object sender, MouseEventArgs e)
{
   _dragging = false; 
}

private void panel1_MouseMove(object sender, MouseEventArgs e)
{
  if(_dragging)
  {
     Point p = PointToScreen(e.Location);
     Location = new Point(p.X - this._start_point.X,p.Y - this._start_point.Y);     
  }
}

Es ist. Wie bereits an anderer Stelle erwähnt, hängt dies davon ab, dass das Formular weiterhin MouseMove-Ereignisse generiert. Angenommen, Sie stufen das Formular in der obersten Pixelzeile ein und ziehen es nach oben. Es wird nichts passieren, obwohl das Formular herumspringt, sobald Sie die Maus wieder darauf bewegen.
Joey

12

Nur WPF


Ich habe nicht den genauen Code zur Hand, aber in einem kürzlich durchgeführten Projekt habe ich das MouseDown-Ereignis verwendet und einfach Folgendes ausgedrückt:

frmBorderless.DragMove();

Window.DragMove-Methode (MSDN)


2
Das ist allerdings WPF. Ok, das OP hat dies nicht genau spezifiziert.
Joey

Ja, das habe ich über das Projekt vergessen, das ich gemacht habe. Ich habe mir nur Formulare angesehen und es ist nicht verfügbar. Es tut uns leid!
Chris

3
@ Chris Das hat bei mir in einem WPF-Projekt funktioniert. Vielen Dank, dass Sie die Antwort nicht gelöscht haben.
Rembunator

7

Ref. Video-Link

Dies ist getestet und leicht zu verstehen.

protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case 0x84:
            base.WndProc(ref m);
            if((int)m.Result == 0x1)
                m.Result = (IntPtr)0x2;
            return;
    }

    base.WndProc(ref m);
}

6
Dieser Code funktioniert, aber wie ist es leicht zu verstehen? Ich weiß nichts in diesem Codesegment außer der switch-Anweisung!
Jamshaid Kamran

Dies ist WM_NCHITTESTin Verkleidung.
Andreas Rejbrand

4

Es gibt keine Eigenschaft, die Sie umdrehen können, um dies einfach magisch geschehen zu lassen. Schauen Sie sich die Ereignisse für das Formular an und es wird ziemlich trivial, dies durch Setzen von this.Topund zu implementieren this.Left. Insbesondere möchten Sie sich ansehen MouseDown, MouseUpund MouseMove.


Ich dachte, ich müsste diese Ereignisse nutzen, bin mir aber nicht sicher, was ich damit anfangen soll. Wie kann ich das Formular verschieben, wenn das MouseDown-Ereignis aufgerufen wird?
Benutzer

1
Mit der Maus nach unten setzen Sie ein Flag und speichern die Basiskoordinaten. Beim Bewegen der Maus - wenn das Flag gesetzt ist - passen Sie den oberen und linken Rand um den Versatz der neuen Mauskoordinaten an. Mit der Maus nach oben löschen Sie die Flagge.
Murph

Trotzdem können Sie dies mit der Windows-API ziemlich einfach tun, was nicht davon abhängt, dass immer noch Mausereignisse abgerufen werden. Diese Methode schlägt fehl, wenn Sie ein Pixel am oberen Rand des Formulars greifen und beispielsweise nach oben ziehen.
Joey

4
public Point mouseLocation;
private void frmInstallDevice_MouseDown(object sender, MouseEventArgs e)
{
  mouseLocation = new Point(-e.X, -e.Y);
}

private void frmInstallDevice_MouseMove(object sender, MouseEventArgs e)
{
  if (e.Button == MouseButtons.Left)
  {
    Point mousePos = Control.MousePosition;
    mousePos.Offset(mouseLocation.X, mouseLocation.Y);
    Location = mousePos;
  }
}

Dies kann Ihr Problem lösen ....


Sie können auch "e.Location" anstelle von Control.MousePosition
Reza Taibur


4

Der beste Weg, den ich gefunden habe (natürlich modifiziert)

// This adds the event handler for the control
private void AddDrag(Control Control) { Control.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DragForm_MouseDown); }
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();

private void DragForm_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        ReleaseCapture();
        SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
        // Checks if Y = 0, if so maximize the form
        if (this.Location.Y == 0) { this.WindowState = FormWindowState.Maximized; }
    }
}

Um Drag auf ein Steuerelement anzuwenden, fügen Sie dies einfach nach InitializeComponent () ein.

AddDrag(NameOfControl);

4

Es hat bei mir funktioniert.

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        _mouseLoc = e.Location;
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            int dx = e.Location.X - _mouseLoc.X;
            int dy = e.Location.Y - _mouseLoc.Y;
            this.Location = new Point(this.Location.X + dx, this.Location.Y + dy);
        }
    }

Willkommen bei Stack Overflow - Tour , bitte überprüfen Sie, wie zu antworten ist . Sie müssen eine Erklärung geben, wie dieser Code das Problem des OP "Originalplakats" löst. Es wäre hilfreicher für alle, die Ihre Antwort überprüfen.
Mauricio Arias Olave

2

Für .NET Framework 4

Sie können this.DragMove()für das MouseDownEreignis der Komponente (in diesem Beispiel mainLayout) verwenden, die Sie zum Ziehen verwenden.

private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
    this.DragMove();
}

2

Der einfachste Weg ist:

Erstellen Sie zunächst ein Label mit dem Namen label1. Gehen Sie zu den Ereignissen von label1> Mausereignisse> Label1_Mouse Verschieben und schreiben Sie diese:

if (e.Button == MouseButtons.Left){
    Left += e.X;
    Top += e.Y;`
}

2

Ich habe versucht, ein randloses Fensterformular beweglich zu machen, das ein WPF-Element-Host-Steuerelement und ein WPF-Benutzersteuerelement enthielt.

Am Ende hatte ich ein Stack-Panel namens StackPanel in meinem WPF-Benutzersteuerelement, das logisch zu versuchen schien, auf zu klicken, um es zu verschieben. Der Versuch, den Code von junmats zu verwenden, funktionierte, wenn ich die Maus langsam bewegte. Wenn ich die Maus jedoch schneller bewegte, bewegte sich die Maus vom Formular weg und das Formular blieb irgendwo in der Mitte der Bewegung hängen.

Dies verbesserte seine Antwort auf meine Situation mit CaptureMouse und ReleaseCaptureMouse, und jetzt bewegt sich die Maus nicht mehr vom Formular weg, während sie es bewegt, selbst wenn ich es schnell bewege.

private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
{
    _start_point = e.GetPosition(this);
    StackPanel.CaptureMouse();
}

private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
    StackPanel.ReleaseMouseCapture();
}

private void StackPanel_MouseMove(object sender, MouseEventArgs e)
{
    if (StackPanel.IsMouseCaptured)
    {
        var p = _form.GetMousePositionWindowsForms();
        _form.Location = new System.Drawing.Point((int)(p.X - this._start_point.X), (int)(p.Y - this._start_point.Y));
    }
}

    //Global variables;
    private Point _start_point = new Point(0, 0);

2

Da bei einigen Antworten untergeordnete Steuerelemente nicht ziehbar sind, habe ich eine kleine Hilfsklasse erstellt. Es sollte das oberste Formular übergeben werden. Kann auf Wunsch allgemeiner gestaltet werden.

class MouseDragger
{
    private readonly Form _form;
    private Point _mouseDown;

    protected void OnMouseDown(object sender, MouseEventArgs e)
    {
        _mouseDown = e.Location;
    }

    protected void OnMouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            int dx = e.Location.X - _mouseDown.X;
            int dy = e.Location.Y - _mouseDown.Y;
            _form.Location = new Point(_form.Location.X + dx, _form.Location.Y + dy);
        }
    }
    public MouseDragger(Form form)
    {
        _form = form;

        MakeDraggable(_form);            
    }

    private void MakeDraggable(Control control)
    {
        var type = control.GetType();
        if (typeof(Button).IsAssignableFrom(type))
        {
            return;
        }

        control.MouseDown += OnMouseDown;
        control.MouseMove += OnMouseMove;

        foreach (Control child in control.Controls)
        {
            MakeDraggable(child);
        }
    }
}

1

Wenn Sie doppelklicken und Ihr Formular vergrößern / verkleinern müssen, können Sie die erste Antwort verwenden, eine globale int-Variable erstellen und jedes Mal 1 hinzufügen, wenn der Benutzer auf die Komponente klickt, die Sie zum Ziehen verwenden. Wenn variable == 2ja, machen Sie Ihr Formular größer / kleiner. Verwenden Sie auch einen Timer für jede halbe Sekunde oder Sekunde, um Ihre variable = 0;


1

Das Hinzufügen eines MouseLeftButtonDownEreignishandlers zum MainWindow hat für mich funktioniert.

Fügen Sie in der Ereignisfunktion, die automatisch generiert wird, den folgenden Code hinzu:

base.OnMouseLeftButtonDown(e);
this.DragMove();

1

Ich erweitere die Lösung von jay_t55 um eine weitere Methode ToolStrip1_MouseLeave, die das Ereignis behandelt, dass sich die Maus schnell bewegt und die Region verlässt.

private bool mouseDown;
private Point lastLocation;

private void ToolStrip1_MouseDown(object sender, MouseEventArgs e) {
    mouseDown = true;
    lastLocation = e.Location;
}

private void ToolStrip1_MouseMove(object sender, MouseEventArgs e) {
    if (mouseDown) {
        this.Location = new Point(
            (this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);

        this.Update();
    }
}

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

private void ToolStrip1_MouseLeave(object sender, EventArgs e) {
    mouseDown = false;
}

0

Ich habe folgendes versucht und Presto Changeo, mein transparentes Fenster war nicht mehr eingefroren, sondern konnte verschoben werden !! (werfen Sie all diese anderen komplexen Lösungen oben weg ...)

   private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        // Begin dragging the window
        this.DragMove();
    }

Diese Antwort ist für WPF, die Frage bezieht sich auf WinForms.
Ray

0

Form 1(): new Moveable(control1, control2, control3);

Klasse:

using System;
using System.Windows.Forms;

class Moveable
{
    public const int WM_NCLBUTTONDOWN = 0xA1;
    public const int HT_CAPTION = 0x2;
    [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
    [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
    public static extern bool ReleaseCapture();
    public Moveable(params Control[] controls)
    {
        foreach (var ctrl in controls)
        {
            ctrl.MouseDown += (s, e) =>
            {
                if (e.Button == MouseButtons.Left)
                {
                    ReleaseCapture();
                    SendMessage(ctrl.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
                    // Checks if Y = 0, if so maximize the form
                    if (ctrl.FindForm().Location.Y == 0) { ctrl.FindForm().WindowState = FormWindowState.Maximized; }
                }
            };
        }
    }
}

0
   [DllImport("user32.DLL", EntryPoint = "ReleaseCapture")]
    private extern static void ReleaseCapture();

    [DllImport("user32.DLL", EntryPoint = "SendMessage")]
    private extern static void SendMessage(System.IntPtr hWnd, int Msg, int wParam, int lParam);
    private void panelTitleBar_MouseDown(object sender, MouseEventArgs e)
    {
        ReleaseCapture();
        SendMessage(this.Handle, 0x112, 0xf012, 0);
    }

Es wird schön sein, wenn Sie Ihre Antwort mit einigen Erklärungen unterstützen :)
Mustafamg
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.