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?
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.
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;
}
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;
}
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);
}
}
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();
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);
}
WM_NCHITTEST
déguisé.
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.Top
et this.Left
. Plus précisément, vous voudrez regarder MouseDown
, MouseUp
et MouseMove
.
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 ...
Ce morceau de code du lien ci-dessus a fait l'affaire dans mon cas :)
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
this.Capture = false;
Message msg = Message.Create(this.Handle, 0XA1, new IntPtr(2), IntPtr.Zero);
this.WndProc(ref msg);
}
}
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);
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);
}
}
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();
}
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;`
}
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);
É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);
}
}
}
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 == 2
alors agrandissez / réduisez votre formulaire. Utilisez également une minuterie toutes les demi-secondes ou toutes les secondes pour créer votre variable = 0
;
L'ajout d'un MouseLeftButtonDown
gestionnaire 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();
J'étends la solution de jay_t55 avec une autre méthode ToolStrip1_MouseLeave
qui 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;
}
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();
}
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; }
}
};
}
}
}
[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);
}
Form1_MouseDown
n'est pas affecté à l'MouseDown
événement réel deForm1
.this.MouseDown += ...
à laMain()
fonction pour le formulaire