在鼠标按下时获取屏幕像素

Posted

技术标签:

【中文标题】在鼠标按下时获取屏幕像素【英文标题】:Getting screen pixels on mouse press 【发布时间】:2020-06-13 09:29:23 【问题描述】:

当我单击屏幕上的任意位置(包括我的应用程序外部)时,我想获取鼠标坐标处的屏幕像素。

作为第一步,我截图如下:

from PyQt5 import QtWidgets, QtGui

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        w = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout()
        w.setLayout(layout)
        self.setCentralWidget(w)

        screenshot = QtWidgets.QApplication.primaryScreen().grabWindow(w.winId())

如何将我点击的坐标映射到屏幕截图?

我认为下一步是将屏幕截图转换为Pixmap 以提取像素,但我不知道如何将其与鼠标按下坐标联系起来。

【问题讨论】:

【参考方案1】:

在任何 Qt 窗口外部捕获点击事件的唯一方法是通过grabMouse()。考虑到这仅适用于 Linux:

注意:在 Windows 上,grabMouse() 仅在鼠标位于进程拥有的窗口内时才有效。在 macOS 上,grabMouse() 仅在鼠标位于该小部件的框架内时才有效。

还要注意抓鼠标可能很危险:

警告:鼠标抓取应用程序中的错误经常锁定终端。使用此函数时要格外小心,并考虑在调试时使用 -nograb 命令行选项。

只要小部件抓住鼠标,它就会捕获所有个鼠标事件(包括鼠标滚轮),无论它们的位置如何,所以它也非常重要尽快释放它。然后,就不需要映射坐标了:mousePressEvent 已经提供了基于屏幕坐标的全局位置,并且由于您已经截取了整个屏幕区域,因此这些坐标将匹配。

最后,要获取像素数据,将grabWindow提供的QPixmap转换成QImage并使用pixelColor

由于grabMouse 的平台限制,在以下示例中,我将创建一个透明窗口,充当“假”鼠标抓取器。

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        w = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout()
        w.setLayout(layout)
        self.setCentralWidget(w)
        self.grabButton = QtWidgets.QPushButton('Grab')
        layout.addWidget(self.grabButton)
        self.label = QtWidgets.QLabel('Waiting')
        layout.addWidget(self.label)
        self.grabButton.setCheckable(True)
        self.grabButton.toggled.connect(self.startGrab)

        self.desktopId = QtWidgets.QApplication.desktop().winId()

        if sys.platform != 'linux':
            self.grabber = QtWidgets.QWidget(flags=QtCore.Qt.FramelessWindowHint)
            self.grabber.setAttribute(QtCore.Qt.WA_TranslucentBackground)
            self.grabber.installEventFilter(self)
        else:
            self.grabber = None

    def grabPixel(self, event):
        buttonRect = self.grabButton.rect()
        buttonRect.translate(self.grabButton.mapToGlobal(QtCore.QPoint()))
        if event.globalPos() not in buttonRect:
            screenshot = QtWidgets.QApplication.primaryScreen().grabWindow(self.desktopId).toImage()
            pixel = screenshot.pixelColor(event.globalPos())
            self.label.setText('Click on x\nRGB: '.format(event.globalX(), event.globalY(), pixel.name()))
        self.grabButton.toggle()

    def startGrab(self, grab):
        if grab:
            if self.grabber:
                rect = QtCore.QRect()
                for screen in QtWidgets.QApplication.screens():
                    rect |= screen.geometry()
                self.grabber.setGeometry(rect)
                self.grabber.show()
            else:
                self.grabMouse()
        else:
            self.releaseMouse()

    def eventFilter(self, source, event):
        if source == self.grabber and event.type() == QtCore.QEvent.MouseButtonPress:
            self.grabPixel(event)
            self.grabber.hide()
        return super().eventFilter(source, event)

    def mousePressEvent(self, event):
        self.grabPixel(event)

【讨论】:

评论不用于扩展讨论;这个对话是moved to chat。

以上是关于在鼠标按下时获取屏幕像素的主要内容,如果未能解决你的问题,请参考以下文章

鼠标左键按下时如何更改鼠标光标?

使 Pyqt 按钮在鼠标按下而不是鼠标按下时运行功能

js面向对象开发之--元素拖拽

鼠标按下时的 JavaScript

如何在鼠标左键按下时触发循环 autoclicker c++

Twitter Bootstrap 工具提示:鼠标按下时闪烁