Win32屏幕坐标转换Qt坐标

Win32消息的屏幕坐标如何转换Qt坐标

偶尔一些情况,需要将Win32 API获取到的鼠标位置转换到Qt的窗口坐标中,常见的方法是除以当前窗口的缩放(QPaintDevice::devicePixelRatioF或者其他),这样做是不准确的,只适合单屏幕

实际原始坐标是基于整个桌面系统的坐标,而Qt的坐标则是基于屏幕与缩放后的坐标。可能鼠标位置确实在窗口上,但通过QWidget::mapFromGlobal就不知道转到哪里去了。

下面是准确的办法:

int x = GET_X_LPARAM(msg->lParam);
int y = GET_Y_LPARAM(msg->lParam);
QPoint gpos(x,y);
QWindow * handle = widget->window()->windowHandle();
if(handle && handle->screen())
{
    
    
    QScreen * screen = handle->screen();
    QPoint offset = screen->geometry().topLeft();
    gpos = (gpos - offset) / screen->devicePixelRatio() + offset;
}
QPoint lpos = widget->mapFromGlobal(gpos);

实际Qt内部也是类似的逻辑,下面解释一下为什么这么做。

最终仍旧是需要使用QWidget::mapFromGlobal将全局坐标转换到指定窗口坐标,只不过该参数必须是Qt自己的全局坐标。

当用鼠标将窗口从一个屏幕A拖拽到另一个屏幕B,一开始只有一小部分在屏幕B,此时Qt的窗口坐标仍旧是基于屏幕A的,用鼠标点击屏幕B的部分,虽然鼠标在屏幕B,但坐标需要经过屏幕A的转换。也就是,将Win32的坐标以屏幕A的位置以及缩放进行换算。

需要先通过QWidget::window获取顶层窗口,因为子控件的屏幕是跟着顶层窗口的,比如弹出的对话框可以移动到其他屏幕。通过QWindow::screen获取到屏幕。(Qt5.14新增了QWidget::screen,更方便吧)

QScreen::geometry的左上角,是整个桌面区域的位置,这个坐标没有经过缩放,但Qt在该屏幕内的坐标需要经过缩放。所以先计算在该屏幕的偏移,后进行缩放,再加回去,对应:

gpos = (gpos - offset) / screen->devicePixelRatio() + offset

就这些,虽然很简单,也是折腾了很久,有时候最直接的办法就是看Qt的源码

猜你喜欢

转载自blog.csdn.net/eiilpux17/article/details/118977375
今日推荐