Qt 5,获取鼠标在屏幕中的位置

问题描述 投票:0回答:8

首先,我想提一下,我发现了相关帖子如何在 Qt 中获取屏幕上的鼠标位置? 但它对我来说“不起作用”。我做了一些测试,结果并没有达到我的预期,所以我决定发一篇新文章来谈谈我所做的测试并寻找替代解决方案。

这是我用来进行测试的代码:

QScreen *screen0 = QApplication::screens().at(0);
QScreen *screen1 = QApplication::screens().at(1);

printf("screen0 %s \n", screen0->name().toStdString().c_str());
printf("screen1 %s \n", screen1->name().toStdString().c_str());

// Position on first screen.
QPoint pos0 = QCursor::pos(screen0);

// Position on second screen.
QPoint pos1 = QCursor::pos(screen1);

printf("pos 0: %d, %d \n", pos0.x(), pos0.y());
printf("pos 1: %d, %d \n", pos1.x(), pos1.y());

// Get position without screen.
QPoint pos = QCursor::pos();
printf("pos: %d, %d \n", pos.x(), pos.y());

我所期望的是,只有一个屏幕会返回有效位置,因为光标仅在一个屏幕上,而不是在两个屏幕上。但事实并非如此,两个位置(

pos0
pos1
)具有完全相同的值,正如我们在输出中看到的:

screen0 DVI-D-0 
screen1 HDMI-0 
pos 0: 1904, 1178 
pos 1: 1904, 1178 
pos: 1904, 1178 

由于两个位置具有相同的值,因此我无法知道光标在哪个屏幕上。我不知道这是正常行为还是错误,因为文档没有说明当屏幕参数不是鼠标所在的屏幕时会发生什么。

我的想法是在鼠标所在的屏幕上打开/启动一个应用程序(由必须检测所选屏幕的 Qt 守护进程执行)。我知道使用 libX11 这是可能的,因为我过去这样做过,但我需要使用 Qt 5,并且我不知道如何使用 Qt 检测选定的屏幕。

我还使用

QApplication
QDesktopWidget
类进行了其他测试,但没有运气。

c++ qt qt5 multiscreen
8个回答
18
投票

这真的很奇怪。作为解决方法,您可以尝试以下方法:

QPoint globalCursorPos = QCursor::pos();
int mouseScreen = qApp->desktop()->screenNumber(globalCursorPos);

现在您知道光标位于哪个屏幕中。然后您可以执行以下操作找到该屏幕中的光标位置:

QRect mouseScreenGeometry = qApp->desktop()->screen(mouseScreen)->geometry();
QPoint localCursorPos = globalCursorPos - mouseScreenGeometry.topLeft();

7
投票

这似乎是一个微不足道的解决方案,但在我的 KDE 上它可以工作(我最初遇到了同样的问题)。 如果您想确定相对于小部件的本地鼠标坐标(我相信这将以设备像素为单位并且相对于小部件的左上角),您可以使用

QWidget::mapFromGlobal(QCursor::pos());

即致电

this->mapFromGlobal


2
投票

这可能对你有用吗? 它对我有用

QDesktopWidget *widget           = QApplication::desktop();
 QPosition globalCursorPosition   = widget->cursor().pos();


1
投票

要确定您所在的屏幕,您可以迭代

QGuiApplication::screens()
并检查光标是否适合屏幕的 geometry

这是一个计算本机光标位置的更复杂的示例(请注意使用高 DPI 屏幕所需的额外工作):

QPoint getNativeCursorPosition()
{
    QPoint pos = cursorPosToNative(QCursor::pos());

    // Cursor positions from Qt are calculated in a strange way, the offset to
    // the origin of the current screen is in device-independent pixels while
    // the origin itself is native!

    for (QScreen *screen : QGuiApplication::screens()) {
        QRect screenRect = screen->geometry();
        if (screenRect.contains(pos)) {
            QPoint origin = screenRect.topLeft();
            return origin + (pos - origin) * screen->devicePixelRatio();
        }
    }

    // should not happen, but try to find a good fallback.
    return pos * qApp->devicePixelRatio();
}

0
投票

看来这不能用 Qt 来完成(至少在我的系统配置中是这样,而且似乎在 Windows 中也是如此),我决定使用 libX11 来实现该实现,它的工作原理就像魅力一样。

这不是一个理想的解决方案,因为我只想使用 Qt,但它有效。


0
投票

通过 QML,您可以使用屏幕 QML 类型的属性:

Screen.virtualX :虚拟桌面内屏幕的 x 坐标。

Screen.virtualY :虚拟桌面内屏幕的 y 坐标。

import QtQuick 2.6
import QtQuick.Window 2.2

console.log("Pos x : " + Screen.virtualX )
console.log("Pos y : " + Screen.virtualY )

这适用于单屏幕以及多显示器系统。


0
投票

我最近在 Qt 5.15 + Windows + 混合 DPI 上遇到了类似的问题,需要在 QWindow 对象中解决此问题。

QScreen* primaryScreen = QGuiApplication::primaryScreen();
QScreen* thisScreen = screen();
qreal primaryDPR = primaryScreen->devicePixelRatio();
qreal thisDPR = thisScreen->devicePixelRatio();
qreal scale = thisDPR / primaryDPR;
QPoint pos = scale  * QCursor::pos();

我不确定这是否适用于其他平台。


0
投票

我会这样做:

  1. 获取包含鼠标的屏幕

    auto *screen = QGuiApplication::screenAt(QCursor::pos());
    

    适用于 Qt5。 参见

    screenAt
    QGuiApplication::screenAt
    实施

  2. 获取鼠标在该屏幕上的位置

    auto mousePos = QCursor::pos() - screen->geometry.topLeft();
    
© www.soinside.com 2019 - 2024. All rights reserved.