首页 > 解决方案 > 活动期间 GUI 没有变化?(Python3.6、PyQt5)

问题描述

我正在尝试在操作期间更改按钮的样式。

当按下按钮时,我想让它们变成蓝色,然后读取 rfid 卡,然后通过 ID 将按钮的颜色更改为绿色或红色(在代码中只是红色以便更容易)。

问题在于将按钮样式更改为蓝色无济于事(绿色和红色效果很好)。它正在等待完成“clicked()”方法吗?如何告诉 PyQt5 “现在就做!” ?

编辑:我将伪代码修改为可重现的示例。

#!/usr/bin/python3
import sys
import time
from PyQt5.QtWidgets import *

class MainScreen(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.button = QPushButton("TEXT")
        self.button.clicked.connect(self.clicked)
        self.changeButtonColor("black")  # set default style
        self.grid = QGridLayout(self)
        self.grid.addWidget(self.button)
        self.show()

    def changeButtonColor(self, color):
        self.button.setStyleSheet("QPushButton{ \
                color: "+color+"; font: bold 18px;}")

    def clicked(self):
        self.changeButtonColor("blue")  # nothing happening (this is my problem!)
        uid = self.readCard()  # reading ID from rfid card
        self.changeButtonColor("red")

    def readCard(self):
        #return rfid.read() # in real case
        time.sleep(2)
        return "12345678"

def main():
    app = QApplication(sys.argv)
    window = MainScreen()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

标签: pythonuser-interfaceeventspyqt5

解决方案


void QTimer::singleShot(int ms, const QObject *receiver, const char *member)

这个静态函数在给定的时间间隔后调用一个槽。

使用此函数非常方便,因为您无需费心使用 timerEvent 或创建本地 QTimer 对象。

import sys
import time
from PyQt5.QtWidgets import *
from PyQt5 import QtCore

class MainScreen(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.button = QPushButton("TEXT")
        self.button.clicked.connect(self.clicked)
        self.changeButtonColor("black")             
        self.grid = QGridLayout(self)
        self.grid.addWidget(self.button)
        self.show()

    def changeButtonColor(self, color):
        self.button.setStyleSheet("QPushButton{ \
                color: "+color+"; font: bold 18px;}")

    def clicked(self):
        self.changeButtonColor("blue")  # nothing happening (this is my problem!)
#        time.sleep(2)                  # reading ID from rfid card
#        self.changeButtonColor("red")
        QtCore.QTimer.singleShot(2000, lambda: self.changeButtonColor("red"))             # <---

def main():
    app = QApplication(sys.argv)
    window = MainScreen()
    sys.exit(app.exec_())

在此处输入图像描述


更新

import sys
import time
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import *

class Worker(QtCore.QObject):                              # +++

    started  = QtCore.pyqtSignal()
    finished = QtCore.pyqtSignal()
    data     = QtCore.pyqtSignal(str)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.running = False
        self.stop = 5

    @QtCore.pyqtSlot()
    def read_data_from_sensor(self):
        self.started.emit()
        time.sleep(1)                                  # We simulate the blocking process
        while self.running and self.stop:
            dt  = time.strftime("%Y-%m-%d %H:%M:%S")
            self.data.emit(dt)
            time.sleep(1)                              # We simulate the blocking process
            self.stop -= 1
            
        self.finished.emit()


class MainScreen(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.button = QPushButton("TEXT Start")
        self.button.clicked.connect(self.clicked)
        self.changeButtonColor("black") 
        
        self.label_data = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignCenter)
        self.label_data.setText('Pending')
        
        self.grid = QGridLayout(self)
        self.grid.addWidget(self.label_data)
        self.grid.addWidget(self.button)
        self.show()
### vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv       
        self._worker = Worker()
        self._worker.started.connect(self.on_started)
        self._worker.finished.connect(self.on_finished)
        self._worker.data.connect(self.update_label)

        self._thread = QtCore.QThread(self)
        self._thread.start()
        self._worker.moveToThread(self._thread)      

    @QtCore.pyqtSlot()
    def on_started(self):
        self.label_data.setText("Start to read")
        self.button.setText("TEXT Stop")
        self.button.setEnabled(True) 
        self._worker.stop = 5
        
    @QtCore.pyqtSlot()
    def on_finished(self):
        self.label_data.setText("Pending")
        self.button.setText("TEXT Start")
        self.button.setEnabled(True)
        self.changeButtonColor("red")                      # <---
        self._worker.running = False
        self._worker.stop = 5
        
    @QtCore.pyqtSlot(str)
    def update_label(self, data):
        self.label_data.setText(data)
### ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        

    def changeButtonColor(self, color):
        self.button.setStyleSheet("QPushButton{ \
                color: "+color+"; font: bold 18px;}")

    def clicked(self):
        self.changeButtonColor("blue")  # nothing happening (this is my problem!)
#        time.sleep(2)                  # reading ID from rfid card
#        self.changeButtonColor("red")
#        QtCore.QTimer.singleShot(2000, lambda: self.changeButtonColor("red"))             # <---

### vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv       
        if self._worker.running:
            self._worker.running = False
        else:
            self._worker.running = True
            QtCore.QTimer.singleShot(0, self._worker.read_data_from_sensor)
        self.button.setEnabled(False)        
### ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^       
        

def main():
    app = QApplication(sys.argv)
    window = MainScreen()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

在此处输入图像描述


推荐阅读