Rendre un formulaire sans bordure mobile?


109

Existe-t-il un moyen de rendre un formulaire qui n'a pas de bordure (FormBorderStyle est défini sur "aucun") déplaçable lorsque la souris est cliquée sur le formulaire comme s'il y avait une bordure?

Réponses:


252

Cet article sur CodeProject détaille une technique. Cela se résume essentiellement à:

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

Cela fait essentiellement exactement la même chose que saisissant la barre de titre d'une fenêtre, du point de vue du gestionnaire de fenêtres.


Cela ne fonctionne pas du tout pour moi. Le code fonctionne très bien, tout est correct et ma fenêtre est toujours là. Des idées?
dbrree le

8
@dbrree Vous avez probablement copié le code, cela ne fonctionnera pas car il Form1_MouseDownn'est pas affecté à l' MouseDownévénement réel de Form1.
Remon Ramy

2
Si vous avez une étiquette ou une icône (ou tout autre objet de premier plan!) Où vous saisissez le formulaire à faire glisser, ajoutez également un événement mousedown à ces éléments. Les événements de formulaire ne peuvent pas voir à travers les objets de formulaire.
Paul Nelson

1
Vous devez ajouter this.MouseDown += ...à la Main()fonction pour le formulaire
Richard Peck

1
A fonctionné à merveille pour moi!!!! J'ai dû déplacer la gestion des événements vers le panneau que je mettais à la place du formulaire, mais cela a fonctionné
Justin

54

Ne rendons pas les choses plus difficiles qu'elles ne devraient l'être. J'ai rencontré tellement d'extraits de code qui vous permettent de faire glisser un formulaire (ou un autre contrôle). Et beaucoup d'entre eux ont leurs propres inconvénients / effets secondaires. Surtout ceux où ils font croire à Windows qu'un contrôle sur un formulaire est le formulaire réel.

Cela étant dit, voici mon extrait. Je l'utilise tout le temps. Je voudrais également noter que vous ne devriez pas utiliser this.Invalidate (); comme d'autres aiment le faire car cela fait scintiller le formulaire dans certains cas. Et dans certains cas, il en va de même. En utilisant this.Update, je n'ai eu aucun problème de scintillement:

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 ... a cherché cette réponse pendant près de deux heures .... im nouveau à c # cependant, vous m'avez fait des merveilles!
PrinceOfRavens

C'est exactement la façon dont je pensais, mon seul problème était que c'était un buggy comme tout l'enfer jusqu'à ce que je lis comment vous l'avez fait. Merci mate
EasyBB

Celui-ci fonctionnait mieux pour moi que l'incroyable petit extrait de code au-dessus des remplacements WndProc. Remarquez que le WndProc a fonctionné ... il a simplement empêché d'autres choses de fonctionner. Merci!
Mmm

Probablement la meilleure option ici car cela fonctionne bien et ne repose pas sur WndProc (peut facilement être porté sur d'autres plates-formes avec Mono). Peut être amélioré en changeant l'état en maximisé / normal si Y <10
Sylverdrag

Il ne fonctionne pas en mono, a changé .net 4.5.2 en mono / net 4.5 et ne fonctionne toujours pas. Essayer de trouver une solution maintenant.
Roger Deep

35

Une autre façon plus simple de faire la même chose.

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
N'importe qui de rendre possible que vous puissiez déplacer le formulaire en tenant un outil spécifique (par exemple une étiquette).
Thomas W

2
Si vous double-cliquez, le formulaire est agrandi. Lisez également ici et là que cela casse le clic droit.
Sebastiano

19

utilisez MouseDown, MouseMove et MouseUp. Vous pouvez définir un indicateur de variable pour cela. J'ai un échantillon, mais je pense que vous devez le réviser.

Je codifie l'action de la souris sur un panneau. Une fois que vous avez cliqué sur le panneau, votre formulaire se déplacera avec lui.

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

C'est. Comme déjà dit ailleurs, cela repose sur la forme générant toujours des événements MouseMove. En guise de cas simple, supposons que vous classiez le formulaire sur la ligne de pixels la plus haute et que vous le tiriez vers le haut. Rien ne se passera, bien que le formulaire saute autour dès que vous déplacez la souris dessus.
Joey

12

WPF uniquement


Je n'ai pas le code exact sous la main, mais dans un projet récent, je pense que j'ai utilisé l'événement MouseDown et j'ai simplement mis ceci:

frmBorderless.DragMove();

Window.DragMove, méthode (MSDN)


2
C'est WPF, cependant. Ok, l'OP ne l'a pas exactement spécifié.
Joey

Ouais, c'est quelque chose que j'ai oublié du projet que je faisais. Je viens de regarder Forms et ce n'est pas disponible. Désolé!
Chris

3
@Chris Cela a fonctionné pour moi dans un projet WPF. Merci de ne pas avoir supprimé la réponse.
Rembunator

7

Réf. lien vidéo

Ceci est testé et facile à comprendre.

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
Ce code fonctionne, mais comment est-il facile à comprendre? Je ne sais rien de ce segment de code à part l'instruction switch!
Jamshaid Kamran

C'est WM_NCHITTESTdéguisé.
Andreas Rejbrand le

4

Il n'y a aucune propriété que vous pouvez retourner pour que cela se produise comme par magie. Regardez les événements du formulaire et il devient assez simple de l'implémenter en définissant this.Topet this.Left. Plus précisément, vous voudrez regarder MouseDown, MouseUpet MouseMove.


J'ai pensé que je devrais utiliser ces événements, mais je ne sais pas quoi en faire. Lorsque l'événement MouseDown est appelé, comment autoriser le déplacement du formulaire?
utilisateur

1
En descendant la souris, vous définissez un drapeau et stockez les coordonnées de base. Lors du déplacement de la souris - si le drapeau est défini - vous ajustez le haut et la gauche du décalage des nouvelles coordonnées de la souris. Sur la souris, vous effacez le drapeau.
Murph

Néanmoins, vous pouvez le faire avec l'API Windows assez facilement, qui ne dépend pas de l'obtention d'événements de souris. Cette méthode échoue si vous saisissez un pixel tout en haut du formulaire et faites glisser vers le haut, par exemple.
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;
  }
}

cela peut résoudre votre problème ...


Vous pouvez également utiliser "e.Location" au lieu de Control.MousePosition
Reza Taibur


4

Meilleur moyen que j'ai trouvé (modifié bien sûr)

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

Pour appliquer le glissement à un contrôle, insérez simplement ceci après InitializeComponent ()

AddDrag(NameOfControl);

4

Cela a fonctionné pour moi.

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

Bienvenue dans Stack Overflow - visite guidée , veuillez vérifier Comment répondre . Vous devez fournir une explication sur la façon dont ce code résout le problème de l'OP "affiche originale". Ce sera plus utile pour quiconque vérifie votre réponse.
Mauricio Arias Olave

2

Pour .NET Framework 4,

Vous pouvez utiliser this.DragMove()pour l' MouseDownévénement du composant (mainLayout dans cet exemple) que vous utilisez pour faire glisser.

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

2

Le moyen le plus simple est:

Créez d'abord une étiquette nommée label1. Accédez aux événements de label1> événements de souris> Label1_Mouse Move et écrivez-les:

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

2

J'essayais de rendre mobile un formulaire de fenêtres sans bordure contenant un contrôle WPF Element Host et un contrôle WPF User.

Je me suis retrouvé avec un panneau de pile appelé StackPanel dans mon contrôle utilisateur WPF qui semblait la chose logique à essayer de cliquer pour se déplacer. Essayer le code de junmats fonctionnait lorsque je déplaçais lentement la souris, mais si je déplaçais la souris plus rapidement, la souris se déplaçait hors du formulaire et le formulaire serait coincé quelque part au milieu du mouvement.

Cela a amélioré sa réponse à ma situation en utilisant CaptureMouse et ReleaseCaptureMouse et maintenant la souris ne bouge pas du formulaire tout en le déplaçant même si je le déplace rapidement.

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

Étant donné que certaines réponses ne permettent pas aux contrôles enfants d'être déplaçables, j'ai créé une petite classe d'aide. Il devrait être passé le formulaire de niveau supérieur. Peut être rendu plus générique si vous le souhaitez.

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

De plus, si vous avez besoin de DoubleClick et d'agrandir / réduire votre formulaire, vous pouvez utiliser la première réponse, créer une variable int globale, ajouter 1 chaque fois que l'utilisateur clique sur le composant que vous utilisez pour faire glisser. Si variable == 2alors agrandissez / réduisez votre formulaire. Utilisez également une minuterie toutes les demi-secondes ou toutes les secondes pour créer votre variable = 0;


1

L'ajout d'un MouseLeftButtonDowngestionnaire d'événements à MainWindow a fonctionné pour moi.

Dans la fonction d'événement qui est automatiquement générée, ajoutez le code ci-dessous:

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

1

J'étends la solution de jay_t55 avec une autre méthode ToolStrip1_MouseLeavequi gère l'événement de la souris se déplaçant rapidement et quittant la région.

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

J'ai essayé ce qui suit et hop changeo, ma fenêtre transparente n'était plus figée en place mais pouvait être déplacée !! (jetez toutes ces autres solutions complexes ci-dessus ...)

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

Cette réponse est pour WPF, la question concerne WinForms.
Ray

0

Formulaire 1(): 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);
    }

Ce sera bien si vous soutenez votre réponse avec quelques explications :)
Mustafamg
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.