Signals von überall aus erreichbar machen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
jb_alvarado
User
Beiträge: 55
Registriert: Mittwoch 11. Juli 2018, 11:11

Ah, das ist wirklich cool! Und so wie ich das sehe, wird dann "send()" auch im gleichen Thread ausgeführt wie der Worker und damit queued?!
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja.
jb_alvarado
User
Beiträge: 55
Registriert: Mittwoch 11. Juli 2018, 11:11

Kann man eigentlich problemlos Funktionen im Worker aufrufen? (abgesehen von worker.work())

Ich würde gerne etwas in der Richtung umsetzten:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
from time import sleep

from PySide2.QtCore import QObject, Signal, QThread
from PySide2.QtWidgets import (QApplication, QWidget, QLabel,
                               QPushButton, QVBoxLayout)


class Worker(QObject):
    progress = Signal(str)

    def __init__(self):
        QObject.__init__(self)

        self._pause = False
        self.is_running = True
        self.count = 0

    def work(self):
        while self.is_running:
            if not self._pause:
                self.progress.emit(str(self.count))
                self.count += 1
            sleep(0.2)

    def pause(self):
        self._pause = True

    def start(self):
        self._pause = False

    def quit(self):
        self.is_running = False


def main():
    app = QApplication(sys.argv)

    worker_thread = QThread()
    worker = Worker()
    worker_thread.started.connect(worker.work)

    worker.moveToThread(worker_thread)

    def run_worker():
        if button.text() == 'Start':
            worker.start()
            if not worker_thread.isRunning():
                worker_thread.start()
            button.setText("Stop")
        else:
            button.setText("Start")
            worker.pause()

    def stop_worker():
        worker.quit()
        worker_thread.quit()
        worker_thread.wait()

    app.aboutToQuit.connect(stop_worker)

    w = QWidget()
    w.setWindowTitle('Signal Sender')

    layout = QVBoxLayout(w)
    label = QLabel(w)
    button = QPushButton(w)
    button.setText("Start")
    button.clicked.connect(run_worker)

    layout.addWidget(label)
    layout.addWidget(button)

    def update_label(text):
        label.setText(text)

    worker.progress.connect(update_label)

    w.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Ist jetzt nicht schön gelöst, ich weiß, es geht nur ums Prinzip: Also eine Möglichkeit den Worker zu pausieren. Theoretisch würde es auch gehen, ihn zu schließen und neu zu starten, aber ich dachte pausieren ist vielleicht etwas leichter.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich verstehe nicht, was deine Frage mit dem Code zu tun hat.

Wie dem auch sei: ja man kann problemlos Funktionen aus dem Worker aufrufen.

Und statt mit so einer Frickelei löst man so etwas wie schon mal besprochen mit einer Queue von Arbeitsaufträgen. Dann wird der Thread wirklich schlafen gelegt, und dann bei bedarf wieder aufgeweckt.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und noch ein Nachtrag: in dem von mir mal verlinkten anderen Beitrag hier verargumentieren wir, dass es nicht nötig ist, Threads zu startet und zu stoppen. Starte einfach einen zu Beginn der Anwendung, und lass ihn Aufträge abarbeiten. Und ein Auftrag kann dann “beende dich” sein, worauf dann natürlich mit join gewartet werden muss.
jb_alvarado
User
Beiträge: 55
Registriert: Mittwoch 11. Juli 2018, 11:11

Die Queue verwende ich auch in meinem original Script, aber da war es bis dato so, dass die Auftragsschlange irgendwann mal fertig war. Allerdings soll es die Möglichkeit geben, die Auftragsliste zu reseten, aufzufüllen und wieder neu zu starten.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn die fertig ist, dann wartet der Thread eben bis der nächste Auftrag kommt. Das entleeren könnte zb mittels eine priority queue passiere, bei der ein Abbruch-Kommando einfach eine höhere Priorität hat.
Antworten