Rendere mobile una forma senza bordi?


109

Esiste un modo per rendere mobile un modulo che non ha bordo (FormBorderStyle è impostato su "nessuno") quando si fa clic con il mouse sul modulo come se ci fosse un bordo?

Risposte:


252

Questo articolo su CodeProject descrive in dettaglio una tecnica. Fondamentalmente si riduce a:

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

Questo essenzialmente fa esattamente lo stesso che afferrare la barra del titolo di una finestra, dal punto di vista del gestore delle finestre.


Questo non funziona affatto per me. Il codice funziona bene, tutto è corretto e la mia finestra è ancora lì. Qualche idea?
dbrree

8
@dbrree Probabilmente hai copiato il codice, che non funzionerà in quanto Form1_MouseDownnon è assegnato MouseDownall'evento effettivo di Form1.
Remon Ramy

2
Se hai un'etichetta o un'icona (o qualsiasi altro oggetto in primo piano!) Dove stai afferrando il modulo da trascinare, aggiungi un evento mousedown anche a questi elementi. Gli eventi del modulo non possono vedere attraverso gli oggetti del modulo.
Paul Nelson,

1
È necessario aggiungere this.MouseDown += ...alla Main()funzione per il modulo
Richard Peck

1
Ha funzionato benissimo per me!!!! Ho dovuto spostare la gestione dell'evento sul pannello che stavo mettendo al posto del modulo, ma ha funzionato
Justin,

54

Non rendiamo le cose più difficili di quanto dovrebbero essere. Mi sono imbattuto in così tanti frammenti di codice che ti consentono di trascinare un modulo (o un altro controllo). E molti di loro hanno i loro svantaggi / effetti collaterali. Soprattutto quelli in cui inducono Windows a pensare che un controllo su un modulo sia il modulo effettivo.

Detto questo, ecco il mio frammento. Io lo uso per tutto il tempo. Vorrei anche notare che non dovresti usare this.Invalidate (); come ad altri piace fare perché in alcuni casi provoca lo sfarfallio del modulo. E in alcuni casi lo fa anche questo. Utilizzando this.Update, non ho avuto problemi di sfarfallio:

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 ... ho cercato questa risposta per quasi due ore .... sono nuovo in c # però, mi hai fatto miracoli!
PrinceOfRavens

Questo è esattamente il modo in cui pensavo, il mio unico problema era che era pieno di bug fino a quando non ho letto come l'hai fatto. Grazie
amico

Questo ha funzionato meglio per me rispetto al fantastico minuscolo frammento sopra WndProc. Intendiamoci, il WndProc ha funzionato ... ha solo impedito ad altre cose di funzionare. Grazie!
Mmm

Probabilmente l'opzione migliore qui in quanto funziona bene e non si basa su WndProc (può essere facilmente portato su altre piattaforme con Mono). Può essere migliorato cambiando lo stato in massimizzato / normale se Y <10
Sylverdrag

Non funziona su mono, ha cambiato .net 4.5.2 in mono / net 4.5 e ancora non funziona. Sto cercando di trovare una soluzione adesso.
Roger Deep

35

Un altro modo più semplice per fare la stessa cosa.

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
Chiunque ti consente di spostare il modulo tenendo premuto uno strumento specifico (ad esempio un'etichetta).
Thomas W

2
Se si fa doppio clic, il modulo viene ingrandito. Leggi anche qua e là che questo interrompe il clic con il tasto destro.
Sebastiano

19

usa MouseDown, MouseMove e MouseUp. Puoi impostare un flag variabile per questo. Ho un campione, ma penso che tu debba rivedere.

Sto codificando l'azione del mouse su un pannello. Dopo aver fatto clic sul pannello, il modulo si sposterà con esso.

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

È. Come già detto altrove, questo si basa sul modulo che genera ancora eventi MouseMove. In un caso semplice, supponiamo di valutare il modulo nella riga di pixel più in alto e trascinarlo verso l'alto. Non accadrà nulla, anche se il modulo salterà non appena sposti il ​​mouse su di esso.
Joey

12

Solo WPF


non ho il codice esatto a portata di mano, ma in un progetto recente penso di aver usato l'evento MouseDown e semplicemente messo questo:

frmBorderless.DragMove();

Metodo Window.DragMove (MSDN)


2
Questo è WPF, però. Ok, l'OP non lo ha specificato esattamente.
Joey

Sì, che è qualcosa che ho dimenticato del progetto che stavo facendo. Ho appena guardato Moduli e non è disponibile. Scusa!
Chris,

3
@Chris This ha funzionato per me in un progetto WPF. Grazie per non aver cancellato la risposta.
Rembunator

7

Ref. collegamento video

Questo è testato e facile da capire.

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
Questo codice funziona, ma come è facile da capire? Non so nulla in questo segmento di codice oltre all'istruzione switch!
Jamshaid Kamran

Questo è WM_NCHITTESTsotto mentite spoglie.
Andreas Rejbrand

4

Non ci sono proprietà che puoi capovolgere per farlo accadere magicamente. Guarda gli eventi per il modulo e diventa abbastanza banale implementarlo impostando this.Tope this.Left. In particolare ti consigliamo di guardare MouseDown, MouseUpe MouseMove.


Ho pensato che avrei dovuto usare quegli eventi ma non sono sicuro di cosa farne. Quando viene chiamato l'evento MouseDown, come consento lo spostamento del form?
utente

1
Con il mouse si imposta una bandiera e si memorizzano le coordinate di base. Al movimento del mouse, se la bandiera è impostata, si regola la parte superiore e sinistra dell'offset delle nuove coordinate del mouse. Alzando il mouse si cancella la bandiera.
Murph

Tuttavia, puoi farlo con l'API di Windows abbastanza facilmente, il che non dipende dal continuare a ricevere gli eventi del mouse. Questo metodo non riesce se, ad esempio, afferri un pixel all'estremità superiore del modulo e trascini verso l'alto.
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;
  }
}

