Seite 1 von 2

Re: Signals von überall aus erreichbar machen

Verfasst: Freitag 26. April 2019, 15:32
von jb_alvarado
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?!

Re: Signals von überall aus erreichbar machen

Verfasst: Freitag 26. April 2019, 15:44
von __deets__
Ja.

Re: Signals von überall aus erreichbar machen

Verfasst: Sonntag 28. April 2019, 13:23
von jb_alvarado
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.

Re: Signals von überall aus erreichbar machen

Verfasst: Sonntag 28. April 2019, 13:26
von __deets__
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.

Re: Signals von überall aus erreichbar machen

Verfasst: Sonntag 28. April 2019, 13:40
von __deets__
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.

Re: Signals von überall aus erreichbar machen

Verfasst: Sonntag 28. April 2019, 14:11
von jb_alvarado
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.

Re: Signals von überall aus erreichbar machen

Verfasst: Sonntag 28. April 2019, 15:08
von __deets__
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.