到第四部分Delphi XE3的代码能基本完成窗体界面的绘制。窗口中的其他控件的处理方法也是相同的,截获消息处理消息。
问题这个编译出来的个头可不小。Release版本竟然2.43M,完全是个胖子。系统中应该加入了大量基础代码(如泛型之类),用Delphi7编译出来应该能小一截。
使用默认Release的配置方案,没有第三方控件。
翻译到C++进行测试,发现明显这个个头没法比。Debug版本88.5K...~~~ 这货确实小。
C版本只实现了部分代码(第一篇内容),并没有全部实现。思路一样,只是换个表示方法而已。
代码中处理了四个消息,还是比较简单。只有 WM_WINDOWPOSCHANGING 消息的处理稍微长些。
- WM_NCPAINT --- 绘制非客户区
- WM_NCCALCSIZE --- 重新设置边缘宽度
- WM_NCACTIVATE --- 程序切换时重绘非客户去
- WM_WINDOWPOSCHANGING --- 重设界面样式
连注释和空行也就152行代码。
重新绘制非客户区 WM_NCPAINT
// 非客户去绘制
case WM_NCPAINT:
GetWindowRect(hwnd, &rw);
GetClientRect(hwnd, &rc);
pt.x = rc.left;
pt.y = rc.top;
ClientToScreen(hwnd, &pt);
OffsetRect(&rc, pt.x - rw.left, pt.y - rw.top);
hdc = GetWindowDC(hwnd);
ExcludeClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
OffsetRect(&rw, -rw.left, -rw.top);
// 使用这个方式比使用fillrect函数填充效果好,不闪烁
SetBkColor(hdc, 0xBF7B18);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rw, 0, 0, 0);
ReleaseDC(hwnd, hdc);
return 0;
重新设置窗体边缘宽度 WM_NCCALCSIZE
// 设置窗体边框宽度
case WM_NCCALCSIZE:
((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].left += 3;
((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].top += 55;
((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].right -= 4;
((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].bottom -= 4;
break;
切换程序时重绘非客户去WM_NCACTIVATE
case WM_NCACTIVATE:
PostMessage(hWnd, WM_NCPAINT, 1, 0); // 通知刷新非客户区
break;
设置窗体样式 WM_WINDOWPOSCHANGING
// 有修改窗体尺寸时重设样式
//
case WM_WINDOWPOSCHANGING:
bChanged = FALSE;
// 窗体位置发生改变,重新计算绘制样式
if (!bChangeSizeCalled) {
bChanged = (((LPWINDOWPOS)lParam)->flags & SWP_FRAMECHANGED);
if ((((LPWINDOWPOS)lParam)->flags & SWP_NOMOVE) == 0) {
rWindowSize.left = ((LPWINDOWPOS)lParam)->x;
rWindowSize.top = ((LPWINDOWPOS)lParam)->y;
}
if ((((LPWINDOWPOS)lParam)->flags & SWP_NOSIZE) == 0) {
bChanged = bChanged || (((LPWINDOWPOS)lParam)->cx != rWindowSize.right) || (((LPWINDOWPOS)lParam)->cy != rWindowSize.bottom);
rWindowSize.right = ((LPWINDOWPOS)lParam)->cx;
rWindowSize.bottom = ((LPWINDOWPOS)lParam)->cy;
}
bChanged = bChanged && ((rWindowSize.right * rWindowSize.bottom) != 0);
if (bChanged) {
bChangeSizeCalled = TRUE;
__try {
hTmp = hRegion;
hRegion = CreateRoundRectRgn(0, 0, rWindowSize.right, rWindowSize.bottom, 3, 3);
SetWindowRgn(hwnd, hRegion, TRUE);
if (hTmp)
DeleteObject(hTmp);
} __finally {
bChangeSizeCalled = FALSE;
}
}
}
if (!bChanged)
return DefWindowProc(hwnd, message, wParam, lParam);
return 0;
开发环境:
- VS2015 社区版
- Win7
完整源代码: