GUI mit Qt5 - Endlosschleife in Thread durch Button beenden

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
salu44
User
Beiträge: 6
Registriert: Sonntag 22. Dezember 2019, 17:59

Hallo zusammen,

ich habe folgendes Problem:
Parallel zu einem GUI läuft in einer Thread-Klasse eine Endlosschleife. Durch Drücken eines Buttons auf der GUI soll diese Endlosschleife beendet werden.

Meine Frage:
Wie kann ich durch einen Tastendruck auf den Thread zugreifen und die Endlosschleife beenden?

Ich wäre sehr dankbar für jeden Tipp:)
Grüße


Hier mein Beispielcode:

Code: Alles auswählen

import sys
from PyQt5.QtWidgets import QWidget, QAction, QMenu, QApplication, QMessageBox as QMB, QPushButton, QMainWindow
from PyQt5 import QtCore, QtWidgets
from PyQt5 import uic
import time
from PyQt5.QtCore import QThread, pyqtSignal, QObject



class Thread(QThread):
    # Create a counter thread

    change_text_btn = pyqtSignal(str)
    # text_status_Fehler_val = pyqtSignal(int, int)
    # text_status_Warnung_val = pyqtSignal(int, int)
    # text_status_val = pyqtSignal(int)
    # text_status = pyqtSignal(str)
    change_color_start_btn = pyqtSignal(str)
    # color_status_box = pyqtSignal(int, int)

    def __init__(self, *args):
        super(Thread, self).__init__()

        # Store constructor arguments (re-used for processing)

        self.args = args
        print(self.args[0])

    def run(self):

        x = 0
        z = 0

        endtime = time.time() + (self.args[0]/4) * 60


        while time.time() < endtime:
            x += 1
            print(x)
            time.sleep(0.01)


        time.sleep(0.5)
        self.change_text_btn.emit('Dauermessung läuft...')
        self.change_color_start_btn.emit('g')

        # Schleife soll durch Tastendruck beendet werden
        while 1:
            z+=1
            print(z)
            time.sleep(0.01)


class MainWindow(QMainWindow):

    def __init__(self):

        super().__init__()
        uic.loadUi('test_V1.ui', self)

        self.button_Einstellungen_uebernehmen.clicked.connect(self.Einstellungen_uebernehmen)
        self.button_start.clicked.connect(self.Messung_starten)
        self.status.clear()


    def Einstellungen_uebernehmen(self):
        '''Diese Funktion liest die Einstellungswerte vom GUI ein.'''

        self.einlaufzeit = int(self.comboBox_einlaufzeit.currentText())
        print(self.einlaufzeit)

        self.button_Einstellungen_uebernehmen.setStyleSheet("background-color: rgb(0,220,0)")


    def Messung_starten(self):

        self.thread = Thread(self.einlaufzeit)
        self.thread.change_text_btn.connect(self.setText_btn)
        # self.thread.text_status_Fehler_val.connect(self.setStatus_Fehler)
        # self.thread.text_status_Warnung_val.connect(self.setStatus_Warnung)
        # self.thread.text_status_val.connect(self.setStatus)
        # self.thread.text_status.connect(self.setText_Status)
        self.thread.change_color_start_btn.connect(self.color_start_btn)
        #self.thread.color_status_box.connect(self.color_checkbox)
        self.thread.start()


    def setText_btn(self, text_a):
        self.button_start.setText(text_a)


    def color_start_btn(self, color_a):
        if color_a == 'o':
            self.button_start.setStyleSheet("background-color: rgb(255,165,79)")
        elif color_a == 'g':
            self.button_start.setStyleSheet("background-color: rgb(0,220,0)")


    def closeEvent(self, ev):

        r = QMB.question(self, "Abfrage", "beenden?",
                         QMB.Yes | QMB.No, QMB.No)
        if r == QMB.Yes:
            ev.accept()
        else:
            ev.ignore()



def main():

    app = QApplication(sys.argv)  # A new instance of QApplication
    form = MainWindow()  # We set the form to be our ExampleApp (design)
    form.show()  # Show the form
    app.exec_()  # and execute the app


if __name__ == '__main__':  # if we're running file directly and not importing it
    main()  # run the main function
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das gezeigte Muster durch Ableitung von threads ist veraltet und ungeschickt. Und beraubt dich der Möglichkeit, den Qt-Eigenen Mechanismus von Signal/slots wie er von mir zb hier viewtopic.php?t=44250&start=15 dargestellt wird zu nutzen. Und das ist auch der Weg, wie man Hintergrund-Threads etwas mitteilt.
salu44
User
Beiträge: 6
Registriert: Sonntag 22. Dezember 2019, 17:59

Vielen Dank für die Antwort!
Ich habe es jetzt so gelöst, dass die Schleife so lange läuft bis eine globale Variable x geändert wird. Ist vielleicht nicht die wirklich schön, aber funktioniert.
Grüße
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@salu44: Das ist in der Tat nicht schön und ich sehe da auch gar keinen Grund für. Um einen QThread zu unterbrechen gibt es extra `requestInterruption()` und `isInterruptionRequestet()`.

Attrbute sollten alle nach Ablauf der `__init__()`-Methode angelegt werden und nicht irgendwann später noch hinzugefügt werden. Das macht Code nur unnötig unübersichtlich. Wenn man `thread` in der `__init__()` schon mit `None` initialisiert kann man auch testen ob bereits ein Thread läuft oder nicht. Man darf dann auch nicht vergessen nach Ende des Threads `thread` wieder an `None` zu binden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten