Có cách nào để làm cho biểu mẫu không có đường viền (FormBorderStyle được đặt thành "không") có thể di chuyển được khi con chuột được nhấp xuống trên biểu mẫu giống như thể có đường viền không?
Có cách nào để làm cho biểu mẫu không có đường viền (FormBorderStyle được đặt thành "không") có thể di chuyển được khi con chuột được nhấp xuống trên biểu mẫu giống như thể có đường viền không?
Câu trả lời:
Bài viết này trên CodeProject nêu chi tiết về một kỹ thuật. Về cơ bản là tóm tắt:
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);
}
}
Đây thực chất không chính xác giống như lấy thanh tiêu đề của cửa sổ, từ quan điểm của quản lý cửa sổ của tầm nhìn.
Form1_MouseDown
không được gán cho MouseDown
sự kiện thực tế của Form1
.
this.MouseDown += ...
vào Main()
chức năng đối với hình thức
Đừng làm mọi thứ khó khăn hơn mức cần thiết. Tôi đã xem qua rất nhiều đoạn mã cho phép bạn kéo một biểu mẫu xung quanh (hoặc một Điều khiển khác). Và nhiều người trong số họ có nhược điểm / tác dụng phụ của riêng họ. Đặc biệt là những người mà họ đánh lừa Windows nghĩ rằng Điều khiển trên biểu mẫu là biểu mẫu thực.
Điều đó đang được nói, đây là đoạn mã của tôi. Tôi sử dụng nó mọi lúc. Tôi cũng muốn lưu ý rằng bạn không nên sử dụng this.Invalidate (); như những người khác thích làm vì nó khiến biểu mẫu nhấp nháy trong một số trường hợp. Và trong một số trường hợp, điều này cũng vậy. Sử dụng cái này. Cập nhật, tôi không gặp bất kỳ sự cố chập chờn nào:
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;
}
Một cách khác đơn giản hơn để làm điều tương tự.
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;
}
sử dụng MouseDown, MouseMove và MouseUp. Bạn có thể đặt một cờ biến cho điều đó. Tôi có một mẫu, nhưng tôi nghĩ bạn cần phải sửa đổi.
Tôi đang mã hóa thao tác chuột vào một bảng điều khiển. Khi bạn nhấp vào bảng điều khiển, biểu mẫu của bạn sẽ di chuyển cùng với nó.
//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);
}
}
Chỉ WPF
không có mã chính xác để sử dụng, nhưng trong một dự án gần đây, tôi nghĩ rằng tôi đã sử dụng sự kiện MouseDown và chỉ cần đặt điều này:
frmBorderless.DragMove();
Điều này đã được thử nghiệm và dễ hiểu.
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
ngụy trang.
Không có tài sản nào bạn có thể lật để biến điều này trở nên kỳ diệu. Nhìn vào các sự kiện cho biểu mẫu và nó trở nên khá đơn giản để thực hiện điều này bằng cách đặt this.Top
và this.Left
. Cụ thể bạn sẽ muốn nhìn vào MouseDown
, MouseUp
và 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;
}
}
điều này có thể giải quyết vấn đề của bạn ....
Đoạn mã này từ liên kết trên đã thực hiện thủ thuật trong trường hợp của tôi :)
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);
}
}
Cách tốt nhất tôi đã tìm thấy (tất nhiên đã sửa đổi)
// 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; }
}
}
Để áp dụng kéo cho một điều khiển, chỉ cần chèn cái này sau InitializeComponent ()
AddDrag(NameOfControl);
Nó đã làm việc cho tôi.
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);
}
}
Đối với .NET Framework 4,
Bạn có thể sử dụng this.DragMove()
cho MouseDown
sự kiện của thành phần (mainLayout trong ví dụ này) bạn đang sử dụng để kéo.
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
Cách dễ nhất là:
Đầu tiên tạo một nhãn có tên là label1. Đi tới sự kiện của label1> sự kiện chuột> Label1_Mouse Di chuyển và viết những điều sau:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
Tôi đang cố tạo dạng cửa sổ không viền có thể di chuyển được trong đó có điều khiển Máy chủ phần tử WPF và điều khiển Người dùng WPF.
Tôi đã kết thúc với một bảng điều khiển ngăn xếp có tên StackPanel trong điều khiển người dùng WPF của tôi, điều này có vẻ hợp lý khi thử nhấp vào để di chuyển. Thử mã của junmats hoạt động khi tôi di chuyển chuột chậm, nhưng nếu tôi di chuyển chuột nhanh hơn, chuột sẽ di chuyển ra khỏi biểu mẫu và biểu mẫu sẽ bị kẹt ở đâu đó giữa di chuyển.
Điều này đã cải thiện câu trả lời của anh ấy cho tình huống của tôi khi sử dụng CaptureMouse và ReleaseCaptureMouse và bây giờ con chuột không di chuyển khỏi biểu mẫu khi di chuyển nó ngay cả khi tôi di chuyển nó nhanh chóng.
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);
Vì một số câu trả lời không cho phép kéo các điều khiển con, tôi đã tạo một lớp trợ giúp nhỏ. Nó phải được thông qua biểu mẫu cấp cao nhất. Có thể được thực hiện chung chung hơn nếu muốn.
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);
}
}
}
Ngoài ra, nếu bạn cần DoubleClick và làm cho Biểu mẫu của mình lớn hơn / nhỏ hơn, bạn có thể sử dụng Câu trả lời đầu tiên, tạo biến int chung, thêm 1 mỗi khi người dùng nhấp vào thành phần bạn sử dụng để kéo. Nếu variable == 2
sau đó làm cho biểu mẫu của bạn lớn hơn / nhỏ hơn. Cũng sử dụng bộ đếm thời gian cho mỗi nửa giây hoặc một giây để thực hiện variable = 0
;
Thêm một MouseLeftButtonDown
trình xử lý sự kiện vào MainWindow đã làm việc cho tôi.
Trong hàm sự kiện được tạo tự động, hãy thêm mã dưới đây:
base.OnMouseLeftButtonDown(e);
this.DragMove();
Tôi đang mở rộng giải pháp từ jay_t55 với một phương pháp ToolStrip1_MouseLeave
khác xử lý sự kiện chuột di chuyển nhanh và rời khỏi vùng.
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;
}
Tôi đã thử cách sau và trước khi thay đổi, cửa sổ trong suốt của tôi không còn bị đóng băng tại chỗ mà có thể di chuyển được !! (vứt bỏ tất cả các giải pháp phức tạp khác ở trên ...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
Hình thức 1(): new Moveable(control1, control2, control3);
Lớp học:
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);
}