设计没有Style的Winform窗体,通过拖动操作区而非标题区让Form跟着鼠标移动。

我们平时设计常用的Form都是基于FormBorderStyle为Sizeable的,但是随着扁平化发展的迅速,Winform也偏向于扁平化的设计(虽然要做的更炫更好的话还是推荐WPF,但是毕竟Winfom还在用么)。

实际工作中碰到这样一个问题,我制作了一个窗体FormBorderStyle为None的窗体,如图:

如果此时我要移动这个窗体的话,由于没有标题栏,所以无法移动,当一个比较简单的解决办法是,对Form添加MouseDown事件和MouseMove事件,代码如下:

方案1:

Point downPoint;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    downPoint = new Point(e.X, e.Y); 
}

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Location = new Point(Location.X + e.X - downPoint.X, 
            Location.Y + e.Y - downPoint.Y);
    } 
}

MouseDown的时候将当前鼠标坐标存储,MouseMove的时候,实际上就是实时的将窗体最后一次的Location+偏移量-鼠标的位置。

这样做好处在于简单,不足在于:

(1)如果添加了如图所示的OpenFileDialog,那么当打开这个窗体的时候,主窗体会记录鼠标位置,同时当你选择文件的时候,默认认为你进行了偏移,关闭选择文件窗口的时候窗体就偏移了。

(2)对于窗体上的一些控件,必须添加两个事件使之也能同步,不太友好。

方案2:

这个方案是网上找到的,实际上利用消息的机制来进行设置,优点:不用声明api函数。缺点是:窗体上放着Panel等容器就会失效。

const int WM_NCHITTEST = 0x0084;
const int HTLEFT = 10;
const int HTCAPTION = 2;
const int HTCLIENT = 1;
protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);
    switch (m.Msg)
    {
        case WM_NCHITTEST:
            if (m.Result == (IntPtr)HTCLIENT)
                m.Result = (IntPtr)HTCAPTION;
            break;
    }
}

方案3:

这个方案是我现在用的方案,虽然比较复杂,但是能恰到好处的处理掉拖动的问题,同时其他控件调用也比较方便

using System.Runtime.InteropServices;

[DllImport("User32.DLL")]
public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("User32.DLL")]
public static extern bool ReleaseCapture();
public const uint WM_SYSCOMMAND = 0x0112;
public const int SC_MOVE = 61456;
public const int HTCAPTION = 2;

private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    ReleaseCapture();
    SendMessage(Handle, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
}

实际上还是使用了消息机制,优点在于,例如Label等控件也只需要调用一下这个方法就可以进行整个窗体的移动了。

posted on 2013-06-14 17:03  浅草才能没马蹄  阅读(394)  评论(0)    收藏  举报

导航