在winform经常用到无边框的窗体,原因就是想使自己的程序界面完全的自定义,网上也有过不少的相关资料
今天我发了一下的午的时间整理了一下.觉得还不错,贴出来看看.
为了提高托动的缩放的效率,减少系统开销,一般软件都用支持只显示窗体四周的虚线的方法,这也是windows默认的设置
首先看下其它软件的窗体托动,先说QQ2009吧,QQ2009的主窗体在托动时如果在屏幕上来回快速托动,等停下来时你会发现,很有可能鼠标现在在窗体的位置已经不是按下的位置了.再说酷我音乐盒.鼠标在托动或缩放窗体时,如果鼠标移动到窗体的各边框上时,鼠标形状仍然会改变.而且就算系统设置设置成托动时显示窗体内容,在托动和缩放时也不会显示内容,仍然是虚线.此虚线遇到有些情况会很乱,比如在播放的动画的电影上时,因为直按用屏幕DC画的,而且放后破坏其它窗体的界面,其它的重画时,他就可能会不显示了下面介绍几种托动的方法
先说两种常用的,再补充说明
1.在mousemove,mousedown,mouseup三个事件的配合下来移动和缩放就不说了,代码多,效率低,一般初学者都能写出来.
2.就是用系统已经存在的方法,一般是重写窗口过程,和用sendmessage来骗系统.
重写回调函数的小例子
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCLBUTTONDBLCLK://WM_NCLBUTTONDBLCLK=163 <0xA3>拦截鼠标非客户区左键双击消息,决定窗体是否最大化显示
if (this.MaximizeBox)
{
base.WndProc(ref m);//这种方法的好处是自己不用处理鼠标形状了.
this.Invalidate();
}
return;
case WM_NCHITTEST://WM_NCHITTEST=132 <0x84>
base.WndProc(ref m);//如果去掉这一行代码,窗体将失去MouseMove..等事件
Point lpint = new Point((int)m.LParam);//可以得到鼠标坐标,这样就可以决定怎么处理这个消息了,是移动窗体,还是缩放,以及向哪向的缩放
m.Result = (IntPtr)0x2;//托动HTCAPTION=2 <0x2>
//当然可以托动也可以改变大小了
//HTLEFT=10 <0xA> 左边框
//HTTOP=12 <0xC> 上边框
//HTTOPLEFT=13 <0xD>
//HTTOPRIGHT=14 <0xE>
//HTRIGHT=11 <0xB>
//HTBOTTOM=15 <0xF>
//HTBOTTOMLEFT=16 <0x10>
//HTBOTTOMRIGHT=17 <0x11>
//HTBORDER=18 <0x12>
//HTMINBUTTON=8 <0x8> 最小化按钮
//HTMAXBUTTON=9 <0x9> 最大化按钮
//HTCLOSE=20 <0x14> 关闭按钮
return;
default:
base.WndProc(ref m);
return;
}
}
发送消息的例子,也可以在上面的回函数中加入发送消息的方法,
也可以在窗体的mousedown..等事件和其它控件的事件里发送消息
记得要先释放鼠标用API函数ReleaseCapture();或控件的或窗体的Capture属性Capture = false;
API函数的声明我就不说了这里用到的API有三个,SetWindowLong可用可不用,只是用他来举另一个例子
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool ReleaseCapture();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SetWindowLong(IntPtr hWnd, int Index, long Value);
//托动
SendMessage(this.Handle, /*WM_SYSCOMMAND */274,/*移动信息SC_MOVE=*/61456+/*HTCAPTION =2*/2, 0);
//左边框缩放
SendMessage(this.Handle, /*WM_SYSCOMMAND */274,/*移动信息SC_Size=*/61440 +/*WMSZ_LEFT=1 <0x1> 这里可以换成其它参数下面给出*/1, 0);
//左边框WMSZ_LEFT=1 <0x1>
//右边WMSZ_RIGHT=2 <0x2>
//上边WMSZ_TOP=3 <0x3>
//WMSZ_TOPLEFT=4 <0x4>
//WMSZ_TOPRIGHT=5 <0x5>
//WMSZ_BOTTOM=6 <0x6>
//WMSZ_BOTTOMLEFT=7 <0x7>
//WMSZ_BOTTOMRIGHT=8 <0x8>
这里就可以完成两种方法的托动和缩放了,但 是还是和有边框的不一样,有边框的托动时和缩放时可以是很粗的虚线,而现在的却很细很细的.
这时就可以用上面提到过的SetWindowLong了,
SetWindowLong(this.Handle, GWL_STYLE, WS_SYSMENU | WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
这样不但是粗边框了,而且系统菜单都有了,但是有一点不好,有兴趣的话自己可以研究下
而我用另一种方法觉得还可以,在窗体的MouseDown里这样写
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
this.Capture = false;
Form ff = new Form();
ff.StartPosition = FormStartPosition.Manual;
ff.Size = this.Size;
ff.Location = this.Location;
//ff.Show();不让窗体显示
SendMessage(ff.Handle, 274, 61440+1, 0);//发送移动信息,也可以发送其它比如缩放消息
this.Size= ff.Size;
this.Location = ff.Location;
ff.Dispose();
}