【问题标题】:MFC CheckBox - retrieve accurate square sizeMFC CheckBox - 检索准确的正方形大小
【发布时间】:2021-06-28 09:26:51
【问题描述】:

该问题已在here 进行过讨论,但人们选择了一个不准确的解决方案。我正在使用带有BS_AUTOCHECKBOX 标志的CButton 类。有没有一种精确的方法来确定 Windows/MFC 上带有黑色边框(带有复选标记)的正方形的大小?还有这个方块和文字的差距?

我意识到,差距可以这样计算(scale_factor取决于客户端当前屏幕DPI - 100%dpi,scale_factor==1;150%dpi,scale_factor==1.5等)

std::ceil(3 * scale_factor)

我需要我的解决方案根据客户端的屏幕分辨率/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);

在 100% DPI 时返回 15px,在 125% DPI 时返回 19px,如果我减去

int xInner = GetSystemMetrics( SM_CXEDGE );
int yInner = GetSystemMetrics( SM_CYEDGE );

它返回 2px(在每个 DPI 设置 (???) 上),我在 100% dpi 上得到 13px,但在 125% DPI 上得到 17px(应该是 16),并且错误只会随着更高的 DPI 而变大。问题是SM_CXMENUCHECK 不代表标准的CButton 复选框。

我想避免自定义绘图。有没有办法用像素精度来做到这一点(如果没有,你想出的最好的解决方案是什么)?非常感谢。

编辑: 澄清一下,我需要一个函数(或某种算法),它将在 100% 缩放时返回 13px,在 125% 时返回 16px,在 150% 和 175% 时返回 20px(以及任何其他可能的缩放)。这意味着我需要一个真实大小的复选框(由 Windows 根据当前在客户端屏幕上设置的分辨率绘制)。

【问题讨论】:

  • 附带问题:它必须是一个按钮吗?也可以映射到点击事件的标准复选框呢?
  • 这里有一些关于主题的答案值得调查:stackoverflow.com/questions/22689311/get-the-size-of-checkbox
  • 我不知道如何在 MFC 中以另一种方式创建“标准复选框”,而不是通过创建带有复选框标志的 CButton。这些主题看起来很有希望,谢谢!我试试看。
  • 我需要从代码中动态创建控件。无论如何,问题已经得到解答,感谢您的帮助。

标签: windows winapi checkbox mfc win32gui


【解决方案1】:

你可以使用GetThemePartSize函数。

还有一些代码:

HTHEME hTheme = ::OpenThemeData(hwnd, L"button");
SIZE szCheckBox;
HRESULT hr = GetThemePartSize(hTheme, NULL, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, NULL, TS_TRUE, &szCheckBox);

编辑:

回复相关:Determine checkbox square size [MFC]

【讨论】:

  • 我在对他的问题的评论中链接到该代码。 ?
  • @mrdecompilator 你好,这个答案能解决你的问题吗?如果您有任何问题,请随时告诉我,如果有帮助,请接受。
  • 是的,我还将链接附加到给出正确大小的答案的链接 - stackoverflow.com/a/59376905/13566062
【解决方案2】:

使用GetSystemMetricsForDpi 怎么样?

引用:

根据提供的 DPI 检索指定的系统指标或系统配置设置。

此函数返回与GetSystemMetrics 相同的结果,但会根据您提供的任意 DPI(如果合适)对其进行缩放。

所以:

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 问题的正确方法,该文章指出:

此外,在 Win32 编程的情况下,许多 Win32 API 没有任何 DPI 或显示上下文,因此它们只会返回与系统 DPI 相关的值。使用 grep 搜索您的代码以查找其中一些 API 并将其替换为可识别 DPI 的变体会很有用。

它甚至显示了一个例子:

#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 上受支持。

【讨论】:

  • 感谢您的建议。请检查原始帖子的编辑。我不想指定 DPI,我想要一个函数根据客户端屏幕上当前设置的 DPI 返回复选框的真实大小。
  • 但这就是它的作用。这显然是 MS 为完成这项工作所提供的。您有多个显示器和多种 DPI 可能性。您计算出您正在使用的 DPI 值并将其传递给函数。它将返回正确的比例值。哪个回答了您提出的问题。
  • 好的,那么我应该将哪些参数传递给该函数,以便它在 150% DPI 时返回 20px,在 DPI 设置为 175% 时返回 20px?我认为此函数不会为标准复选框返回正确的值,因为 SM_CXMENUCHECK 不像我附加的屏幕截图中那样表示标准复选框。这是菜单中的复选标记,是一个完全不同的元素。
  • 我无法自行测试和调试。我的建议是首先查看 Microsoft 文章并测试在尝试使用他们用于计算 DPI 等的方法后得到什么结果。它可能会让你回到同一个地方,在这种情况下,它更像是一个 Visual Studio 查询您应该通过“帮助”菜单上的软件系统将其定向到 Microsoft。但请先尝试,因为他们只会要求您提供他们可以测试的示例项目。
  • 嗯,对我来说,该功能完全可以正常工作,至少对于 96、120、144 DPI。我已经提到了这个问题,这个功能以及我原来的一个与你给它的元素一起工作。在我们的例子中,它是 SM_CXMENUCHECK,这不是我感兴趣的元素。必须有另一种方式,不过感谢您的建议。
猜你喜欢
  • 1970-01-01
  • 2018-05-18
  • 2014-05-02
  • 1970-01-01
  • 2016-04-20
  • 2020-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多