C# – 3 cách di chuyển form không có thanh tiêu đề (title bar)

Đây là giải pháp khi bạn tạo một Form không có thanh tiêu đề và muốn dùng chuột để di chuyển tại vị trí bất kì. Bạn cũng có thể áp dụng các phương pháp này để di chuyển một control trong Form.

Cách 1: Sử dụng Windows API

Nguyên lý của cách này là giả lập thông điệp chuột được nhấn lên title bar của form và di chuyển. Để thực hiện ta cần dùng đến Windows API SendMessage() để gửi thông điệp đến cửa sổ cùng với hai tham số để xác định thông điệp là WM_NCLBUTTONDOWN và HTCAPTION.

Để khai báo hàm SendMessage(), ta cần thêm namespace System.Runtime.InteropServices và dùng attribute [DllImport]:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

hWnd: handle của cửa sổ sẽ được nhận thông điệp.

Msg: định danh của thông điệp, trong ví dụ này là WM_NCLBUTTONDOWN. Xem System-Defined Messages.

wParam và lParam: các thông tin đi kèm với thông điệp.

Ta sẽ sử dụng hàm này trong sự kiện MouseDown của form. Nhưng trước khi gọi hàm này, ta phải đảm bảo form sẽ không bắt giữ và nhận các input của chuột bằng cách đặt property Capture = false.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        const int WM_NCLBUTTONDOWN = 0xA1;
        const int HT_CAPTION = 0x2;

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {

            if (e.Button == MouseButtons.Left)
            {
                this.Capture = false;
                SendMessage(this.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
            base.OnMouseDown(e);
        }

    }
}

Cách 2: Tính toán và thay đổi vị trí form theo tọa độ chuột

Phương pháp này rất đơn giản và không cần dùng đến Windows API. Ta chỉ cần lưu lại vị trí khi chuột nhấn xuống (MouseDown) và khi chuột di chuyển, ta sẽ tính toán lại vị trí form dựa vào sự thay đổi giữa vị trí mới và vị trí của của chuột. Sử dụng thêm một biến boolean isMouseDown để xác định trạng thái của chuột.

using System.Windows.Forms;
using System.Drawing;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        bool isMouseDown;

        int xLast;
        int yLast;

        public Form1()
        {
            InitializeComponent();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            isMouseDown = true;
            xLast = e.X;
            yLast = e.Y;

            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (isMouseDown)
            {
                int newY = this.Top + (e.Y - yLast);
                int newX = this.Left + (e.X - xLast);

                this.Location = new Point(newX, newY);
            }

            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            isMouseDown = false;

            base.OnMouseUp(e);
        }

    }
}

Cách 3: Thay đổi thông điệp của cửa sổ

Phương pháp này được thực hiện bằng cách thay đổi thông điệp nhấn chuột trên client area (vùng trong cửa sổ trừ title bar) thành thông điệp trên title bar. Bằng cách override phương thức WndProc(), ta sẽ thay đổi property Message.Result từ HTCLIENT thành HTCAPTION. Property này tương ứng với tham số wParam trong hàm SensMessage().

Đây là cách tốt nhất và đơn giản nhất mà bạn nên áp dụng.

using System;
using System.Windows.Forms;
using System.Drawing;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        const int WM_NCHITTEST = 0x84;
        const int HTCLIENT = 0x1;
        const int HTCAPTION = 0x2;

        public Form1()
        {
            InitializeComponent();
        }
        protected override void WndProc(ref Message message)
        {
            base.WndProc(ref message);

            if (message.Msg == WM_NCHITTEST && (int)message.Result == HTCLIENT)
                message.Result = (IntPtr)HTCAPTION;
        }
    }
}
Advertisements

8 thoughts on “C# – 3 cách di chuyển form không có thanh tiêu đề (title bar)

  1. WndProc (viết tắt của Window Procedure) là phương thức nhận các thông điệp mà hệ thống gửi đến một cửa sổ. Ví dụ khi bạn click chuột lên vùng nội dung Form thì thông điệp WM_NCHITTEST sẽ được gửi đến WndProc cùng với tham số WM_NCHITTEST. Ngược lại nếu bạn click chuột lên vùng title của Form thì thông điệp WM_NCHITTEST với tham số HTCAPTION sẽ được gửi đến WndProc.

    Trả lời
  2. Cho mình hỏi là minh đang tìm hiểu về wpf . Mình cũng muốn di chuyển form mà không có title bar, mình đã thử search mà không ra, không biết bạn có thể chỉ mình không vậy. Mình cũng đã thử sử dụng sự kiện MouseLeftButtonDown mà vẫn không được, không biết mình có làm sai ở chổ nào không nữa. Mong được sớm hồi âm

    Trả lời

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s