Skip to content

Instantly share code, notes, and snippets.

@MaurizioB
Created June 13, 2020 17:17
Show Gist options
  • Save MaurizioB/30763f4e0ce7cdf055cc2d43c6e2ceb5 to your computer and use it in GitHub Desktop.
Save MaurizioB/30763f4e0ce7cdf055cc2d43c6e2ceb5 to your computer and use it in GitHub Desktop.
Click based screen grab workaround for systems not supporting Qt mouseGrab()
from PyQt5 import QtCore, QtGui, QtWidgets
class FakeCursor(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.ToolTip)
self.setFixedSize(16, 16)
path = QtGui.QPainterPath()
path.moveTo(0, 8)
path.lineTo(6, 8)
path.moveTo(8, 0)
path.lineTo(8, 6)
path.moveTo(10, 8)
path.lineTo(16, 8)
path.moveTo(8, 10)
path.lineTo(8, 16)
stroker = QtGui.QPainterPathStroker()
stroker.setCapStyle(QtCore.Qt.FlatCap)
stroker.setWidth(2)
final = stroker.createStroke(path)
region = QtGui.QRegion()
for path in final.toFillPolygons(QtGui.QTransform()):
region |= QtGui.QRegion(path.toPolygon())
self.setMask(region)
def closeEvent(self, event):
event.ignore()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.fillRect(self.rect(), QtCore.Qt.black)
class GrabTest(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QVBoxLayout(self)
self.grabButton = QtWidgets.QPushButton('Grab')
layout.addWidget(self.grabButton)
self.grabButton.installEventFilter(self)
self.grabButton.setCheckable(True)
self.grabButton.toggled.connect(self.startGrab)
self.label = QtWidgets.QLabel('Waiting')
layout.addWidget(self.label)
self.mousePos = None
self.fakeCursor = FakeCursor()
def startGrab(self, state):
if state:
# store the cursor position
self.mousePos = QtGui.QCursor.pos()
self.grabButton.setMouseTracking(True)
self.grabButton.grabMouse()
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.BlankCursor))
self.fakeCursor.show()
self.fakeCursor.move(self.mousePos - self.fakeCursor.rect().center())
self.label.setText('Grabbing')
else:
self.grabButton.setMouseTracking(False)
self.grabButton.releaseMouse()
self.grabButton.blockSignals(True)
self.grabButton.setChecked(False)
self.grabButton.blockSignals(False)
QtGui.QCursor.setPos(self.fakeCursor.pos() + self.fakeCursor.rect().center())
self.mousePos = None
QtWidgets.QApplication.restoreOverrideCursor()
self.fakeCursor.hide()
def getPixel(self):
desktopId = QtWidgets.QApplication.desktop().winId()
screenshot = QtWidgets.QApplication.primaryScreen().grabWindow(desktopId).toImage()
pos = self.fakeCursor.pos() + self.fakeCursor.rect().center()
pixel = screenshot.pixelColor(pos)
self.label.setText('Click on {}x{}\nRGB: {}'.format(pos.x(), pos.y(), pixel.name()))
def eventFilter(self, source, event):
if source == self.grabButton:
if event.type() == QtCore.QEvent.MouseButtonPress and self.grabButton.isChecked():
self.getPixel()
elif event.type() == QtCore.QEvent.MouseButtonRelease and event.button() == QtCore.Qt.LeftButton:
self.grabButton.toggle()
return True
elif event.type() == QtCore.QEvent.MouseMove and self.mousePos is not None:
# get the difference with the previous mouse position
delta = event.globalPos() - self.mousePos
screenRect = QtCore.QRect()
for screen in QtWidgets.QApplication.screens():
screenRect |= screen.geometry()
# set the (possible) geometry using the delta
geo = self.fakeCursor.geometry().translated(delta)
# ensure that the fake cursor doesn't go outside screen margins
center = geo.center()
diff = self.fakeCursor.width() // 2
if center.x() > screenRect.right():
geo.moveRight(screenRect.right() + diff)
elif center.x() < screenRect.left():
geo.moveLeft(screenRect.left() - diff)
if center.y() > screenRect.bottom():
geo.moveBottom(screenRect.bottom() + diff)
elif center.y() < screenRect.top():
geo.moveTop(screenRect.top() - diff)
# actually move the fake cursor
self.fakeCursor.move(geo.topLeft())
# reset the cursor position back to the initial
QtGui.QCursor.setPos(self.mousePos)
return super().eventFilter(source, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = GrabTest()
w.show()
sys.exit(app.exec_())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment