活动期间 GUI 没有变化? (Python3.6,PyQt5)
Posted
技术标签:
【中文标题】活动期间 GUI 没有变化? (Python3.6,PyQt5)【英文标题】:No changes of GUI during event? (Python3.6, PyQt5) 【发布时间】:2019-09-09 11:13:08 【问题描述】:我正在尝试在操作期间更改按钮的样式。
当按钮被按下时,我想让它们变成蓝色,然后读取 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()
【问题讨论】:
请发帖minimal reproducible example 【参考方案1】:void QTimer::singleShot(int msec, 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()
【讨论】:
QTimer 不错,但在我的情况下 'time.sleep()' 实际上是一个读取 rfid 卡的函数,所以我不知道用户连接卡需要多长时间 【参考方案2】:安装quamash和qtawesome
#!/usr/bin/python3
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QSize
import asyncio
from quamash import QEventLoop
import qtawesome as qt
class MainScreen(QWidget):
oop = None
def __init__(self, _loop):
try:
QWidget.__init__(self)
self.loop = _loop
self.button = QPushButton("TEXT")
self.button.clicked.connect(self.synced_click)
self.button.setStyleSheet("color: black;")
self.grid = QGridLayout(self)
self.grid.addWidget(self.button)
self.show()
except Exception as e:
print(e)
def synced_click(self):
try:
asyncio.ensure_future(self.clicked(), loop=self.loop)
except Exception as e:
print('error')
print(e)
@asyncio.coroutine
async def clicked(self):
try:
spin_icon = qt.icon('fa5s.spinner', color='red', animation=qt.Spin(self.button))
self.loop.call_soon_threadsafe(self.button.setIconSize, QSize(12, 12))
self.loop.call_soon_threadsafe(self.button.setIcon, spin_icon)
self.loop.call_soon_threadsafe(self.button.setText, "progress")
self.loop.call_soon_threadsafe(self.button.setStyleSheet, "color: red;")
await asyncio.sleep(3)
tick_icon = qt.icon('fa5s.check-circle', color='blue')
self.loop.call_soon_threadsafe(self.button.setStyleSheet, "color:blue;")
self.loop.call_soon_threadsafe(self.button.setText, "done")
self.loop.call_soon_threadsafe(self.button.setIcon, tick_icon)
await asyncio.sleep(1)
except Exception as e:
print('error')
print(e)
if __name__ == "__main__":
import sys
loop = QEventLoop(QApplication(sys.argv))
asyncio.set_event_loop(loop=loop)
with loop:
window = MainScreen(loop)
loop.run_forever()
【讨论】:
以上是关于活动期间 GUI 没有变化? (Python3.6,PyQt5)的主要内容,如果未能解决你的问题,请参考以下文章