简体   繁体   中英

How to make MFC CToolbar button sizes more consistent for high DPI aware applications on Windows 7/10

I'm working on a old C++ MFC app using CToolbar for its toolbar compiling with Visual Studio 2017.

When the application is set to 'High DPI Aware' in the manifest settings (Project/Properties/Configuration Properties/Manifest Tool/Input and Output/DPI Awareness) as expected at runtime the toolbar seems to scale with the main monitor DPI scaling factor on Windows 10 and is about about half as tall as the menu bar text.

On Windows 7 this scaling doesn't seem to happen. The toolbar is about the same height as the menu bar text at 100% DPI and stays the same pixel height at different DPI settings. Using or not using XP style DPI scaling makes no difference.

Is the underlying toolbar common control on Windows 7 fundamentally less capable of high DPI scaling? Is there an effective way to adjust this and make the Windows 7 and Windows 10 toolbar sizes more consistent?

I can reproduce the same issue running the DOCKTOOL MFC sample recompiled with High DPI Awareness in the manifest using Visual Studio 2017.

https://github.com/Microsoft/VCSamples/tree/master/VC2010Samples/MFC/general/docktool

// code excerpts from DOCKTOOL below:
class CMainFrame : public CFrameWnd

{
protected: // create from serialization only
    CMainFrame();
    DECLARE_DYNCREATE(CMainFrame)

    CToolBar    m_wndMainBar;

// Generated message map functions
protected:
    //{{AFX_MSG(CMainFrame)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
//....


if (!m_wndMainBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_SIZE_DYNAMIC |
            CBRS_TOP | ((m_bToolTips)?(CBRS_TOOLTIPS | CBRS_FLYBY):0), IDW_MAIN_BAR) ||
        !m_wndMainBar.LoadBitmap(
            (m_bColor)?IDR_COLOR_MAINBAR:IDR_MONO_MAINBAR) ||
        !m_wndMainBar.SetButtons(MainButtons, sizeof(MainButtons)/sizeof(UINT)))
    {
        TRACE0("Failed to create mainbar\n");
        return -1;      // fail to create
    }

Use CToolBar::SetSizes to assign a new button size and bitmap size. You have to know the dimensions of the bitmap used in resource.

The example below assumes the bitmap is 16 x 15 pixels. This will make the buttons bigger based on the DPI settings (but it won't make the bitmap bigger)

//get DPI scaling 
double fx = GetSystemMetrics(SM_CXSMICON) / 16.0f;
double fy = GetSystemMetrics(SM_CYSMICON) / 16.0f;
if(fx < 1) fx = 1;
if(fy < 1) fy = 1;

CRect temp;
m_wndMainBar.GetItemRect(0, &temp);
temp.MoveToXY(0, 0);
temp.right = int(temp.right * fx);
temp.bottom = int(temp.bottom * fy);

CSize bmp_size(16, 15);
m_wndMainBar.SetSizes(temp.Size(), bmp_size);

To make the bitmap bigger, you have to go to resource editor and create a separate bitmap for each scaling.

For example, for 125% DPI scaling, create a bitmap 25% larger and use bmp_size(20, 18) instead of bmp_size(16, 15)

This method can become very complicated, therefore you may consider using icons with LoadIconWithScaleDown . That way you create a large icon, for lets say 150% DPI, and use the same icon for 125% and 100% DPI scaling.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM