zoukankan      html  css  js  c++  java
  • 窗体皮肤实现

    到第四部分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 }
    单元 skin.cpp

    蘑菇房 (moguf.com)

  • 相关阅读:
    算法洗脑系列(8篇)——第五篇 分治思想
    算法洗脑系列(8篇)——第七篇 动态规划
    算法洗脑系列(8篇)——第四篇 枚举思想
    8天学通MongoDB——第二天 细说增删查改
    12篇学通C#网络编程——第一篇 基础之进程线程
    算法系列15天速成——第十五天 图【下】(大结局)
    算法洗脑系列(8篇)——第一篇 递推思想
    8天学通MongoDB——第三天 细说高级操作
    8天学通MongoDB——第四天 索引操作
    算法洗脑系列(8篇)——第八篇 概率思想
  • 原文地址:https://www.cnblogs.com/gleam/p/3986395.html
Copyright © 2011-2022 走看看