在最小化窗口的同时更改系统颜色时,菜单栏消失

时间:2018-09-25 20:51:29

标签: winapi menubar wm-paint

我的应用程序具有工具栏类型菜单。我对窗口过程进行了子分类,以实现视觉增强,这意味着我的应用程序正在绘制菜单栏。在最小化和还原应用程序窗口后,菜单会重新绘制。

但是,如果在最小化应用程序窗口的同时更改了系统颜色,则在恢复应用程序窗口时,菜单栏将消失。我发现,当在最小化应用程序窗口的同时系统颜色发生变化时,恢复窗口后,WM_PAINT不会发送到菜单栏。

我尝试了以下操作:

  1. 通过响应WM_PAINT调用InvalidateRect()强制将WM_SIZE发送到菜单栏,但这并未导致发送WM_PAINT

  2. 通过使用WM_PAINT标志调用RedrawWindow(),强制将RDW_INTERNALPAINT发送到菜单栏。它成功发送了WM_PAINT,并调用了绘制菜单的过程。但是菜单仍然不显示。

  3. 当系统颜色更改时,通过响应ShowWindow()调用WM_SYSCOLORCHANGE来恢复窗口。有效。 WM_PAINT被发送到菜单栏,菜单出现。但是,我认为让我的窗口突然弹出,中断用户对其他程序的操作是不礼貌的。

有人可以建议我如何在不恢复窗口的情况下正确地显示菜单栏吗?

下面是我的尝试方法。

在主窗口过程中:

