MFC CheckBox - 检索准确的正方形大小
MFC CheckBox - retrieve accurate square size
问题已被讨论 here,但人们接受了一个不准确的解决方案。我正在使用带有 BS_AUTOCHECKBOX
标志的 CButton
class。有没有一种精确的方法来确定 Windows/MFC 上带有黑色边框(带有复选标记)的正方形的大小?还有这个方块和文字之间的差距?
我明白了,差距可以这样计算(scale_factor
取决于客户端当前屏幕DPI - 100%dpi,scale_factor==1;150%dpi,scale_factor==1.5等)
std::ceil(3 * scale_factor)
我需要我的解决方案 return 基于客户端屏幕 resolution/DPI 设置的真实尺寸。 Windows 在 100% DPI 上创建此正方形 13x13px,在 125% DPI 上创建 16x16px,但在 150% 和 175% DPI 上创建 20x20px!因此,不可能仅将 13 与 scale_factor
.
相乘
这个代码
int x = GetSystemMetrics(SM_CXMENUCHECK);
int y = GetSystemMetrics(SM_CYMENUCHECK);
returns 15px on 100% DPI, 19px on 125% DPI, 如果我减去
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
which returns 2px(在每个 DPI 设置上(???)),我在 100% dpi 上得到 13px,但在 125% DPI 上得到 17px(它应该是 16)并且只有错误随着更高的 DPI 变得更大。问题是 SM_CXMENUCHECK
不代表标准 CButton
复选框。
我想避免自定义绘图。有没有办法以像素精度做到这一点(如果没有,你想出的最佳解决方案是什么)?非常感谢。
编辑:
澄清一下,我需要一个函数(或某种算法),它将 return 100% 缩放时为 13px,125% 时为 16px,150% 和 175% 时为 20px(以及任何其他可能的缩放比例)。这意味着我需要复选框的真实大小(由 Windows 根据客户端屏幕上当前设置的分辨率绘制)。
使用 GetSystemMetricsForDpi
怎么样?
引用:
Retrieves the specified system metric or system configuration setting taking into account a provided DPI.
This function returns the same result as GetSystemMetrics
but scales it according to an arbitrary DPI you provide if appropriate.
所以:
int x = GetSystemMetricsForDpi(SM_CXMENUCHECK, dpi);
int y = GetSystemMetricsForDpi(SM_CYMENUCHECK, dpi);
int xInner = GetSystemMetricsForDpi(SM_CXEDGE, dpi);
int yInner = GetSystemMetricsForDpi(SM_CYEDGE, dpi);
这些方法和其他方法已记录 (High DPI Desktop Application Development on Windows) 作为处理 DPI 问题的正确方法,并且该文章指出:
Also, in the case of Win32 programming, many Win32 APIs do not have any DPI or display context so they will only return values relative to the System DPI. It can be useful to grep through your code to look for some of these APIs and replace them with DPI-aware variants.
它甚至显示了一个例子:
#define INITIALX_96DPI 50
#define INITIALY_96DPI 50
#define INITIALWIDTH_96DPI 100
#define INITIALHEIGHT_96DPI 50
// DPI scale the position and size of the button control
void UpdateButtonLayoutForDpi(HWND hWnd)
{
int iDpi = GetDpiForWindow(hWnd);
int dpiScaledX = MulDiv(INITIALX_96DPI, iDpi, 96);
int dpiScaledY = MulDiv(INITIALY_96DPI, iDpi, 96);
int dpiScaledWidth = MulDiv(INITIALWIDTH_96DPI, iDpi, 96);
int dpiScaledHeight = MulDiv(INITIALHEIGHT_96DPI, iDpi, 96);
SetWindowPos(hWnd, hWnd, dpiScaledX, dpiScaledY, dpiScaledWidth, dpiScaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
}
请注意,根据文档,此功能仅在 Windows 10 上受支持。
您可以使用GetThemePartSize
函数。
还有一些代码:
HTHEME hTheme = ::OpenThemeData(hwnd, L"button");
SIZE szCheckBox;
HRESULT hr = GetThemePartSize(hTheme, NULL, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, NULL, TS_TRUE, &szCheckBox);
编辑:
问题已被讨论 here,但人们接受了一个不准确的解决方案。我正在使用带有 BS_AUTOCHECKBOX
标志的 CButton
class。有没有一种精确的方法来确定 Windows/MFC 上带有黑色边框(带有复选标记)的正方形的大小?还有这个方块和文字之间的差距?
我明白了,差距可以这样计算(scale_factor
取决于客户端当前屏幕DPI - 100%dpi,scale_factor==1;150%dpi,scale_factor==1.5等)
std::ceil(3 * scale_factor)
我需要我的解决方案 return 基于客户端屏幕 resolution/DPI 设置的真实尺寸。 Windows 在 100% DPI 上创建此正方形 13x13px,在 125% DPI 上创建 16x16px,但在 150% 和 175% DPI 上创建 20x20px!因此,不可能仅将 13 与 scale_factor
.
这个代码
int x = GetSystemMetrics(SM_CXMENUCHECK);
int y = GetSystemMetrics(SM_CYMENUCHECK);
returns 15px on 100% DPI, 19px on 125% DPI, 如果我减去
int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );
which returns 2px(在每个 DPI 设置上(???)),我在 100% dpi 上得到 13px,但在 125% DPI 上得到 17px(它应该是 16)并且只有错误随着更高的 DPI 变得更大。问题是 SM_CXMENUCHECK
不代表标准 CButton
复选框。
我想避免自定义绘图。有没有办法以像素精度做到这一点(如果没有,你想出的最佳解决方案是什么)?非常感谢。
编辑: 澄清一下,我需要一个函数(或某种算法),它将 return 100% 缩放时为 13px,125% 时为 16px,150% 和 175% 时为 20px(以及任何其他可能的缩放比例)。这意味着我需要复选框的真实大小(由 Windows 根据客户端屏幕上当前设置的分辨率绘制)。
使用 GetSystemMetricsForDpi
怎么样?
引用:
Retrieves the specified system metric or system configuration setting taking into account a provided DPI.
This function returns the same result as
GetSystemMetrics
but scales it according to an arbitrary DPI you provide if appropriate.
所以:
int x = GetSystemMetricsForDpi(SM_CXMENUCHECK, dpi);
int y = GetSystemMetricsForDpi(SM_CYMENUCHECK, dpi);
int xInner = GetSystemMetricsForDpi(SM_CXEDGE, dpi);
int yInner = GetSystemMetricsForDpi(SM_CYEDGE, dpi);
这些方法和其他方法已记录 (High DPI Desktop Application Development on Windows) 作为处理 DPI 问题的正确方法,并且该文章指出:
Also, in the case of Win32 programming, many Win32 APIs do not have any DPI or display context so they will only return values relative to the System DPI. It can be useful to grep through your code to look for some of these APIs and replace them with DPI-aware variants.
它甚至显示了一个例子:
#define INITIALX_96DPI 50
#define INITIALY_96DPI 50
#define INITIALWIDTH_96DPI 100
#define INITIALHEIGHT_96DPI 50
// DPI scale the position and size of the button control
void UpdateButtonLayoutForDpi(HWND hWnd)
{
int iDpi = GetDpiForWindow(hWnd);
int dpiScaledX = MulDiv(INITIALX_96DPI, iDpi, 96);
int dpiScaledY = MulDiv(INITIALY_96DPI, iDpi, 96);
int dpiScaledWidth = MulDiv(INITIALWIDTH_96DPI, iDpi, 96);
int dpiScaledHeight = MulDiv(INITIALHEIGHT_96DPI, iDpi, 96);
SetWindowPos(hWnd, hWnd, dpiScaledX, dpiScaledY, dpiScaledWidth, dpiScaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
}
请注意,根据文档,此功能仅在 Windows 10 上受支持。
您可以使用GetThemePartSize
函数。
还有一些代码:
HTHEME hTheme = ::OpenThemeData(hwnd, L"button");
SIZE szCheckBox;
HRESULT hr = GetThemePartSize(hTheme, NULL, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, NULL, TS_TRUE, &szCheckBox);
编辑: