code revue

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

Hallo zusammen

kann mir jemand sagen, wieso die Printausgabe zwei mal was ausgibt.
Ich habe den Eindruck, dass die Animation doppelt gestartet wird. Genau so wie die Printausgabe

Code: Alles auswählen


class AnimButton(QPushButton):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.thread = WorkerThread(self)
        self.thread.start()
        self.thread.animation.connect(self.check_animation)

        color_button = self.palette().color(QPalette.Button).getRgb()
        color_highlight = self.palette().color(QPalette.Highlight).getRgb()
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.animieren)
        self.color_flag = True

        self.color1 = QtGui.QColor(color_button[0], color_button[1], color_button[2])
        self.color2 = QtGui.QColor(color_highlight[0], color_highlight[1], color_highlight[2])

        self._animation = QtCore.QVariantAnimation(
            self,
            valueChanged=self._animate,
            startValue=0.00001,
            endValue=0.9999,
            duration=500
        )

    def check_animation(self):
        while self.animieren():
            self.timer.start()
        self.timer.stop()
        self.setStyleSheet('')

    def _animate(self, value):
        grad = "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 {color1}, stop:{value} {color2}, stop: 1.0 {color1});".format(
            color1=self.color1.name(), color2=self.color2.name(), value=value
        )
        self.setStyleSheet(grad)

    def animieren(self):
        if self.color_flag:
            self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
            self._animation.start()
        else:
            self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
            self._animation.start()
        self.color_flag = not self.color_flag


class WorkerThread(QThread):
    animation = pyqtSignal(bool)

    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)
        self._running = False
        self.animation.emit(False)
        self.animation_flag = False
        self.test = 0

    def run(self):
        self._running = True
        while self._running:
            self.doWork()

    def doWork(self):
        interval = 5000
        loop = QEventLoop()
        QTimer.singleShot(interval, loop.quit)
        loop.exec_()
        self.check_time()
        print(self.test)
        self.test += 1

    def check_time(self):
        zeit_start_animation = QTime.fromString("15:28", "hh:mm")
        zeit_stop_animation = zeit_start_animation.addSecs(30)
        now = QDateTime.currentDateTime().time()

        if now > zeit_start_animation and now < zeit_stop_animation:
            self.animation.emit(True)

Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

ich habe es ein wenig angepasst.
Die doppelausgabe bei print('d') bleibt.
Auch wenn es funktioniert, wüsste ich gerne wieso dies so ist.

Code: Alles auswählen

class AnimButton(QPushButton):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.color_flag = True
        self.worker = WorkerThread()
        self.worker.status.connect(self.handle_connection)
        self.worker.start()

        self.timer = QTimer()
        self.timer.setInterval(800)
        self.timer.timeout.connect(self.animieren)

        color_button = self.palette().color(QPalette.Button).getRgb()
        color_highlight = self.palette().color(QPalette.Highlight).getRgb()
        self.color1 = QtGui.QColor(color_button[0], color_button[1], color_button[2])
        self.color2 = QtGui.QColor(color_highlight[0], color_highlight[1], color_highlight[2])

        self._animation = QtCore.QVariantAnimation(self, valueChanged=self._animate, startValue=0.00001, endValue=0.9999, duration=500)
        self.setStyleSheet('')

    def handle_connection(self, status_blinken):
        if status_blinken:
            self.timer.start()
        else:
            self.timer.stop()
            self.setStyleSheet('')

    def _animate(self, value):
        grad = "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 {color1}, stop:{value} {color2}, stop: 1.0 {color1});".format(
            color1=self.color1.name(), color2=self.color2.name(), value=value)
        self.setStyleSheet(grad)

    def animieren(self):
        if self.color_flag:
            self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
            self._animation.start()
        else:
            self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
            self._animation.start()
        self.color_flag = not self.color_flag


class WorkerThread(QThread):
    status = pyqtSignal(bool)
    oneParameterSignal = pyqtSignal(str)

    def __init__(self, parent=None):
        super(WorkerThread, self).__init__(parent)
        self.running = False
        self.test = 0

    def run(self):
        self._running = True
        while self._running:
            time.sleep(5)
            self.check_time()

    def check_time(self):
        print('d')
        zeit_start_animation = QTime.fromString("22:12", "hh:mm")
        zeit_stop_animation = zeit_start_animation.addSecs(300)
        now = QDateTime.currentDateTime().time()
        if now > zeit_start_animation and now < zeit_stop_animation:
            self.status.emit(True)
        else:
            self.status.emit(False)

__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Thread ist komplett ueberfluessig. Dafuer reicht ein normaler Timer. Dan self._animation.start() kommt in jedem if/else-Zweig vor. Kann also *einmal* dahinter. check_time wird alle 5 Sekunden aufgerufen. Wie oft das print also passiert haengt davon ab, wie lange dein Programm laeuft.

Und zu guter Letzt: man laesst Code Revue passieren, aber man bittet um ein Code Review.
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

__deets__
danke für deine Antwort.
Ja hast recht, QThread ist echt überflüssig. Ich werde es umbauen.
Meine Frage ging dahingehend, dass (print'd') immer zwei mal gleichzeitig ausgegeben wird. D.h. alle 5s kommen zwei 'd' raus. Natürlich solange das Programm läuft.
Mir ist nicht klar, ob dieser Effekt nur bei mir ist, oder das Verhalten so normal ist. Ersteres dürfte eher zutreffen.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ohne ein geschlossenes, nachvollziehbares Beispiel ist das schwer zu sagen. Allgemein laufen Threads selbstverstaendlich nur einmal. Nicht mehrfach. Es ist also irgendetwas in deinem Code.

Das von dir verwandte Muster, Threads per Ableitung zu nutzen, wird uebrigens sehr explizit *nicht* mehr empfohlen. https://doc.qt.io/qt-5/qthread.html#details

Man sollte Worker-Objekte mit moveToThread benutzen, damit signal/slot-connections sauber funktionieren.

Ich wuerde das Thema Threads aber auch nur angehen, wenn du *musst*. Denn das ist komplex. Und bisher musst du nicht.
Antworten