在不同的 DPI 中使用 GetWindowRect 的坐标错误

2022-01-12 00:00:00 rect winapi c++ mfc dpi

我想在我的 MFC 程序中捕获组件的坐标.

I want to capture the coordinate of components in my MFC program.

现在我可以使用 GetWindowRect 完美地完成这个任务.但是,当我将 windows dpi 设置为 150% (120 dpi) 时,我会从 GetWindowRect 获得不同的坐标.

Now I can perfectly complete this by using GetWindowRect. However, when I set my windows dpi to 150% (120 dpi), I get different coordinates from GetWindowRect.

因此,我研究了一些将新坐标转换为默认 dpi (96 dpi) 的方法.

Therefore, I survey some method to convert new coordinates to that in default dpi (96 dpi).

最后,我尝试的时候发现有一些错误:

Finally, I found there was some error when I tried:

Rect.top = Rect.top * (DEFAULT_DPIY / CURRENT_DPIY);
Rect.left = Rect.left * (DEFAULT_DPIX / CURRENT_DPIX);

转换后的值非常接近,但不相等.

The converted value is very close, but not equal.

有什么方法可以无误地转换吗?

Is there any method to convert it without error ?

推荐答案

你的程序受制于 DPI 虚拟化.处理这个问题的正确方法是让您的程序具有高 DPI 意识,但这很可能涉及比您准备尝试的更多的更改.

Your program is subject to DPI virtualization. The right way to deal with this is to make your program high DPI aware but that may well involve more changes than you are prepared to attempt.

如果您不想解决高 DPI 意识,那么您至少可以让您的算术变得更好.您的代码使用整数除法.但这将是不准确的.为了尽量减少这种不准确性,您应该在乘法之后执行除法:

If being high DPI aware is not something you wish to tackle, then you can at least make your arithmetic better. Your code uses integer divide. But that's going to be inaccurate. In order to minimise that inaccuracy you should perform the division after the multiplication:

Rect.top = (Rect.top * DEFAULT_DPIY) / CURRENT_DPIY;
Rect.left = (Rect.left * DEFAULT_DPIX) / CURRENT_DPIX;

当然,这里的括号可以省略而不改变意思,但我认为在这种情况下明确说明操作的顺序是很好的.

Of course, the parentheses could be omitted here without changing the meaning, but I think it's nice to be explicit about the ordering of the operations in this case.

另一种选择是使用 MulDiv:

Another option would be to use MulDiv:

Rect.top = MulDiv(Rect.top, DEFAULT_DPIY, CURRENT_DPIY);
Rect.left = MulDiv(Rect.left, DEFAULT_DPIX, CURRENT_DPIX);

相关文章