Làm cho một biểu mẫu không viền có thể di chuyển được?


109

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:


252

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.


Điều này không hiệu quả với tôi chút nào. Mã chạy rất tốt, mọi thứ đều chính xác, và cửa sổ của tôi vẫn chỉ nằm ở đó. Có ý kiến ​​gì không?
dbrree

8
@dbrree Có thể bạn đã sao chép mã, mã đó sẽ không hoạt động vì Form1_MouseDownkhông được gán cho MouseDownsự kiện thực tế của Form1.
Remon Ramy

2
Nếu bạn có một nhãn hoặc một biểu tượng (hoặc bất kỳ đối tượng tiền cảnh nào khác!) Mà bạn đang lấy biểu mẫu để kéo, hãy thêm một sự kiện mousedown vào những mục này. Các sự kiện biểu mẫu không thể nhìn thấy qua các đối tượng biểu mẫu.
Paul Nelson

1
Bạn cần phải thêm this.MouseDown += ...vào Main()chức năng đối với hình thức
Richard Peck

1
Làm việc như một cái duyên đối với tôi !!!! Tôi đã phải chuyển việc xử lý sự kiện sang bảng điều khiển mà tôi đã đặt ở vị trí của biểu mẫu nhưng nó đã hoạt động
Justin

54

Đừ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;
    }

1
dang winforms ... đã tìm kiếm câu trả lời này trong gần hai giờ đồng hồ .... tôi mới sử dụng c #, bạn đã làm tôi thắc mắc!
PrinceOfRavens

Đây chính xác là cách tôi nghĩ, vấn đề duy nhất của tôi là nó bị lỗi như một cái quái gì đó cho đến khi tôi đọc cách bạn làm điều đó. Cảm ơn người bạn đời
EasyBB

Đoạn mã này hoạt động tốt hơn đối với tôi so với đoạn mã nhỏ tuyệt vời ở trên ghi đè WndProc. Xin lưu ý bạn, WndProc đã hoạt động ... nó chỉ ngăn những thứ khác hoạt động. Cảm ơn!
Mmm,

Có lẽ là lựa chọn tốt nhất ở đây vì nó hoạt động độc đáo và không dựa vào WndProc (có thể dễ dàng chuyển sang các nền tảng khác bằng Mono). Có thể được cải thiện bằng cách thay đổi trạng thái thành tối đa / bình thường nếu Y <10
Sylverdrag

Nó không hoạt động trên mono, đã thay đổi .net 4.5.2 thành mono / net 4.5 và vẫn không hoạt động. Đang cố gắng tìm giải pháp ngay bây giờ.
Roger Deep,

35

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

1
Bất kỳ ai giúp bạn có thể di chuyển biểu mẫu bằng cách giữ một công cụ cụ thể (ví dụ: nhãn).
Thomas W

2
Nếu được nhấp đúp, biểu mẫu sẽ được phóng to. Cũng đọc ở đây và ở đó rằng điều này phá vỡ khi nhấp chuột phải.
Sebastiano

19

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

Nó là. Như đã nói ở những nơi khác, điều này dựa trên biểu mẫu vẫn tạo ra các sự kiện MouseMove. Trong trường hợp đơn giản, giả sử bạn xếp biểu mẫu ở hàng pixel trên cùng và kéo lên trên. Sẽ không có gì xảy ra, mặc dù biểu mẫu sẽ nhảy xung quanh ngay khi bạn di chuyển chuột trở lại nó.
Joey

12

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();

Phương thức Window.DragMove (MSDN)


2
Đó là WPF, mặc dù. Ok, OP không chỉ định chính xác điều này.
Joey

Vâng, đó là điều mà tôi đã quên về dự án mà tôi đang làm. Tôi vừa xem Biểu mẫu và nó không có sẵn. Lấy làm tiếc!
Chris

3
@Chris Điều này đã làm việc cho tôi trong một dự án WPF. Cảm ơn vì đã không xóa câu trả lời.
Rembunator

7

Tham khảo liên kêt video

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

6
Mã này hoạt động, nhưng làm thế nào để nó dễ hiểu? Tôi không biết về bất cứ điều gì trong đoạn mã này ngoài câu lệnh switch!
Jamshaid Kamran

Đây là WM_NCHITTESTngụy trang.
Andreas Rejbrand

4

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.Topthis.Left. Cụ thể bạn sẽ muốn nhìn vào MouseDown, MouseUpMouseMove.


Tôi nghĩ rằng tôi sẽ phải sử dụng những sự kiện đó nhưng tôi không chắc phải làm gì với chúng. Khi sự kiện MouseDown được gọi, làm cách nào để cho phép di chuyển biểu mẫu?
người dùng

1
Khi di chuột xuống, bạn đặt cờ và lưu trữ các tọa độ cơ sở. Khi di chuyển chuột - nếu cờ được đặt - bạn điều chỉnh trên cùng và bên trái theo độ lệch của tọa độ chuột mới. Khi di chuột lên, bạn xóa cờ.
Murph

Tuy nhiên, bạn có thể làm điều này với Windows API khá dễ dàng mà không phụ thuộc vào việc vẫn nhận được các sự kiện chuột. Phương pháp này không thành công nếu bạn lấy một pixel ở cạnh trên cùng của biểu mẫu và kéo lên trên, chẳng hạn.
Joey

4
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 ....


Bạn cũng có thể sử dụng "e.Location" thay vì Control.MousePosition
Reza Taibur

4

https://social.msdn.microsoft.com/Forums/vstudio/en-US/d803d869-68e6-46ff-9ff1-fabf78d6393c/how-to-make-a-borderless-form-in-c?forum=csharpgeneral

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

4

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

4

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

Chào mừng bạn đến với Stack Overflow - tham quan , vui lòng kiểm tra Cách trả lời . Bạn phải cung cấp lời giải thích về cách mã này giải quyết vấn đề của OP "áp phích gốc". Sẽ hữu ích hơn cho bất kỳ ai kiểm tra câu trả lời của bạn.
Mauricio Arias Olave

2

Đối với .NET Framework 4,

Bạn có thể sử dụng this.DragMove()cho MouseDownsự 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();
}

2

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

2

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

2

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

1

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 == 2sau đó 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;


1

Thêm một MouseLeftButtonDowntrì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();

1

Tôi đang mở rộng giải pháp từ jay_t55 với một phương pháp ToolStrip1_MouseLeavekhá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;
}

0

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

Câu trả lời này dành cho WPF, câu hỏi là về WinForms.
Ray

0

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

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

Sẽ rất tốt nếu bạn hỗ trợ câu trả lời của mình với một số giải thích :)
Mustafamg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.