在任何 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)