【问题标题】:What is the correct way to destroy the CMFCMenuBar and CMFCToolBar and recreate them?销毁 CMFCMenuBar 和 CMFCToolBar 并重新创建它们的正确方法是什么?
【发布时间】:2020-06-23 06:35:09
【问题描述】:

我想将 MFC 应用程序更改为可感知每个监视器。大多数事情都可以正常工作,但菜单和工具栏却不行。我想简单地重新创建它们,大概是拾取当前的 DPI。我基本上试过了:

  if (m_wndToolBar.GetSafeHwnd()) {
    m_wndToolBar.DestroyWindow();
  }

  if (m_wndMenuBar.GetSafeHwnd()) {
    m_wndMenuBar.DestroyWindow();
  }

随后是正常的创建过程,但在 m_wndMenuBar.Create() 它断言。

这是在 m_wndMenuBar.Create(this) 中失败的地方

if (!CMFCBaseToolBar::Create(
        GetGlobalData()->RegisterWindowClass(_T("Afx:ToolBar")), dwStyle, rect, pParentWnd, nID, 0))
    {
        return FALSE;
    }

【问题讨论】:

    标签: mfc dpi


    【解决方案1】:

    假设您的主窗口源自CFrameWnd,您可以从应用程序的资源重新加载菜单栏,应该重置它(其中resource 是主菜单的 ID,并且加速器表):

     CMyFrameWnd *pFrame = dynamic_cast(AfxGetApp()->AfxGetMainWnd());
        if (pFrame && pFrame->IsWindowEnabled())) {
            HMENU defMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCE(resource));
            pFrame->m_wndMenuBar.CreateFromMenu(defMenu, TRUE, TRUE);
            pFrame->LoadAccelTable(MAKEINTRESOURCE(resource));
        }
    

    您可以可能使用CMFCToolBar::LoadToolBar()成员在工具栏上执行类似的操作,但我没有使用或测试过该功能。

    【讨论】:

    • 它没有改变字体大小。我希望它能像启动时那样扩展。所以我们的想法是销毁现有项目,让它再次创建它们,MFC 会自动设置大小(在每个监视器 dpi 模式下)。
    • 添加了失败位置的详细信息。
    【解决方案2】:

    在每个显示器模式下处理 DPI 缩放。这似乎适用于默认菜单栏和工具栏。

      class CCustomMFCToolBar : public CMFCToolBar
      {
        public:
        BOOL FullRestoreOriginalState()
        {
          // ensure restore original
            if (m_uiOriginalResID == 0)
            {
                return FALSE;
            }
    
          // remove existing images
          ResetAllImages();
    
          // reset id so bitmaps are loaded again
          UINT resid=m_uiOriginalResID;
          m_uiOriginalResID=0;
    
          // handle loading toolbar and bitmaps
            BOOL bRes = LoadToolBar(resid);
    
            AdjustLayout();
    
            if (IsFloating())
            {
                RecalcLayout();
            }
            else if (m_pParentDockBar != NULL)
            {
                CSize sizeCurr = CalcFixedLayout(FALSE, IsHorizontal());
                CRect rect;
                GetWindowRect(rect);
    
                if (rect.Size() != sizeCurr)
                {
                    SetWindowPos(NULL, 0, 0, sizeCurr.cx, sizeCurr.cy, SWP_NOMOVE  | SWP_NOACTIVATE | SWP_NOZORDER);
                    UpdateVirtualRect();
                }
                m_pDockBarRow->ArrangePanes(this);
                AFXGetParentFrame(this)->RecalcLayout();
            }
    
            RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
    
            return bRes;
        }
    
      };
    

    在此处捕获 DPI 更改或重新启动所有项目,因为 WM_SETTINGCHANGED 在 WM_DPICHANGED 之后调用

    void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
    {
      CFrameWndEx::OnSettingChange(uFlags, lpszSection);
      g_DPIHelper.SetChangedScaleForWindow(m_hWnd);
    
     
      struct GlobalDataUnprotect : AFX_GLOBAL_DATA
      {
        #define AFX_FONT_NAME_OFFICE       _T("Tahoma")
        #define AFX_FONT_NAME_OFFICE_2007  _T("Segoe UI")
        #define AFX_FONT_NAME_DEFAULT      _T("MS Sans Serif")
        #define AFX_FONT_NAME_VERT         _T("Arial")
        #define AFX_FONT_NAME_MARLETT      _T("Marlett")
    
         // This is a copy of UpdateFonts() modified a couple places to
         // set the correct / changed scaling.
    
        static int CALLBACK FontFamilyProcFonts(const LOGFONT FAR* lplf, const TEXTMETRIC FAR* lptm, ULONG ulFontType, LPARAM lParam)
        {
            ENSURE(lplf != NULL);
            ENSURE(lParam != NULL);
    
            CString strFont = lplf->lfFaceName;
            return strFont.CollateNoCase((LPCTSTR) lParam) == 0 ? 0 : 1;
        }
    
        void UpdateScaledFonts()
        {
            CWindowDC dc(NULL);
    
            m_dblRibbonImageScale = static_cast<double>(g_DPIHelper.GetScale())/100.0;
    
            if (m_dblRibbonImageScale > 1. && m_dblRibbonImageScale < 1.1)
            {
                m_dblRibbonImageScale = 1.;
            }
    
            if (fontRegular.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontRegular.Detach());
            }
    
            if (fontTooltip.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontTooltip.Detach());
            }
    
            if (fontBold.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontBold.Detach());
            }
    
            if (fontDefaultGUIBold.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontDefaultGUIBold.Detach());
            }
    
            if (fontUnderline.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontUnderline.Detach());
            }
    
            if (fontDefaultGUIUnderline.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontDefaultGUIUnderline.Detach());
            }
    
            if (fontVert.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontVert.Detach());
            }
    
            if (fontVertCaption.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontVertCaption.Detach());
            }
    
            if (fontMarlett.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontMarlett.Detach());
            }
    
            if (fontSmall.GetSafeHandle() != NULL)
            {
                ::DeleteObject(fontSmall.Detach());
            }
    
            // Initialize fonts:
    
            NONCLIENTMETRICS info;
            info.cbSize = sizeof(info);
            GetNonClientMetrics (info);
    
            LOGFONT lf;
            memset(&lf, 0, sizeof(LOGFONT));
    
            lf.lfCharSet = (BYTE) GetTextCharsetInfo(dc.GetSafeHdc(), NULL, 0);
    
            lf.lfHeight = info.lfMenuFont.lfHeight;
            lf.lfWeight = info.lfMenuFont.lfWeight;
            lf.lfItalic = info.lfMenuFont.lfItalic;
    
            //------------------
            // Adjust font size:
            //------------------
            int nFontHeight = lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight;
            if (nFontHeight <= 12)
            {
                nFontHeight = 11;
            }
            else if (!m_bDontReduceFontHeight)
            {
                nFontHeight--;
            }
    
            lf.lfHeight = (lf.lfHeight < 0) ? -nFontHeight : nFontHeight;
    
          lf.lfHeight=g_DPIHelper.ScaleNonClientMetricsFont(lf.lfHeight);
    
            // Check if we should use system font
            lstrcpy(lf.lfFaceName, info.lfMenuFont.lfFaceName);
    
            BOOL fUseSystemFont = m_bUseSystemFont || (info.lfMenuFont.lfCharSet > SYMBOL_CHARSET);
            if (!fUseSystemFont)
            {
                // Check for "Segoe UI" or "Tahoma" font existance:
                if (::EnumFontFamilies(dc.GetSafeHdc(), NULL, FontFamilyProcFonts, (LPARAM)(LPCTSTR) AFX_FONT_NAME_OFFICE_2007) == 0)
                {
                    // Found! Use MS Office 2007 font!
                    lstrcpy(lf.lfFaceName, AFX_FONT_NAME_OFFICE_2007);
              lf.lfQuality=5; // CLEARTYPE_QUALITY;
                }
                else if (::EnumFontFamilies(dc.GetSafeHdc(), NULL, FontFamilyProcFonts, (LPARAM)(LPCTSTR) AFX_FONT_NAME_OFFICE) == 0)
                {
                    // Found! Use MS Office font!
                    lstrcpy(lf.lfFaceName, AFX_FONT_NAME_OFFICE);
                }
                else
                {
                    // Not found. Use default font:
                    lstrcpy(lf.lfFaceName, AFX_FONT_NAME_DEFAULT);
                }
            }
        
            fontRegular.CreateFontIndirect(&lf);
    
            // Create small font:
            LONG lfHeightSaved = lf.lfHeight;
    
            lf.lfHeight = (long)((1. + abs(lf.lfHeight)) * 2 / 3);
            if (lfHeightSaved < 0)
            {
                lf.lfHeight = -lf.lfHeight;
            }
    
            fontSmall.CreateFontIndirect(&lf);
            lf.lfHeight = lfHeightSaved;
    
            // Create tooltip font:
            NONCLIENTMETRICS ncm;
            ncm.cbSize = sizeof(ncm);
            GetNonClientMetrics (ncm);
    
            lf.lfItalic = ncm.lfStatusFont.lfItalic;
            lf.lfWeight = ncm.lfStatusFont.lfWeight;
            fontTooltip.CreateFontIndirect(&lf);
    
            lf.lfItalic = info.lfMenuFont.lfItalic;
            lf.lfWeight = info.lfMenuFont.lfWeight;
    
            // Create "underline" font:
            lf.lfUnderline = TRUE;
            fontUnderline.CreateFontIndirect(&lf);
            lf.lfUnderline = FALSE;
    
            // Create bold font:
            lf.lfWeight = FW_BOLD;
            fontBold.CreateFontIndirect(&lf);
    
            // Create Marlett font:
            BYTE bCharSet = lf.lfCharSet;
            lf.lfWeight = info.lfMenuFont.lfWeight;
            lf.lfCharSet = SYMBOL_CHARSET;
            lf.lfWeight = 0;
          lf.lfHeight=g_DPIHelper.ScaleNonClientMetricsFont(::GetSystemMetrics(SM_CYMENUCHECK) - 1);
            lstrcpy(lf.lfFaceName, AFX_FONT_NAME_MARLETT);
    
            fontMarlett.CreateFontIndirect(&lf);
            lf.lfCharSet = bCharSet; // Restore charset
    
            // Create vertical font:
            CFont font;
            if (font.CreateStockObject(DEFAULT_GUI_FONT))
            {
                if (font.GetLogFont(&lf) != 0)
                {
                    lf.lfOrientation = 900;
                    lf.lfEscapement = 2700;
    
              lf.lfHeight = g_DPIHelper.ScaleNonClientMetricsFont(info.lfMenuFont.lfHeight);
                    lf.lfWeight = info.lfMenuFont.lfWeight;
                    lf.lfItalic = info.lfMenuFont.lfItalic;
    
                    {
                        lstrcpy(lf.lfFaceName, AFX_FONT_NAME_VERT);
                    }
    
                    fontVert.CreateFontIndirect(&lf);
    
                    lf.lfEscapement = 900;
                    fontVertCaption.CreateFontIndirect(&lf);
                }
            }
    
            // Create dialog underline and bold fonts:
            CFont* pDefaultGUIFont = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT));
            ASSERT_VALID(pDefaultGUIFont);
            pDefaultGUIFont->GetLogFont(&lf);
    
            lf.lfUnderline = TRUE;
            fontDefaultGUIUnderline.CreateFontIndirect(&lf);
            lf.lfUnderline = FALSE;
    
            lf.lfWeight = FW_BOLD;
            fontDefaultGUIBold.CreateFontIndirect(&lf);
    
            UpdateTextMetrics();
    
          extern CObList afxAllToolBars;
    
            // Notify toolbars about font changing:
            for (POSITION posTlb = afxAllToolBars.GetHeadPosition(); posTlb != NULL;)
            {
                CMFCToolBar* pToolBar = (CMFCToolBar*) afxAllToolBars.GetNext(posTlb);
                ENSURE(pToolBar != NULL);
    
                if (CWnd::FromHandlePermanent(pToolBar->m_hWnd) != NULL)
                {
                    ASSERT_VALID(pToolBar);
                    pToolBar->OnGlobalFontsChanged();
                }
            }
        }
    
      };
    
      GlobalDataUnprotect *globaldata=reinterpret_cast<GlobalDataUnprotect*>(GetGlobalData());
      globaldata->UpdateScaledFonts();
    
    
      m_wndToolBar.CleanUpLockedImages();
      m_wndToolBar.FullRestoreOriginalState();
     
    }
    

    【讨论】:

      猜你喜欢
      • 2016-01-23
      • 1970-01-01
      • 2016-12-12
      • 2021-05-28
      • 2014-10-04
      • 2012-05-16
      • 1970-01-01
      • 2020-09-14
      • 1970-01-01
      相关资源
      最近更新 更多