How to run widgets that use Qtimer from a different Thread?

Asked

Viewed 39 times

0

I created an application where the user presses a certain key combination - using the package pynput - and a message from a "Qtoaster" appears on screen. Below is an example code:

from pynput import keyboard
from toaster import show_message         # Toaster criado a partir de um QFrame com QTimer
from PyQt5.QtWidgets import QApplication

def func():
    show_message("Executado com sucesso.")

app = QApplication([])
thread = keyboard.GlobalHotKeys({"<ctrl>+<alt>+z": func})
thread.start()
app.exec_()

The problem is that whenever I run the code and press the keys, the QToaster crashes and the following error message is printed on the console:

QObject::startTimer: Timers can only be used with threads started with QThread

I know this error is being generated because Qtoaster is not created on main thread. My question is: how to execute the QToaster from another Thread without it locking, from a sign or something? In Pyqt5 there is some feature that allows me to execute a code of a different Thread from a signal, as in the code below?

executor = Executor()
executor.set_function(lambda: show_message("Executado com sucesso."))

thread = keyboard.GlobalHotKeys({"<ctrl>+<alt>+z": executor.start})
thread.start()

1 answer

0


I honestly do not know if that is the best solution to this problem, but it is still a solution. Yes, there is a feature in Pyqt5 to create signals and it is the class QtCore.pyqtSignal.

Through it, you can define a function to be executed - using the method connect - and thread the method emit which, when executed, will send a signal to perform the function you connected.

The problem is that to use the pyqtSignal, you must follow some rules:

  1. You can only use it within a class you inherit from QCore.QObject.
  2. The object of pyqtSignal should be created as a class attribute.

That said, your code would look like this:

from pynput import keyboard
from toaster import show_message  
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QApplication
import sys

def func():
    show_message("Executado com sucesso.")

class MyClass(QObject):   # Não estou tão criativo hoje para dar nome de classe, sorry ;)
    signal = pyqtSignal()

app = QApplication([])

myObject = MyClass()
myObject.signal.connect(func)

thread = keyboard.GlobalHotKeys({"<ctrl>+<alt>+z": myObject.signal.emit})
thread.start()
app.exec_()

Browser other questions tagged

You are not signed in. Login or sign up in order to post.