【编程】界面 – 皮肤界面(自画窗口标题)

    在皮肤界面中,最难的恐怕就是自画窗口标题了,网上虽然有各种各样的解决方法,但是都不是很完美,而商业皮肤界面程序包是需要花钱买的。


其中最主要的问题有:


1、在标题栏或边框移动鼠标时系统会画窗口标题


2、没有任务栏图标。当取消了 SYS_CAPTION Style 后系统不会画窗口标题了,但是同时该窗口也没有任务栏图标。


3、最大化后在标题栏按下鼠标时系统会画窗口标题


4、按下系统按钮再移动鼠标到按钮外后没有正确的重画按钮


    没办法,只有自己摸索了,研究了网络上的一些代码片段和几个比较成功的皮肤界面程序比如 RealPlay, Microsoft Money ,发现它们采用的手法都不尽相同,而网上关于这个问题也没有很完美的解决方案,总是有点小瑕疵。最后,去研究了一下 Windows 2000 的核心代码中关于窗口管理部分,终于算是比较满意的解决了上面的这些问题,但是,我采用的方法和RealPlay, Microsoft Money 都不太一样,RealPlay 好象没有了 NC_* 的消息,而Microsoft Money 则是采用遮盖的方法,而我是采用直接重画的方法,关键是找到重画的关键点。



关键代码:


  1    BEGIN_MSG_MAP(TCaptionBaseT)
  2        MESSAGE_HANDLER(WM_NCHITTEST,            OnNCHitTest)
  3        MESSAGE_HANDLER(WM_NCPAINT,                OnNCPaint)
  4
  5        MESSAGE_HANDLER(WM_NCLBUTTONDOWN,        OnNCLButtonDown)
  6        MESSAGE_HANDLER(WM_NCLBUTTONUP,            OnNCLButtonUp)
  7        MESSAGE_HANDLER(WM_NCMOUSEMOVE,            OnNCMouseMove)
  8        MESSAGE_HANDLER(WM_LBUTTONUP,            OnLButtonUp)
  9
10        MESSAGE_HANDLER(WM_NCACTIVATE,            OnNCActivate)
11
12        MESSAGE_HANDLER(WM_SYSCOMMAND,            OnSysCommand)
13        MESSAGE_HANDLER(WM_INITMENU,            OnInitMenu)
14
15        MESSAGE_HANDLER(WM_SIZE,                OnSizeChanged)
16        MESSAGE_HANDLER(WM_STYLECHANGED ,        OnStyleChanged)
17 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingsChange) 18        MESSAGE_HANDLER(WM_SETTEXT,                OnSetText)
19        MESSAGE_HANDLER(WM_SETICON ,            OnSetIcon)
20
21        MESSAGE_HANDLER(WM_CREATE,                OnCreate)
22        MESSAGE_HANDLER(WM_INITDIALOG,            OnInitDialog)
23    END_MSG_MAP()
24
25    LRESULT OnNCLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
26    {
27        // wParam 由 OnNcHitTest 返回
28        T* pT = static_cast<T*>(this);
29       
30        POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
31        mn_ButtonPress = HTNOWHERE;
32
33        switch( wParam )
34        {
35        case HTMINBUTTON:
36        case HTMAXBUTTON:
37        case HTCLOSE:
38        case HTHELP:
39            mn_ButtonPress  = wParam;
40            mb_OnPressed    = TRUE;
41            bHandled        = TRUE;        // 表示已经处理过了,否则系统会重画按钮且 WM_NC_LBUTTONUP 不会被触发。
42            pT->doReDrawCaption();
43            break;
44        case HTCAPTION:
45            bHandled = FALSE;    // 继续让系统进行缺省处理
46            {
47                DWORD nStyle = pT->GetStyle();
48                if(nStyle & WS_MINIMIZE)
49                {
50                    return 0; // BUG: Prevents move of iconic window, but fixes Windows freeze
51                }

52                else
53                if(nStyle & WS_MAXIMIZE)
54                {
55                    // 在系统最大化的时候需要在鼠标按下时重画标题栏
56                    bHandled = TRUE; // 表示已经处理过了,否则系统会重画按钮。
57                    // 让系统对 HTCAPTION 进行处理
58                    pT->DefWindowProc(uMsg, wParam, lParam);
59                    pT->doReDrawCaption();
60                }

61            }

62            break;
63        default:
64            bHandled = FALSE;    // 继续让系统进行缺省处理
65            break;
66        }

67        return 0;
68    }

69   
70    LRESULT OnNCLButtonUp(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
71    {
72        // wParam 由 OnNcHitTest 返回
73        T* pT = static_cast<T*>(this);
74
75        mb_OnPressed = FALSE;
76
77        if(wParam == mn_ButtonPress)
78        {
79            // 鼠标按下和释放在相同的按钮上
80            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
81            switch( wParam )
82            {
83            case HTMINBUTTON:
84                pT->PostMessage(WM_SYSCOMMAND, SC_MINIMIZE, MAKELPARAM(pt.x, pt.y));
85                bHandled = TRUE;    // 禁止系统做缺省处理
86                break;
87            case HTMAXBUTTON:
88                mn_ButtonMove = HTNOWHERE;        // 最大画后鼠标位置将改变
89                if(pT->GetStyle() & WS_MAXIMIZE)
90                    pT->PostMessage(WM_SYSCOMMAND, SC_RESTORE,  MAKELPARAM(pt.x, pt.y));
91                else
92                    pT->PostMessage(WM_SYSCOMMAND, SC_MAXIMIZE, MAKELPARAM(pt.x, pt.y));
93                bHandled = TRUE;    // 禁止系统做缺省处理
94                break;
95            case HTCLOSE:
96                pT->PostMessage(WM_CLOSE);
97                bHandled = TRUE;    // 禁止系统做缺省处理
98                break;
99            case HTHELP:
100                pT->PostMessage(WM_HELP);
101                bHandled = TRUE;    // 禁止系统做缺省处理
102                break;
103            case HTSYSMENU:
104            default:
105                bHandled = FALSE;    // 让系统进行缺省处理
106            }

107        }

108        mn_ButtonPress = HTNOWHERE;
109        return 0;
110    }

111
112    LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
113    {
114        bHandled = FALSE;
115
116        mb_OnPressed    = FALSE;
117        mn_ButtonPress    = HTNOWHERE;
118
119        return 0;
120    }

This entry was posted in [P]编程技术. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word