Créer un fil d'arrière-plan de cette façon

 def listenReply(self):
        while self.SOCK_LISTENING:
            fromNodeRED = self.nodeRED_sock.recv(1024).decode()
            if fromNodeRED=="closeDoor":
                self.door_closed()

 ...

    self.listenThread = Thread(target=self.listenReply, daemon=True)
    self.SOCK_LISTENING = True
    self.listenThread.start()

Mais self.door_closed () a quelques éléments d'interface utilisateur, donc ce n'est pas bon. Comment appeler self.door_closed dans le thread principal à la place?

0
GeneCode 5 oct. 2020 à 10:06

3 réponses

Meilleure réponse

Je l'ai résolu moi-même en utilisant le signal et les slots du PyQt.

class App(QWidget):

    socketSignal = QtCore.pyqtSignal(object) #must be defined in class level

    # BG THREAD
    def listenReply(self):
        while self.SOCK_LISTENING:
            fromNodeRED = self.nodeRED_sock.recv(1024).decode()
            print(fromNodeRED)
            self.socketSignal.emit(fromNodeRED)

.... quelque part dans l'init du thread principal:

    self.socketSignal.connect(self.executeOnMain)
    self.listenThread = Thread(target=self.listenReply, daemon=True)
    self.SOCK_LISTENING = True
    self.listenThread.start()
       

....

def executeOnMain(self, data):
     if data=="closeDoor":
            self.door_closed() # a method that changes the UI

Fonctionne très bien pour moi.

0
GeneCode 8 oct. 2020 à 02:08

Vous pouvez utiliser threading.Event() et le définir chaque fois que vous recevez "closeDoor" de recv.

Par exemple:

g_should_close_door = threading.Event()

def listenReply(self):
    while self.SOCK_LISTENING:
        fromNodeRED = self.nodeRED_sock.recv(1024).decode()
        if fromNodeRED=="closeDoor":
            g_should_close_door.set()

    ...

    self.listenThread = Thread(target=self.listenReply, daemon=True)
    self.SOCK_LISTENING = True
    self.listenThread.start()

    if g_should_close_door.is_set():
        door_closed() 
        g_should_close_door.clear() 
1
SpiderPig1297 5 oct. 2020 à 08:59

Une chose à garder à l'esprit est que chaque thread est une exécution séquentielle d'un seul flux de code, à partir de la fonction sur laquelle le thread a été démarré. Cela n'a pas beaucoup de sens d'exécuter simplement quelque chose sur un thread existant, car ce thread exécute déjà quelque chose et cela perturberait son flux actuel.

Cependant, il est assez facile de communiquer entre les threads et il est possible d'implémenter le code d'un thread de manière à ce qu'il reçoive simplement des fonctions / événements d'autres threads qui lui disent quoi faire. Ceci est communément appelé une boucle d'événements.

Par exemple, votre fil de discussion principal pourrait ressembler à ceci

from queue import Queue

tasks = Queue()

def event_loop():
   while True:
       next_task = tasks.get()
       print('Executing function {} on main thread'.format(next_task))
       next_task()

Dans vos autres threads, vous pouvez demander au thread principal d'exécuter une fonction en l'ajoutant simplement à la file d'attente tasks:

 def listenReply(self):
    while self.SOCK_LISTENING:
        fromNodeRED = self.nodeRED_sock.recv(1024).decode()
        if fromNodeRED=="closeDoor":
            tasks.put(door_closed)
1
Hadi Zolfaghari 5 oct. 2020 à 09:29