到第四部分Delphi XE3的代码能基本完成窗体界面的绘制。窗口中的其他控件的处理方法也是相同的,截获消息处理消息。
问题这个编译出来的个头可不小。Release版本竟然2.43M,完全是个胖子。系统中应该加入了大量基础代码(如泛型之类),用Delphi7编译出来应该能小一截。
使用默认Release的配置方案,没有第三方控件。
翻译到C++进行实验,发现明显这个个头没法比。Debug版本88.5K...~~~ 这货确实小。可惜再小现公司项目也不会考虑用C++开发,有些悲剧。
C版本只实现了部分代码(第一篇内容),并没有全部实现。思路一样,只是换个表示方法而已。
代码中处理了四个消息,还是比较简单。只有 WM_WINDOWPOSCHANGING 消息的处理稍微长些。
WM_NCPAINT --- 绘制非客户区
WM_NCCALCSIZE --- 重新设置边缘宽度
WM_NCACTIVATE --- 程序切换时重绘非客户去
WM_WINDOWPOSCHANGING --- 重设界面样式
重新绘制非客户区 WM_NCPAINT
// LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_NCPAINT: hdc = GetWindowDC(hWnd); PaintNC(hWnd, hdc); ReleaseDC(hWnd, hdc); break; // 非客户去绘制 void PaintNC(HWND hWnd, HDC dc) { HBRUSH hBrush; RECT rw; RECT rc; POINT pt; 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); ExcludeClipRect(dc, rc.left, rc.top, rc.right, rc.bottom); // 扣除客户区 OffsetRect(&rw, -rw.left, -rw.top); hBrush = CreateSolidBrush(0xBF7B18); FillRect(dc, &rw, hBrush); DeleteObject(hBrush); }
重新设置窗体边缘宽度 WM_NCCALCSIZE
1 // 设置窗体边框宽度 2 case WM_NCCALCSIZE: 3 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].left += 3; 4 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].top += 55; 5 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].right -= 4; 6 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].bottom -= 4; 7 break;
切换程序时重绘非客户去WM_NCACTIVATE
1 case WM_NCACTIVATE: 2 PostMessage(hWnd, WM_NCPAINT, 1, 0); 3 break;
设置窗体样式 WM_WINDOWPOSCHANGING
1 // 有修改窗体尺寸时重设样式 2 // 3 4 case WM_WINDOWPOSCHANGING: 5 bChanged = FALSE; 6 if (!gChangeSizeCalled) { 7 bChanged = (((LPWINDOWPOS)lParam)->flags & SWP_FRAMECHANGED); 8 if ((((LPWINDOWPOS)lParam)->flags & SWP_NOMOVE) == 0){ 9 gWindowSize.left = ((LPWINDOWPOS)lParam)->x; 10 gWindowSize.top = ((LPWINDOWPOS)lParam)->y; 11 } 12 if ((((LPWINDOWPOS)lParam)->flags & SWP_NOSIZE) == 0){ 13 bChanged = bChanged || (((LPWINDOWPOS)lParam)->cx != gWindowSize.right) || (((LPWINDOWPOS)lParam)->cy != gWindowSize.bottom); 14 gWindowSize.right = ((LPWINDOWPOS)lParam)->cx; 15 gWindowSize.bottom = ((LPWINDOWPOS)lParam)->cy; 16 } 17 bChanged = bChanged && ((gWindowSize.right * gWindowSize.bottom) != 0); 18 19 if (bChanged){ 20 gChangeSizeCalled = TRUE; 21 __try { 22 hTmp = gRegion; 23 gRegion = CreateRoundRectRgn(0, 0, gWindowSize.right, gWindowSize.bottom, 3, 3); 24 SetWindowRgn(hWnd, gRegion, TRUE); 25 if (hTmp) 26 DeleteObject(hTmp); 27 } 28 __finally { 29 gChangeSizeCalled = FALSE; 30 } 31 } 32 } 33 34 if (!bChanged) 35 return DefWindowProc(hWnd,message, wParam, lParam); 36 37 break;
完整代码文件
1 // skin.cpp : Defines the entry point for the application. 2 // 3 4 #include "stdafx.h" 5 #include "skin.h" 6 7 #define MAX_LOADSTRING 100 8 9 // Global Variables: 10 HINSTANCE hInst; // current instance 11 TCHAR szTitle[MAX_LOADSTRING]; // The title bar text 12 TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name 13 14 HRGN gRegion = 0; 15 BOOL gChangeSizeCalled = FALSE; 16 RECT gWindowSize = {0,0,0,0}; 17 18 // Forward declarations of functions included in this code module: 19 ATOM MyRegisterClass(HINSTANCE hInstance); 20 BOOL InitInstance(HINSTANCE, int); 21 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 22 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 23 24 void PaintNC(HWND, HDC); 25 26 27 int APIENTRY _tWinMain(HINSTANCE hInstance, 28 HINSTANCE hPrevInstance, 29 LPTSTR lpCmdLine, 30 int nCmdShow) 31 { 32 UNREFERENCED_PARAMETER(hPrevInstance); 33 UNREFERENCED_PARAMETER(lpCmdLine); 34 35 // TODO: Place code here. 36 MSG msg; 37 HACCEL hAccelTable; 38 39 // Initialize global strings 40 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 41 LoadString(hInstance, IDC_SKIN, szWindowClass, MAX_LOADSTRING); 42 MyRegisterClass(hInstance); 43 44 // Perform application initialization: 45 if (!InitInstance (hInstance, nCmdShow)) 46 { 47 return FALSE; 48 } 49 50 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SKIN)); 51 52 // Main message loop: 53 while (GetMessage(&msg, NULL, 0, 0)) 54 { 55 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 56 { 57 TranslateMessage(&msg); 58 DispatchMessage(&msg); 59 } 60 } 61 62 return (int) msg.wParam; 63 } 64 65 66 67 // 68 // FUNCTION: MyRegisterClass() 69 // 70 // PURPOSE: Registers the window class. 71 // 72 // COMMENTS: 73 // 74 // This function and its usage are only necessary if you want this code 75 // to be compatible with Win32 systems prior to the ‘RegisterClassEx‘ 76 // function that was added to Windows 95. It is important to call this function 77 // so that the application will get ‘well formed‘ small icons associated 78 // with it. 79 // 80 ATOM MyRegisterClass(HINSTANCE hInstance) 81 { 82 WNDCLASSEX wcex; 83 84 wcex.cbSize = sizeof(WNDCLASSEX); 85 86 wcex.style = CS_HREDRAW | CS_VREDRAW; 87 wcex.lpfnWndProc = WndProc; 88 wcex.cbClsExtra = 0; 89 wcex.cbWndExtra = 0; 90 wcex.hInstance = hInstance; 91 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SKIN)); 92 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 93 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 94 wcex.lpszMenuName = MAKEINTRESOURCE(IDC_SKIN); 95 wcex.lpszClassName = szWindowClass; 96 wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 97 98 return RegisterClassEx(&wcex); 99 } 100 101 // 102 // FUNCTION: InitInstance(HINSTANCE, int) 103 // 104 // PURPOSE: Saves instance handle and creates main window 105 // 106 // COMMENTS: 107 // 108 // In this function, we save the instance handle in a global variable and 109 // create and display the main program window. 110 // 111 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 112 { 113 HWND hWnd; 114 115 hInst = hInstance; // Store instance handle in our global variable 116 117 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 118 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); 119 120 if (!hWnd) 121 { 122 return FALSE; 123 } 124 125 ShowWindow(hWnd, nCmdShow); 126 UpdateWindow(hWnd); 127 128 return TRUE; 129 } 130 131 // 132 // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 133 // 134 // PURPOSE: Processes messages for the main window. 135 // 136 // WM_COMMAND - process the application menu 137 // WM_PAINT - Paint the main window 138 // WM_DESTROY - post a quit message and return 139 // 140 // 141 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 142 { 143 int wmId, wmEvent; 144 PAINTSTRUCT ps; 145 HDC hdc; 146 147 HRGN hTmp; 148 BOOL bChanged; 149 LRESULT result; 150 151 switch (message) 152 { 153 case WM_COMMAND: 154 wmId = LOWORD(wParam); 155 wmEvent = HIWORD(wParam); 156 // Parse the menu selections: 157 switch (wmId) 158 { 159 case IDM_ABOUT: 160 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 161 break; 162 case IDM_EXIT: 163 DestroyWindow(hWnd); 164 break; 165 default: 166 return DefWindowProc(hWnd, message, wParam, lParam); 167 } 168 break; 169 case WM_PAINT: 170 hdc = BeginPaint(hWnd, &ps); 171 // TODO: Add any drawing code here... 172 EndPaint(hWnd, &ps); 173 break; 174 175 case WM_NCPAINT: 176 hdc = GetWindowDC(hWnd); 177 PaintNC(hWnd, hdc); 178 ReleaseDC(hWnd, hdc); 179 break; 180 181 case WM_NCCALCSIZE: 182 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].left += 3; 183 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].top += 55; 184 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].right -= 4; 185 ((LPNCCALCSIZE_PARAMS)lParam)->rgrc[0].bottom -= 4; 186 break; 187 188 case WM_NCACTIVATE: 189 PostMessage(hWnd, WM_NCPAINT, 1, 0); 190 break; 191 192 case WM_WINDOWPOSCHANGING: 193 bChanged = FALSE; 194 195 if (!gChangeSizeCalled) { 196 bChanged = (((LPWINDOWPOS)lParam)->flags & SWP_FRAMECHANGED); 197 198 if ((((LPWINDOWPOS)lParam)->flags & SWP_NOMOVE) == 0){ 199 gWindowSize.left = ((LPWINDOWPOS)lParam)->x; 200 gWindowSize.top = ((LPWINDOWPOS)lParam)->y; 201 } 202 if ((((LPWINDOWPOS)lParam)->flags & SWP_NOSIZE) == 0){ 203 bChanged = bChanged || (((LPWINDOWPOS)lParam)->cx != gWindowSize.right) || (((LPWINDOWPOS)lParam)->cy != gWindowSize.bottom); 204 gWindowSize.right = ((LPWINDOWPOS)lParam)->cx; 205 gWindowSize.bottom = ((LPWINDOWPOS)lParam)->cy; 206 } 207 208 bChanged = bChanged && ((gWindowSize.right * gWindowSize.bottom) != 0); 209 210 if (bChanged) 211 { 212 gChangeSizeCalled = TRUE; 213 __try { 214 hTmp = gRegion; 215 gRegion = CreateRoundRectRgn(0, 0, gWindowSize.right, gWindowSize.bottom, 3, 3); 216 SetWindowRgn(hWnd, gRegion, TRUE); 217 if (hTmp) 218 DeleteObject(hTmp); 219 } 220 __finally { 221 gChangeSizeCalled = FALSE; 222 } 223 } 224 } 225 226 if (!bChanged) 227 return DefWindowProc(hWnd,message, wParam, lParam); 228 229 break; 230 231 case WM_DESTROY: 232 PostQuitMessage(0); 233 break; 234 235 case WM_QUIT: 236 if (gRegion) { 237 DeleteObject(gRegion); 238 gRegion = 0; 239 } 240 return DefWindowProc(hWnd, message, wParam, lParam); 241 242 default: 243 return DefWindowProc(hWnd, message, wParam, lParam); 244 } 245 return 0; 246 } 247 248 // Message handler for about box. 249 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 250 { 251 UNREFERENCED_PARAMETER(lParam); 252 switch (message) 253 { 254 case WM_INITDIALOG: 255 return (INT_PTR)TRUE; 256 257 case WM_COMMAND: 258 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 259 { 260 EndDialog(hDlg, LOWORD(wParam)); 261 return (INT_PTR)TRUE; 262 } 263 break; 264 } 265 return (INT_PTR)FALSE; 266 } 267 268 void PaintNC(HWND hWnd, HDC dc) 269 { 270 HBRUSH hBrush; 271 RECT rw; 272 RECT rc; 273 POINT pt; 274 275 GetWindowRect(hWnd, &rw); 276 GetClientRect(hWnd, &rc); 277 pt.x = rc.left; 278 pt.y = rc.top; 279 ClientToScreen(hWnd, &pt); 280 OffsetRect(&rc, pt.x - rw.left, pt.y - rw.top); 281 282 ExcludeClipRect(dc, rc.left, rc.top, rc.right, rc.bottom); 283 284 OffsetRect(&rw, -rw.left, -rw.top); 285 hBrush = CreateSolidBrush(0xBF7B18); 286 FillRect(dc, &rw, hBrush); 287 DeleteObject(hBrush); 288 }