C#自定义窗体(不设置FormBorderStyle=none)
一直以来都在自定义窗体上困惑 从最初的把边框隐藏,到使用位图,处理消息支持窗体的拖动等,总是不太理想。因为以前都是将FormBorderStyle设置为none 这样窗体就真的没有系统边框了,这也带来了一些问题 一旦把FormBorderStyle设置为none就等于去掉了窗体的非客户区 系统也就认为窗体是没有边框的,当然这样的窗体也失去了系统指令 具体表现在Windows7上,系统主题让窗体在最大化最小化的时候都有动画效果,打开和关闭窗体的时候也有淡入淡出的效果 一旦把FormBorderStyle设置为none这些效果都将失去
经过一段时间之后 终于明白了怎么保留这些效果的同时又可以让客户区的大小等于整个窗体的大小
现在说说解决这个问题的方法
当窗体实例化之后我们需要处理相关的消息 拦截非客户区的消息
具体是这几个WM_NCPAINT WM_NCCALCSIZE WM_NCACTIVATE WM_NCHITTEST
对于前3个消息我们不做处理 对于WM_NCHITTEST 通过处理它我们支持窗体的移动 上下左右以及四个角的拖动大小操作
这是仿QQ2010的窗体 由于客户区大小等于窗体大小 所以最大化最小化关闭按钮可以定义控件放到右上角去 这里主要介绍实现这个窗体的关键
2 {
3 if (m.Msg == Win32.WM_NCPAINT)
4 {
5 return;
6 }
7 else if (m.Msg == Win32.WM_NCCALCSIZE)
8 {
9 return;
10 }
11 else if (m.Msg == Win32.WM_NCACTIVATE)
12 {
13 if (m.WParam == (IntPtr)Win32.WM_FALSE)
14 {
15 m.Result = (IntPtr)Win32.WM_TRUE;
16 }
17 }
18 else if (m.Msg == Win32.WM_NCHITTEST)
19 {
20 if (_canResize == true)
21 {
22 Point point = new Point(m.LParam.ToInt32());
23 int x = point.X;
24 int y = point.Y;
25 if (x < this.Left + 11 && y < this.Top + 11)
26 {
27 m.Result = (IntPtr)Win32.HTTOPLEFT;
28 }
29 else if (x > this.Right - 11 && y < this.Top + 11)
30 {
31 m.Result = (IntPtr)Win32.HTTOPRIGHT;
32 }
33 else if (x > this.Right - 11 && y > this.Bottom - 11)
34 {
35 m.Result = (IntPtr)Win32.HTBOTTOMRIGHT;
36 }
37 else if (x < this.Left + 11 && y > this.Bottom - 11)
38 {
39 m.Result = (IntPtr)Win32.HTBOTTOMLEFT;
40 }
41 else if (x < this.Left + 9)
42 {
43 m.Result = (IntPtr)Win32.HTLEFT;
44 }
45 else if (y < this.Top + 9)
46 {
47 m.Result = (IntPtr)Win32.HTTOP;
48 }
49 else if (x > this.Right - 9)
50 {
51 m.Result = (IntPtr)Win32.HTRIGHT;
52 }
53 else if (y > this.Bottom - 9)
54 {
55 m.Result = (IntPtr)Win32.HTBOTTOM;
56 }
57 else
58 {
59 m.Result = (IntPtr)Win32.HTCAPTION;
60 }
61
62 }
63 else
64 {
65 //m.Result = (IntPtr)Win32.HTCAPTION;
66 ReleaseCapture();
67 SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + Win32.HTCAPTION, 0);
68
69 }
70 }
71 else
72 base.WndProc(ref m);
73 }
经过这样的处理之后非客户区依然存在 只是没有了尺寸,使得窗体的大小和非客户区一样了 这里处理拖动的那部分比如边框+9 -9实际上是+ -4 ,因为我把窗体的有效区域的宽度和高度都设置为比窗体小10 事实上QQ的窗体大小和有效区域也是上下左右各5像素的偏差,这样最有一个好处 就是在最大化的时候 当窗体充满屏幕的时候 基本上标题栏这些基本全部能看见
当然这不属于关键的地方 做好这些之后再给窗体设计一些丰富的属性 作为基窗体使用,非常具有实用的价值