LRESULT CALLBACK DlgWndProc (HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{
 static  int          HighContrastOn ;
 static  HWND         hwndMenuBar ;
 static  HINSTANCE    hThisInst ;
 static  NMTOOLBAR    nmtb = { NULL , IDC_MENUBAR , TBN_DROPDOWN , 0 } ;
 static  HIGHCONTRAST HighContrast = { sizeof (HIGHCONTRAST) , 0 , 0 } ;

 switch (msg) {

    case WM_CREATE :
        hThisInst = ((LPCREATESTRUCT) lParam)->hInstance ;
        SystemParametersInfo (SPI_GETHIGHCONTRAST,0,&HighContrast,0) ;
        HighContrastOn = HighContrast.dwFlags & HCF_HIGHCONTRASTON ;
        return 0 ;

    case WM_DESTROY :
        PostQuitMessage (0) ;
        return 0 ;

    case WM_CLOSE :
        DestroyMenu (hMenu) ;
        DestroyWindow (hDlg);
        return 0 ;

    case WM_SYSCOLORCHANGE :
        ShowWindow (hDlg,SW_NORMAL) ;
        SendMessage (hwndMenuBar,WM_SYSCOLORCHANGE,0,0) ;
        return 0 ;

    case WM_SETTINGCHANGE :
        // Catch change in HighContrast status missed by WM_SYSCOLORCHANGE  
        SystemParametersInfo (SPI_GETHIGHCONTRAST,0,&HighContrast,0) ;
        if (HighContrastOn == (HighContrast.dwFlags & HCF_HIGHCONTRASTON))
            return 0 ;
        HighContrastOn = HighContrast.dwFlags & HCF_HIGHCONTRASTON ;
        SendMessage (hwndMenuBar,WM_SYSCOLORCHANGE,0,0) ;
        return 0 ;

    case WM_NOTIFY :
        OnNotify (hDlg,wParam,lParam) ;
        break ;

    case WM_COMMAND :
        OnCommand (hDlg,wParam,lParam) ;
        break ;

    case WM_INITMENUPOPUP :
        int SubMenu ;
        SubMenu = (int) SendMessage (hwndMenuBar,TB_GETHOTITEM,0,0) ;
        for (int i = 0 ; i < 5 ; i++) {
            if (GetSubMenu (hMenu,i) == (HMENU) wParam)
                SendMessage (hwndMenuBar,WM_INITMENUPOPUP,SubMenu,0) ;
        } /* for (int i = 0 ; i < 5 ; i++) */
        InitMenuPopup ((HMENU) wParam,SubMenu) ;
        return 0 ;

    case WM_UNINITMENUPOPUP :
        int i ;
        // Find out whther the closing menu is sub menu or sub-sub menu
        for (i = 0 ; i < 5 ; i++) {
            if ((HMENU) wParam == GetSubMenu (hMenu,i))
                break ;
        } /* for (i = 0 ; i < 5 ; i++) */
        if (i < 5) {
            UnhookWindowsHookEx (DefaultMsgHook) ;
            SendMessage (hDlg,WM_NOTIFY,IDC_MENUBAR,(LPARAM) &nmtb) ;
            SendMessage (hwndMenuBar,WM_UNINITMENUPOPUP,0,0) ;
        } /* if (i < 5) */
        return 0 ;

    case IDM_INIT :
        InitDialog (hDlg) ;

        hMenu = LoadMenu (hThisInst,"MyProgram") ;
        hwndMenuBar = GetDlgItem (hDlg,IDC_MENUBAR) ;
        nmtb.hdr.hwndFrom = hwndMenuBar ;
        SetWindowSubclass (hwndMenuBar,MenuBarProc,0,0) ;
        SendMessage (hwndMenuBar,WM_NULL,0,0) ;
        return 0 ;

} /* switch (msg) */

/* Pass unprocessed messages to DefDlgProc */
return DefDlgProc (hDlg,msg,wParam,lParam) ;

} /* DlgWndProc */


LRESULT WINAPI MenuBarMsgHook (int Code,WPARAM wParam,LPARAM lParam)
{
static NMTOOLBAR nmtb ;

switch (Code) {

    case MSGF_MENU :
        #define Msg ((LPMSG) lParam)
        HWND hwndMenuBar ;
        hwndMenuBar = GetDlgItem (Msg->hwnd,IDC_MENUBAR) ;

        switch (Msg->message) {
            POINT pt ;

            case WM_LBUTTONDOWN :
            case WM_RBUTTONDOWN :
                pt = Msg->pt ;
                ScreenToClient (hwndMenuBar,(LPPOINT) &pt) ;
                SendMessage (hwndMenuBar,Msg->message,wParam,
                             (LPARAM) MAKELONG (pt.x,pt.y)) ;
                break ;

            case WM_MOUSEMOVE :
                pt = Msg->pt ;
                ScreenToClient (hwndMenuBar,(LPPOINT) &pt) ;
                SendMessage (hwndMenuBar,WM_MOUSEMOVE,wParam,
                             (LPARAM) MAKELONG (pt.x,pt.y)) ;
                break ;
        } /* switch (Msg->message) */
        #undef Msg
} /* switch (Code) */

return CallNextHookEx (NULL,Code,wParam,lParam) ;

} /* MenuBarMsgHook */


LRESULT CALLBACK MenuBarProc (HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam,
                              UINT_PTR uIdSubclass,DWORD_PTR dwRefData)
{
static  bool    BtnDown ;
static  int     HighContrastOn ;
static  int     yc ;
static  int     xr ;
static  int     yb ;
static  int     HBtn = -1 ;
static  char*   Text[] = {"File","Edit","Settings","Design","Help"} ;
static  RECT    Rect[5] ;
static  HFONT   Font ;
static  HPEN    Pen ;
static  HPEN    HPen ;
static  HPEN    SPen ;
static  HBRUSH  Brush ;
static  HBRUSH  HBrush ;
static  HBRUSH  SBrush ;
static  COLORREF  BtnTextColor     = GetSysColor (COLOR_BTNTEXT) ;
static  COLORREF  MenuColor        = GetSysColor (COLOR_MENUBAR) ;
static  COLORREF  HotLightColor    = GetSysColor (COLOR_HOTLIGHT) ;
static  COLORREF  HighLightColor   = GetSysColor (COLOR_HIGHLIGHT) ;
static  COLORREF  HiLightTextColor = GetSysColor (COLOR_HIGHLIGHTTEXT) ;
static  COLORREF  WindowFrameColor = GetSysColor (COLOR_WINDOWFRAME) ;

static  HIGHCONTRAST HighContrast = { sizeof (HIGHCONTRAST) , 0 , 0 } ;
static  TRACKMOUSEEVENT  tme = {sizeof (TRACKMOUSEEVENT),TME_LEAVE,NULL,
                                HOVER_DEFAULT} ;
HDC     hDC ;

switch (msg) {

    case WM_NULL :
        SystemParametersInfo (SPI_GETHIGHCONTRAST,0,&HighContrast,0) ;
        HighContrastOn = HighContrast.dwFlags & HCF_HIGHCONTRASTON ;

        Font   = CreateMenuFont (hwnd) ;
        Pen    = (HPEN) GetStockObject (NULL_PEN) ;
        Brush  = CreateSolidBrush (MenuColor) ;

        if (HighContrastOn) {
            HPen   = CreatePen (PS_SOLID,0,WindowFrameColor) ;
            SPen   = CreatePen (PS_SOLID,0,WindowFrameColor) ;
            HBrush = CreateSolidBrush (HighLightColor) ;
            SBrush = CreateSolidBrush (HighLightColor) ;
        } /* if (HighContrastOn) */
        else {
            HPen   = CreatePen (PS_SOLID,0,0xF87400) ;
            SPen   = CreatePen (PS_SOLID,0,HotLightColor) ;
            HBrush = CreateSolidBrush (0xFFF4E6) ;
            SBrush = CreateSolidBrush (0xFED8B0) ;
        } /* else */
        for (int Btn = 0 ; Btn < 5 ; Btn++)
            SendMessage (hwnd,TB_GETRECT,IDM_FILEMENU + Btn,(LPARAM) (Rect + Btn)) ;

        hDC = GetDC (hwnd) ;
        TEXTMETRIC  tm ;
        GetTextMetrics (hDC,&tm) ;
        ReleaseDC (hwnd,hDC) ;
        yc = (Rect[0].bottom - Rect[0].top - tm.tmHeight) / 2 + tm.tmAscent - 1 ;
        xr = Rect[4].right ;
        yb = Rect[0].bottom ;
        tme.hwndTrack = hwnd ;
        return 0 ;

    case WM_PAINT :
        if (! GetUpdateRect (hwnd,NULL,false))
            break ;
        #define rc (Rect[Btn])
        PAINTSTRUCT ps ;
        hDC = BeginPaint (hwnd,&ps) ;

        SelectObject (hDC,Font) ;
        SelectObject (hDC,Pen) ;
        SelectObject (hDC,Brush) ;
        SetTextAlign (hDC,TA_BASELINE | TA_CENTER) ;
        SetTextColor (hDC,BtnTextColor) ;
        SetBkMode (hDC,TRANSPARENT) ;

        for (int Btn = 0 ; Btn < 5 ; Btn++) { 
            Rectangle (hDC,rc.left,rc.top,rc.right,rc.bottom) ;
            if (Btn == HBtn)
                continue ;
            int xc = (rc.right + rc.left) / 2 ;
            ExtTextOut (hDC,xc,yc,ETO_NUMERICSLATIN,&rc,Text[Btn],
                        (UINT) strlen (Text[Btn]),NULL) ;
        } /* for (int Btn = 0 ; Btn < 5 ; Btn++) */
        #undef rc

        #define rc (Rect[HBtn])
        if (HBtn > -1) {
            SelectObject (hDC,BtnDown ? SPen : HPen) ;
            SelectObject (hDC,BtnDown ? SBrush : HBrush) ;
            SetTextColor (hDC,HighContrastOn ? HiLightTextColor : BtnTextColor) ;
            RoundRect (hDC,rc.left + 1,rc.top + 1,rc.right - 1,rc.bottom - 2,2,2) ;
            int xc = (rc.right + rc.left) / 2 ;
            ExtTextOut (hDC,xc,yc,ETO_NUMERICSLATIN,&rc,Text[HBtn],
                        (UINT) strlen (Text[HBtn]),NULL) ;
        } /* if (HBtn > -1) */
        #undef rc

        EndPaint (hwnd,&ps) ;
        return 0 ;

    case WM_SYSCOLORCHANGE :
        DeleteObject (HPen) ;
        DeleteObject (SPen) ;
        DeleteObject (Brush) ;
        DeleteObject (HBrush) ;
        DeleteObject (SBrush) ;
        HighLightColor   = GetSysColor (COLOR_HIGHLIGHT) ;
        WindowFrameColor = GetSysColor (COLOR_WINDOWFRAME) ;
        HotLightColor    = GetSysColor (COLOR_HOTLIGHT) ;
        HiLightTextColor = GetSysColor (COLOR_HIGHLIGHTTEXT) ;
        BtnTextColor     = GetSysColor (COLOR_BTNTEXT) ;
        MenuColor        = GetSysColor (COLOR_MENUBAR) ;
        SystemParametersInfo (SPI_GETHIGHCONTRAST,0,&HighContrast,0) ;
        HighContrastOn = HighContrast.dwFlags & HCF_HIGHCONTRASTON ;
        if (HighContrastOn) {
            HPen   = CreatePen (PS_SOLID,0,WindowFrameColor) ;
            SPen   = CreatePen (PS_SOLID,0,WindowFrameColor) ;
            HBrush = CreateSolidBrush (HighLightColor) ;
            SBrush = CreateSolidBrush (HighLightColor) ;
        } /* if (HighContrastOn) */
        else {
            HPen   = CreatePen (PS_SOLID,0,0xF87400) ;
            SPen   = CreatePen (PS_SOLID,0,HotLightColor) ;
            HBrush = CreateSolidBrush (0xFFF4E6) ;
            SBrush = CreateSolidBrush (0xFED8B0) ;
        } /* else */
        Brush  = CreateSolidBrush (MenuColor) ;
        return 0 ;

    case WM_NCDESTROY:
        DeleteObject (Font) ;
        DeleteObject (HPen) ;
        DeleteObject (SPen) ;
        DeleteObject (Brush) ;
        DeleteObject (HBrush) ;
        DeleteObject (SBrush) ;
        RemoveWindowSubclass (hwnd,MenuBarProc,0) ;
        break ;

    case WM_INITMENUPOPUP :
        HBtn = (int) wParam ;
        BtnDown = true ;
        InvalidateRect (hwnd,NULL,true) ;
        break ;

    case WM_UNINITMENUPOPUP :
        HBtn = -1 ;
        BtnDown = false ;
        InvalidateRect (hwnd,NULL,true) ;
        break ;

    case WM_MOUSEMOVE :
        #define rc (Rect[Btn])
        int x ;
        int y ;
        x = LOWORD (lParam) ;
        y = HIWORD (lParam) ;
        if (HBtn > -1 && x > xr && ! BtnDown) {
            HBtn = -1 ;
            InvalidateRect (hwnd,NULL,true) ;
            break ;
        } /* if (HBtn > -1 && x > xr && ! BtnDown) */
        for (int Btn = 0 ; Btn < 5 ; Btn++) {
            if (y < rc.bottom && x > rc.left && x < rc.right) {
                if (Btn == HBtn)
                    break ;
                HBtn = Btn ;
                InvalidateRect (hwnd,NULL,true) ;
                break ;
            } /* if (y < rc.bottom && x > rc.left && x < rc.right) */
        } /* for (int Btn = 0 ; Btn < 5 ; Btn++) */
        TrackMouseEvent (&tme) ;
        #undef rc
        break ;

    case WM_MOUSELEAVE :
        if (! BtnDown) {
            HBtn = -1 ;
            InvalidateRect (hwnd,NULL,true) ;
        } /* if (! BtnDown) */
        return 0 ;

} /* switch (msg) */

return DefSubclassProc (hwnd,msg,wParam,lParam) ;

} /* MenuBarProc */

这里是fn的一部分。 InitDialog()显示菜单栏的初始化

#define  NUMBUTTONS   5

static TBBUTTON  tbButtons[NUMBUTTONS] =
    {{I_IMAGENONE, IDM_FILEMENU   , TBSTATE_ENABLED, BTNS_DROPDOWN | BTNS_AUTOSIZE, {0}, 0,(INT_PTR) " File"} ,
     {I_IMAGENONE, IDM_EDITMENU   , TBSTATE_ENABLED, BTNS_DROPDOWN | BTNS_AUTOSIZE, {0}, 0,(INT_PTR) " Edit"} ,
     {I_IMAGENONE, IDM_SETTINGSMENU,TBSTATE_ENABLED, BTNS_DROPDOWN | BTNS_AUTOSIZE, {0}, 0,(INT_PTR) " Settings"} ,
     {I_IMAGENONE, IDM_DESIGNMENU , TBSTATE_ENABLED, BTNS_DROPDOWN | BTNS_AUTOSIZE, {0}, 0,(INT_PTR) " Design"} ,
     {I_IMAGENONE, IDM_HELPMENU   , TBSTATE_ENABLED, BTNS_DROPDOWN | BTNS_AUTOSIZE, {0}, 0,(INT_PTR) " Help"}} ;

HFONT MenuFont = CreateMenuFont (hwndMenuBar) ;
SendMessage (hwndMenuBar,WM_SETFONT,(WPARAM) MenuFont,false) ;
SendMessage (hwndMenuBar,TB_BUTTONSTRUCTSIZE,(WPARAM) sizeof(TBBUTTON),0) ;
SendMessage (hwndMenuBar,TB_ADDBUTTONS, (WPARAM) NUMBUTTONS, 
             (LPARAM) (LPTBBUTTON) &tbButtons) ;

SendMessage (hwndMenuBar,TB_AUTOSIZE,0,0) ;
SendMessage (hwndMenuBar,TB_SETINDENT,2,0) ;
ShowWindow (hwndMenuBar,SW_SHOW) ;

SetWindowSubclass (hwndMenuBar,MenuBarProc,0,0) ;
SendMessage (hwndMenuBar,WM_NULL,0,0) ;
DeleteObject (MenuFont) ;

菜单栏在对话框资源中定义如下

CONTROL   " ",IDC_MENUBAR,"ToolbarWindow32",TBSTYLE_FLAT | TBSTYLE_LIST | WS_CLIPCHILDREN,0,0,0,0,0,HIDC_MENUBAR

2 个答案:

答案 0 :(得分:0)

您应该将WM_SYSCOLORCHANGE消息转发到工具栏控件。

case WM_SYSCOLORCHANGE:
    SendMessage( toolbar_hwnd, WM_SYSCOLORCHANGE, wparam, lparam );
    break;

您发送了TB_AUTOSIZE条消息吗?

SendMessage( toolbar_hwnd, TB_AUTOSIZE, 0, 0 );

答案 1 :(得分:0)

感谢Daniel Sek,我添加了他针对WM_SIZE提出的建议,并解决了问题。

 case WM_SIZE :
     SendMessage (hwndMenuBar,TB_AUTOSIZE,0,0) ;
     return 0 ;

我不需要为MenuBar调用InvalidateRect()。 TB_AUTOSIZE消息导致WM_PAINT消息被发送到菜单栏并显示菜单。

非常感谢您的支持。