questo può risolvere il tuo problema ....


Puoi anche usare "e.Location" invece di Control.MousePosition
Reza Taibur


4

Il modo migliore che ho trovato (modificato ovviamente)

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

Per applicare il trascinamento a un controllo è sufficiente inserirlo dopo InitializeComponent ()

AddDrag(NameOfControl);

4

Ha funzionato per me.

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

Benvenuto in Stack Overflow - tour , controlla Come rispondere . Devi fornire una spiegazione su come questo codice risolve il problema del "poster originale" dell'OP. Sarebbe più utile per chiunque controlli la tua risposta.
Mauricio Arias Olave

2

Per .NET Framework 4,

Puoi usare this.DragMove()per l' MouseDownevento del componente (mainLayout in questo esempio) che stai usando per trascinare.

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

2

Il modo più semplice è:

Per prima cosa crea un'etichetta denominata label1. Vai agli eventi di label1> eventi del mouse> Label1_Mouse Move e scrivi questi:

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

2

Stavo cercando di rendere mobile una finestra senza bordi che conteneva un controllo WPF Element Host e un controllo WPF User.

Ho finito con un pannello dello stack chiamato StackPanel nel mio controllo utente WPF che sembrava la cosa logica su cui provare a fare clic per spostarmi. Il codice di Junmats ha funzionato quando ho spostato il mouse lentamente, ma se ho spostato il mouse più velocemente, il mouse si spostava fuori dal modulo e il modulo sarebbe rimasto bloccato da qualche parte a metà movimento.

Questo ha migliorato la sua risposta per la mia situazione usando CaptureMouse e ReleaseCaptureMouse e ora il mouse non si sposta dal modulo mentre lo sposta anche se lo sposto rapidamente.

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

Poiché alcune risposte non consentono di trascinare i controlli figlio, ho creato una piccola classe di supporto. Dovrebbe essere passato il modulo di primo livello. Può essere reso più generico se lo si desidera.

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

Inoltre, se hai bisogno di DoubleClick e rendere il tuo modulo più grande / più piccolo, puoi utilizzare la prima risposta, creare una variabile globale int, aggiungere 1 ogni volta che l'utente fa clic sul componente che utilizzi per il trascinamento. Se variable == 2poi rendi il tuo modulo più grande / più piccolo. Usa anche un timer ogni mezzo secondo o un secondo per fare il tuo variable = 0;


1

L'aggiunta di un MouseLeftButtonDowngestore di eventi alla MainWindow ha funzionato per me.

Nella funzione evento che viene generata automaticamente, aggiungi il codice seguente:

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

1

Sto espandendo la soluzione da jay_t55 con un altro metodo ToolStrip1_MouseLeaveche gestisce l'evento in cui il mouse si sposta rapidamente e lascia la regione.

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

Ho provato quanto segue e presto changeo, la mia finestra trasparente non era più bloccata ma poteva essere spostata !! (butta via tutte quelle altre soluzioni complesse sopra ...)

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

Questa risposta è per WPF, la domanda riguarda WinForms.
Ray

0

Form1 (): new Moveable(control1, control2, control3);

Classe:

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

Sarà bello se
sostieni la
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.