Czy istnieje sposób, aby formularz, który nie ma obramowania (FormBorderStyle jest ustawiony na „brak”), byłby ruchomy po kliknięciu myszą na formularzu, tak jakby istniała ramka?
Czy istnieje sposób, aby formularz, który nie ma obramowania (FormBorderStyle jest ustawiony na „brak”), byłby ruchomy po kliknięciu myszą na formularzu, tak jakby istniała ramka?
Odpowiedzi:
W tym artykule na CodeProject opisano szczegółowo technikę. Zasadniczo sprowadza się do:
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);
}
}
Zasadniczo robi to dokładnie to samo, co chwytanie paska tytułu okna, z punktu widzenia menedżera okien.
Form1_MouseDown
nie jest przypisany do rzeczywistego MouseDown
zdarzenia Form1
.
this.MouseDown += ...
do Main()
funkcji formularza
Nie róbmy rzeczy trudniejszych niż to konieczne. Natknąłem się na tak wiele fragmentów kodu, które pozwalają przeciągać formularz (lub inną kontrolkę). Wiele z nich ma swoje wady / skutki uboczne. Szczególnie te, w których oszukują system Windows, aby pomyślał, że kontrolka w formularzu jest rzeczywistą formą.
Biorąc to pod uwagę, oto mój fragment. Używam go cały czas. Chciałbym również zauważyć, że nie powinieneś używać this.Invalidate (); jak lubią to robić inni, ponieważ w niektórych przypadkach powoduje to migotanie formularza. A w niektórych przypadkach tak się dzieje. Używając this.Update, nie miałem żadnych problemów z migotaniem:
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;
}
Kolejny prostszy sposób na zrobienie tego samego.
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;
}
użyj MouseDown, MouseMove i MouseUp. Możesz ustawić w tym celu flagę zmiennej. Mam próbkę, ale myślę, że musisz powtórzyć.
Koduję działanie myszy do panelu. Po kliknięciu panelu formularz przesunie się wraz z nim.
//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);
}
}
Tylko WPF
nie mam pod ręką dokładnego kodu, ale myślę, że w ostatnim projekcie użyłem zdarzenia MouseDown i po prostu umieściłem to:
frmBorderless.DragMove();
Jest to sprawdzone i łatwe do zrozumienia.
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
w przebraniu.
Nie ma właściwości, które można odwrócić, aby stało się to magicznie. Spójrz na zdarzenia dla formularza i wdrożenie tego przez ustawienie this.Top
i this.Left
. W szczególności warto przyjrzeć się MouseDown
, MouseUp
i 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;
}
}
to może rozwiązać twój problem ....
Ten fragment kodu z powyższego linku załatwił sprawę w moim przypadku :)
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);
}
}
Najlepszy sposób, jaki znalazłem (oczywiście zmodyfikowany)
// 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; }
}
}
Aby zastosować przeciąganie do kontrolki, po prostu wstaw to po InitializeComponent ()
AddDrag(NameOfControl);
To zadziałało dla mnie.
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);
}
}
W przypadku .NET Framework 4
Możesz użyć this.DragMove()
dla MouseDown
zdarzenia składnika (w tym przykładzie mainLayout), którego używasz do przeciągania.
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
Najłatwiej jest:
Najpierw utwórz etykietę o nazwie label1. Przejdź do zdarzeń label1> zdarzenia myszy> Label1_Mouse Move i napisz te:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
Próbowałem zrobić ruchomy formularz okna bez obramowania, który zawiera kontrolkę hosta elementu WPF i kontrolkę użytkownika WPF.
Skończyło się na panelu stosu o nazwie StackPanel w mojej kontrolce użytkownika WPF, który wydawał się logiczną rzeczą, aby spróbować kliknąć, aby przenieść. Wypróbowanie kodu junmats działało, gdy poruszałem myszą powoli, ale jeśli poruszałem myszą szybciej, mysz odsuwałaby się od formularza, a forma utknęłaby gdzieś w połowie ruchu.
To poprawiło jego odpowiedź dla mojej sytuacji przy użyciu CaptureMouse i ReleaseCaptureMouse, a teraz mysz nie odsuwa się od formularza podczas przenoszenia go, nawet jeśli poruszam się szybko.
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);
Ponieważ niektóre odpowiedzi nie pozwalają na przeciąganie kontrolek podrzędnych, stworzyłem małą klasę pomocniczą. Należy przejść formularz najwyższego poziomu. W razie potrzeby można uczynić bardziej ogólnym.
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);
}
}
}
Jeśli chcesz skorzystać z DoubleClick i powiększyć / pomniejszyć swój formularz, możesz użyć pierwszej odpowiedzi, utworzyć globalną zmienną int i dodać 1 za każdym razem, gdy użytkownik kliknie komponent, którego używasz do przeciągania. Jeśli variable == 2
więc powiększ / pomniejsz swoją formę. Użyj również timera co pół sekundy lub sekundy, aby zrobić variable = 0
;
Dodanie programu MouseLeftButtonDown
obsługi zdarzeń do MainWindow zadziałało dla mnie.
W funkcji zdarzenia, która jest generowana automatycznie, dodaj poniższy kod:
base.OnMouseLeftButtonDown(e);
this.DragMove();
Rozszerzam rozwiązanie z jay_t55 o jeszcze jedną metodę, ToolStrip1_MouseLeave
która obsługuje zdarzenie, w którym mysz porusza się szybko i opuszcza region.
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;
}
Wypróbowałem następujące i presto changeo, moje przezroczyste okno nie było już zamarznięte, ale można je było przesunąć !! (odrzuć wszystkie inne złożone rozwiązania powyżej ...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
Formularz 1(): new Moveable(control1, control2, control3);
Klasa:
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);
}