DDV
DDV

Reputation: 13

PyQT manual animation of Mouse Cursor. Repeatedly change shapes needed for cursor. Works on main thread. Doesnt work on separate thread. How so?


I would like to implement changing cursor in PyQT(PySide6) application. Since didn't find animated gif support for QCursor -> decided to create my own manual animation.

So far:

  1. When change cursor manually without using multithread -> all works, but obviously user can't do anything while cursor is changing. That's why I decided to execute changing cursor code instructions from separate thread.
  2. However, when change cursor with help of multithread - > for some reason cursor only changes when Mouse moves away from widget and then moves back on widget. Why??? I need mouse cursor to change when cursor stands still on widget... Looks like I am missing some kind of an extra hidden update needed when performing change of mouse cursor not from main, but from separate thread...
import sys
import time
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *

class Window(QWidget):
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        self.label1 = QLabel("No multithread")
        self.label1.mouseReleaseEvent = self.showText1

        self.label2 = QLabel("With mulithread")
        self.label2.mouseReleaseEvent = self.showText2

        layout = QHBoxLayout(self)
        layout.addWidget(self.label1)
        layout.addWidget(self.label2)

        self.threadpool = QThreadPool()

    def showText1(self, event):
        print("Label 1 clicked")
        self.change_cursor1()

    def change_cursor1(self):
        for i in range(10):
            self.label1.setCursor(Qt.CursorShape.WaitCursor)
            print("Left label -> Cursor set to 1")
            time.sleep(1)
            self.label1.setCursor(Qt.CursorShape.CrossCursor)
            print("Left label -> Cursor set to 2")
            time.sleep(1)

    def showText2(self, event):
        print("Label 2 clicked")
        self.start_multithread_function()

    def change_cursor2(self):
        for i in range(10):
            self.label2.setCursor(Qt.CursorShape.WaitCursor)
            print("Right label -> Cursor set to 1")
            time.sleep(1)
            self.label2.setCursor(Qt.CursorShape.CrossCursor)
            print("Right label -> Cursor set to 2")
            time.sleep(1)

    def start_multithread_function(self):
        # Pass the function to execute
        worker = Worker(self.change_cursor2)
        self.threadpool.start(worker) # Execute

class Worker(QRunnable): # The container for the parallel work to perform
    def __init__(self, fn):
        super().__init__()
        self.fn = fn

    def run(self):
        print("[Worker] run()")
        self.fn()

if __name__ == "__main__": 
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec())

Upvotes: 0

Views: 63

Answers (1)

DDV
DDV

Reputation: 13

As @musicamante mentioned solution was to use QTimer class instance and bind .timeout() slot to function, that changes cursor's shapes periodically. No mulithreading necessary.

Upvotes: 0

Related Questions