2008-08-27 3 views
18

Je crée un petit formulaire modal utilisé dans l'application Winforms. C'est essentiellement une barre de progression. Mais j'aimerais que l'utilisateur puisse cliquer n'importe où dans le formulaire et le faire glisser pour le déplacer sur le bureau pendant qu'il est encore affiché.Winforms - Cliquez/faites glisser n'importe où dans le formulaire pour le déplacer comme si vous aviez cliqué dans le formulaire.

Comment puis-je implémenter ce comportement?

Répondre

23

Microsoft KB Article 320687 a une réponse détaillée à cette question. Fondamentalement, vous substituez la méthode WndProc pour renvoyer HTCAPTION au message WM_NCHITTEST lorsque le point testé est dans la zone client du formulaire, ce qui indique en fait à Windows de traiter le clic exactement comme si cela s'était passé sur la légende du formulaire.

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

Cela rend le menu contextuel disponible. –

+0

Cela fonctionne, mais si l'écran de démarrage a des contrôles (disons une étiquette), cliquer sur l'étiquette ne le déplace pas. Comment gérer cela spécialement si le splash a plusieurs contrôles? – supafly

3

Le code suivant suppose que la forme de ProgressBarForm a un contrôle ProgressBar avec Dock propriété située à Remplissez

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

Voici une façon de le faire en utilisant un P/Invoke.

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

Vous devez avoir: using System.Runtime.InteropServices; pour que [DllImport()] fonctionne. –

+1

Dans mon projet, j'ai utilisé un code similaire à celui de Timothy Fries, mais j'aime celui-ci parce que vous pouvez utiliser exactement la même technique pour rendre le formulaire dragable par ses contrôles, comme les étiquettes. L'autre technique rend le formulaire dragable, mais si vous cliquez sur les étiquettes, il ne fera pas glisser. – flamey

+0

Ceci est également plus agréable car il vous permet de gérer les événements de clic droit (pour les menus contextuels). Vous pouvez également utiliser sélectivement les clics gauche comme indiqué ci-dessus, ou utiliser le clic droit/moyen au lieu des clics gauche. Globalement beaucoup plus flexible. – coderforlife

0

La réponse acceptée est un truc cool, mais il ne fonctionne pas toujours si le formulaire est couvert par un contrôle enfant à quai Fill comme un groupe spécial (ou dérivés), par exemple, parce que ce contrôle va manger tous la plupart des messages Windows.

Voici une approche simple qui fonctionne dans ce cas aussi: tirer le contrôle en question (utiliser cette classe au lieu de la norme) un message de souris poignée comme ceci:

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

VC++ 2010 Version (de FlySwat de):

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

    }; 
} 
Questions connexes