มีวิธีสร้างแบบฟอร์มที่ไม่มีเส้นขอบหรือไม่ (FormBorderStyle ตั้งค่าเป็น "none") สามารถเคลื่อนย้ายได้เมื่อคลิกเมาส์ลงบนแบบฟอร์มเหมือนกับว่ามีเส้นขอบหรือไม่?
มีวิธีสร้างแบบฟอร์มที่ไม่มีเส้นขอบหรือไม่ (FormBorderStyle ตั้งค่าเป็น "none") สามารถเคลื่อนย้ายได้เมื่อคลิกเมาส์ลงบนแบบฟอร์มเหมือนกับว่ามีเส้นขอบหรือไม่?
คำตอบ:
นี้บทความเกี่ยวกับรายละเอียด CodeProject เทคนิค โดยทั่วไปเดือดลงไปที่:
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);
}
}
โดยพื้นฐานแล้วสิ่งนี้จะเหมือนกับการจับแถบหัวเรื่องของหน้าต่างจากมุมมองของตัวจัดการหน้าต่าง
Form1_MouseDown
ไม่ได้รับมอบหมายให้เป็นจริงกรณีที่มีการMouseDown
Form1
this.MouseDown += ...
ไปยังMain()
ฟังก์ชั่นสำหรับแบบฟอร์ม
อย่าทำสิ่งที่ยากเกินความจำเป็น ฉันเจอตัวอย่างโค้ดมากมายที่ให้คุณลากแบบฟอร์มไปรอบ ๆ (หรือ Control แบบอื่น) และหลายคนมีข้อเสีย / ผลข้างเคียง โดยเฉพาะอย่างยิ่งที่พวกเขาหลอกให้ Windows คิดว่า Control on a form เป็นรูปแบบที่แท้จริง
ที่ถูกกล่าวว่านี่คือตัวอย่างของฉัน ฉันจะใช้มันตลอดเวลา. ฉันต้องการทราบด้วยว่าคุณไม่ควรใช้สิ่งนี้.Invalidate (); อย่างที่คนอื่นชอบทำเพราะทำให้ฟอร์มสั่นไหวในบางกรณี และในบางกรณีก็ทำเช่นนี้รีเฟรช ใช้ this.Update ฉันไม่มีปัญหากะพริบใด ๆ :
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;
}
อีกวิธีที่ง่ายกว่าในการทำสิ่งเดียวกัน
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;
}
ใช้ MouseDown, MouseMove และ MouseUp คุณสามารถตั้งค่าสถานะตัวแปรสำหรับสิ่งนั้น ฉันมีตัวอย่าง แต่คิดว่าคุณต้องแก้ไข
ฉันกำลังเข้ารหัสการทำงานของเมาส์ไปยังแผงควบคุม เมื่อคุณคลิกแผงแล้วแบบฟอร์มของคุณจะย้ายไปด้วย
//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 เท่านั้น
ไม่มีรหัสที่แน่นอนในมือ แต่ในโครงการล่าสุดฉันคิดว่าฉันใช้เหตุการณ์ MouseDown และใส่สิ่งนี้:
frmBorderless.DragMove();
สิ่งนี้ผ่านการทดสอบและเข้าใจง่าย
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
ปลอมตัว
ไม่มีทรัพย์สินที่คุณสามารถพลิกเพื่อให้สิ่งนี้เกิดขึ้นได้อย่างน่าอัศจรรย์ ดูเหตุการณ์ที่เกิดขึ้นสำหรับแบบฟอร์มและมันจะกลายเป็นธรรมเล็กน้อยเพื่อดำเนินการนี้โดยการตั้งค่าและthis.Top
this.Left
โดยเฉพาะคุณจะต้องการที่จะมองไปที่MouseDown
, และMouseUp
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;
}
}
สิ่งนี้สามารถแก้ปัญหาของคุณได้ ....
รหัสบิตนี้จากลิงค์ด้านบนทำเคล็ดลับในกรณีของฉัน :)
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);
}
}
วิธีที่ดีที่สุดที่ฉันพบ (แก้ไขแน่นอน)
// 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; }
}
}
หากต้องการใช้การลากกับตัวควบคุมเพียงแค่ใส่สิ่งนี้หลังจาก InitializeComponent ()
AddDrag(NameOfControl);
มันได้ผลสำหรับฉัน
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);
}
}
สำหรับ. NET Framework 4
คุณสามารถใช้this.DragMove()
สำหรับMouseDown
เหตุการณ์ของส่วนประกอบ (mainLayout ในตัวอย่างนี้) ที่คุณใช้ลาก
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
วิธีที่ง่ายที่สุดคือ:
ขั้นแรกให้สร้างป้ายชื่อ label1 ไปที่เหตุการณ์ของ label1> เหตุการณ์เมาส์> Label1_Mouse Move และเขียนสิ่งเหล่านี้:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
ฉันพยายามสร้างหน้าต่างแบบไร้ขอบที่สามารถเคลื่อนย้ายได้ซึ่งมีการควบคุม WPF Element Host และการควบคุมผู้ใช้ WPF
ฉันลงเอยด้วยแผงสแต็กที่เรียกว่า StackPanel ในการควบคุมผู้ใช้ WPF ของฉันซึ่งดูเหมือนจะเป็นเรื่องที่สมเหตุสมผลที่จะลองคลิกเพื่อย้าย การลองใช้โค้ดของ Junmats ใช้งานได้เมื่อฉันเลื่อนเมาส์ช้าๆ แต่ถ้าฉันเลื่อนเมาส์เร็วขึ้นเมาส์จะเคลื่อนออกจากแบบฟอร์มและแบบฟอร์มจะติดค้างอยู่ที่ไหนสักแห่ง
สิ่งนี้ได้รับการปรับปรุงให้ดีขึ้นสำหรับคำตอบของเขาสำหรับสถานการณ์ของฉันโดยใช้ CaptureMouse และ ReleaseCaptureMouse และตอนนี้เมาส์ไม่เคลื่อนออกจากแบบฟอร์มในขณะที่เคลื่อนย้ายแม้ว่าฉันจะย้ายอย่างรวดเร็ว
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);
เนื่องจากคำตอบบางคำไม่อนุญาตให้ลากการควบคุมเด็กได้ฉันจึงได้สร้างคลาสตัวช่วยเล็กน้อย มันควรจะผ่านฟอร์มระดับบน สามารถทำให้เป็นแบบทั่วไปได้มากขึ้นหากต้องการ
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);
}
}
}
นอกจากนี้หากคุณต้องการ DoubleClick และทำให้แบบฟอร์มของคุณใหญ่ขึ้น / เล็กลงคุณสามารถใช้คำตอบแรกสร้างตัวแปร int ส่วนกลางเพิ่ม 1 ทุกครั้งที่ผู้ใช้คลิกที่ส่วนประกอบที่คุณใช้ในการลาก ถ้าอย่างvariable == 2
นั้นทำให้ฟอร์มของคุณใหญ่ขึ้น / เล็กลง ใช้ตัวจับเวลาทุกๆครึ่งวินาทีหรือหนึ่งวินาทีเพื่อให้คุณvariable = 0
;
การเพิ่มMouseLeftButtonDown
ตัวจัดการเหตุการณ์ไปยัง MainWindow ทำงานให้ฉัน
ในฟังก์ชันเหตุการณ์ที่สร้างขึ้นโดยอัตโนมัติให้เพิ่มรหัสด้านล่าง:
base.OnMouseLeftButtonDown(e);
this.DragMove();
ฉันกำลังขยายโซลูชันจาก jay_t55 ด้วยอีกวิธีหนึ่งToolStrip1_MouseLeave
ที่จัดการกับเหตุการณ์ที่เมาส์เคลื่อนที่อย่างรวดเร็วและออกจากพื้นที่
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;
}
ฉันลองทำตามขั้นตอนต่อไปนี้และทำการเปลี่ยนแปลงล่วงหน้าหน้าต่างโปร่งใสของฉันไม่ถูกแช่แข็งอีกต่อไป แต่สามารถเคลื่อนย้ายได้ !! (ทิ้งโซลูชันที่ซับซ้อนอื่น ๆ ทั้งหมดข้างต้น ... )
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
แบบฟอร์ม 1 (): new Moveable(control1, control2, control3);
ชั้น:
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);
}