Based on the great advice of @ekhumoro:
I found a solution to use a transparent widget and draw an animated shape on the screen that will follow the mouse cursor
The steps are:
- Create a fully transparent widget (i.e. completely hidden)
- This widget shall cover the whole screen; Similar to screenshot applications
- This widget is then configured to ignore all mouse inputs ⇒ It should allow mouse cursor to interact with all UI behind it exactly as if this widget does not exist as all (e.g. user can click through this widget)
- Then shapes/texts/animations can be drawn and moved on that transparent widget
- The coordinates of these shapes can be determined based on the mouse cursor coordinates
- The only limitation of this approach is that we not override the system cursor but we will be shown animations next to it which I believe satisfies the original use case
from PySide6 import QtCore, QtWidgets, QtGui
from PySide6.QtCore import QTimer
from PySide6.QtGui import QPainter, QFont
from PySide6.QtWidgets import QApplication
class TransparentWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(TransparentWidget, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_NoSystemBackground)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
# https://stackoverflow.com/questions/52827296/pyside2-pass-mouse-events-to-system
self.setWindowFlags(self.windowFlags()
# | QtCore.Qt.WindowTransparentForInput
| QtCore.Qt.X11BypassWindowManagerHint
| QtCore.Qt.WindowStaysOnTopHint
| QtCore.Qt.WA_MouseNoMask
| QtCore.Qt.WA_TranslucentBackground
| QtCore.Qt.FramelessWindowHint)
self.x = 0
self.y = 0
self.number = 4
def paintEvent(self, event):
print(f"paintEvent {self.x} {self.y}")
if not self.number:
return
painter = QPainter()
painter.begin(self)
font = QFont()
font.setBold(True)
font.setPixelSize(15)
painter.setFont(font)
pen = QtGui.QPen()
pen.setWidth(3)
pen.setColor(QtCore.Qt.red)
painter.setPen(pen)
painter.setBrush(QtCore.Qt.white)
painter.drawEllipse(self.x + 15, self.y + 15, 30, 30)
pen = QtGui.QPen()
pen.setColor(QtCore.Qt.black)
painter.setPen(pen)
painter.drawText(self.x + 26, self.y + 35, str(self.number))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = TransparentWidget()
w.showFullScreen()
def func():
w.x += 1
w.y += 1
w.update()
timer = QTimer()
timer.timeout.connect(func)
timer.start(10)
sys.exit(app.exec())