winform:關於画非客户区
关于画非客户,其实在VC中已有相关的许多资料,而C#的也有,只是不全面。因为用C#做WINFORM的本来就不是特别多,有的也就加个皮肤控件就完事了。
可我有兴趣,终于完成了一个,嘿嘿!
其实画非客户并不难,只是处理的消息比较多,而C#调用API又不方便,或者说思路就没往API那方面去想,所以造成还是有点不适应。一直鄙視自已對API不是很熟,用到查到。。。。。
主要参考资料,都是VC的
http://www.3800hk.com/Article/cxsj/vc/jmlbcvc/2005-08-25/Article_54021.html
http://hi.baidu.com/ljfblog/blog/item/dc3d1a55c1ff35c6b745ae92.html
http://blog.csdn.net/yyan/archive/2007/04/06/1554048.aspx
主要处理的消息就是NC****,也即是NO CLIENT,所谓的非客户区。
主要处理的消息:
WM_NCCALCSIZE:
The WM_NCCALCSIZE message is sent when the size and position of a window's client area must be calculated. By processing this message, an application can control the content of the window's client area when the size or position of the window changes.
wParam
If wParam is TRUE, it specifies that the application should indicate which part of the client area contains valid information. The system copies the valid information to the specified area within the new client area.
If wParam is FALSE, the application does not need to indicate the valid part of the client area.
lParam
If wParam is TRUE, lParam points to an NCCALCSIZE_PARAMS structure that contains information an application can use to calculate the new size and position of the client rectangle.
If wParam is FALSE, lParam points to a RECT structure. On entry, the structure contains the proposed window rectangle for the window. On exit, the structure should contain the screen coordinates of the corresponding window client area.
if (Convert.ToBoolean(m.WParam.ToInt32()))
{
Win32API.NCCALCSIZE_PARAMS t = (Win32API.NCCALCSIZE_PARAMS)m.GetLParam(typeof(Win32API.NCCALCSIZE_PARAMS));
//Win32API.NCCALCSIZE_PARAMS t = (Win32API.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(Win32API.NCCALCSIZE_PARAMS));一直都用这个,后来才知消息参数里面就带了一个可以转的了
// int i =Win32API.GetSystemMetrics(Win32API
// .SM_CYCAPTION);
int CaptionHeight =
Win32API.GetSystemMetrics(Win32API
.SM_CYCAPTION);
int Border3DWidth = System.Windows.Forms.SystemInformation.Border3DSize.Width;
这里使用FW或者API都可以取到窗体的相关属性
int BorderWidth = System.Windows.Forms.SystemInformation.BorderSize.Width;
尝试过了,只有修改RECT[0]才有效果撒…
t.rgrc[0].top = t.rgrc[0].top - CaptionHeight - Border3DWidth - BorderWidth + TitleImageSize.Height - 1;设置标题栏高度为TitleImageSize.Height
t.rgrc[0].left = t.rgrc[0].left - Border3DWidth;
t.rgrc[0].right = t.rgrc[0].right + Border3DWidth;
t.rgrc[0].bottom = t.rgrc[0].bottom + Border3DWidth;
Marshal.StructureToPtr(t, m.LParam, false);结构体转指针
base.WndProc(ref m);
}
此消息是用于修改窗体客户区位置的。
WM_NCPAINT
The WM_NCPAINT message is sent to a window when its frame must be painted. An application can intercept the WM_NCPAINT message and paint its own custom window frame. The clipping region for a window is always rectangular, even if the shape of the frame is altered.
关健就在于怎么取于DC,不过在FW之下这一下是这么简单
IntPtr hDC = Win32API.GetWindowDC(m.HWnd);
Bitmap bmp = new Bitmap(TitleRec.Width, TitleRec.Height);
Graphics gBMP = Graphics.FromImage(bmp);
Graphics gs = Graphics.FromHdc(hDC);
MSDN示例:
case WM_NCPAINT:
{
HDC hdc;
hdc = GetDCEx(hwnd, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
// Paint into this DC
ReleaseDC(hwnd, hdc);
}
简单介绍下GetWindowDC
GetWindowDC
The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars.
A window device context permits painting anywhere in a window,
because the origin of the device context is the upper-left corner of the window instead of the client area.
WM_NCHITTEST
The WM_NCHITTEST message is sent to a window when the cursor moves, or when a mouse button is pressed or released. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is sent to the window that has captured the mouse.
把这消息处理了,那窗体点击会出现默认按钮,最大化最小化关闭按钮等问题就都解决了。
if (!IsMax)
if (NonCamandRectange.Contains(CurPoint))
{
m.Result = (IntPtr)Win32API.HTCAPTION;
}
还有下面这两个消息
WM_NCUAHDRAWCAPTION
WM_NCUAHDRAWFRAME
這兩個消息好難才找到撒。。。。謝謝前面LJF的博文
“ 0x00AE://WM_NCUAHDRAWCAPTION
0x00AF://WM_NCUAHDRAWFRAME
这两条消息是在xp sp2后加的.xp在以前有个bug在某些时候Titlebar会画错.
在这里不能调用默认处理,直接自绘nc区.”
WM_ACTIVATEAPP
不知大家有沒注意到,有時窗口獲取焦點時標題欄大小會變一點點。而窗體獲得焦點或失去焦點都會發送這個消息,只是在WParam裡面說明是獲得還是失去焦點.ONLostFoucs等都用。
The WM_ACTIVATEAPP message is sent when a window belonging to a different application than the active window is about to be activated. The message is sent to the application whose window is being activated and to the application whose window is being deactivated.
wParam
Specifies whether the window is being activated or deactivated. This parameter is TRUE if the window is being activated; it is FALSE if the window is being deactivated
处理以下消息,可以
WM_NCLBUTTONUP
WM_NCLBUTTONDOWN
WM_NCMOUSEMOVE
這幾倏消息就不難了。。。。處理下就可以了。嘿嘿,主要還是在繪制按鈕上。剩下就是圖片。