如何解决在PyQt中使用QTimer vs Timer
我正在设法在GUI应用程序中用Qtimer在PyQt中使用线程进行工作。对于这样一个基础性的问题表示歉意,但是我搜索了其他类似的问题,但未能找到翔实的答案。
我正在寻求从一系列传感器中收集数据,并根据结果处理对控制结构的更改。不需要用户交互。但是,有一个控制面板和一系列状态指示器,旨在在其运行时显示。我在其他问题和示例中指出,那些使用常规time.sleep()函数的对象通常被定向为使用QTimer。
在进一步的挖掘中,我发现使用time.sleep()可以正常工作的附加代码示例。作为一个对象练习,我试图用各种QTimer调用来代替它,但都无效。
我还发现了一些引用,指出QTimer只能在QCoreApplication或类似的内部运行。但是首先使用Qtimer的原因是QApplication正在运行以支持GUI。没有它,我们将无法访问任何小部件。而且如果没有GUI,我们将不需要QTimer并可以使用time.sleep(),对吗?
我在这里想念什么?当很多其他示例似乎需要QTimer时,为什么这段代码似乎可以与time.sleep()一起正常工作?如果使用QTimer,在QApplication中如何发生?
#!/usr/bin/python3
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import RPi.GPIO as GPIO
import time
import datetime
import sys
class QCustomThread (QThread):
startLoad = pyqtSignal(int)
progressLoad = pyqtSignal(int)
statusLoad = pyqtSignal(bool)
def __init__ (self,parentQWidget = None):
super(QCustomThread,self).__init__(parentQWidget)
self.wasCanceled = False
def run (self):
# Simulate data load estimation
numberOfprogress = 100
self.startLoad.emit(numberOfprogress)
for progress in range(numberOfprogress + 1):
# Delay
time.sleep(0.1)
if not self.wasCanceled:
self.progressLoad.emit(progress)
else:
break
self.statusLoad.emit(True if progress == numberOfprogress else False)
self.exit(0)
def cancel (self):
self.wasCanceled = True
class QCustomMainWindow (QMainWindow):
def __init__ (self):
super(QCustomMainWindow,self).__init__()
# Create action with QPushButton
self.startQPushButton = QPushButton('START')
self.startQPushButton.released.connect(self.startWork)
self.setCentralWidget(self.startQPushButton)
# Create QProgressDialog
self.loadingQProgressDialog = QProgressDialog(self)
self.loadingQProgressDialog.setLabelText('Loading')
self.loadingQProgressDialog.setCancelButtonText('Cancel')
self.loadingQProgressDialog.setwindowModality(Qt.WindowModal)
def startWork (self):
myQCustomThread = QCustomThread(self)
def startLoadCallBack (numberOfprogress):
self.loadingQProgressDialog.setMinimum(0)
self.loadingQProgressDialog.setMaximum(numberOfprogress)
self.loadingQProgressDialog.show()
def progressLoadCallBack (progress):
self.loadingQProgressDialog.setValue(progress)
def statusLoadCallBack (flag):
print ('SUCCESSFUL') if flag else print ('Failed')
myQCustomThread.startLoad.connect(startLoadCallBack)
myQCustomThread.progressLoad.connect(progressLoadCallBack)
myQCustomThread.statusLoad.connect(statusLoadCallBack)
self.loadingQProgressDialog.canceled.connect(myQCustomThread.cancel)
myQCustomThread.start()
myQApplication = QApplication(sys.argv)
myQCustomMainWindow = QCustomMainWindow()
myQCustomMainWindow.show()
sys.exit(myQApplication.exec_())
解决方法
您需要考虑两个重要方面:
-
time.sleep
是 blocking ,QTimer是 not 。 - Q * Application是事件驱动的,这意味着它等待事件队列中的传入事件,并且从不应被阻止,如果不是 really 少量时间(通常是执行插槽/功能所需的时间)。
在Qt主线程中使用诸如sleep
之类的阻塞函数的问题是,它不允许Qt应用程序处理 any 事件,无论它是QApplication还是QGuiApplication或QCoreApplication。
如果在主Qt线程中调用了阻止功能(无论应用程序是否由GUI驱动),所有都将被阻止并排队,直到该功能返回为止,包括 any 信号发射和后续处理。
请注意,当涉及不同的线程时,不是有两种工作方式:如果Qt检测到发送方和接收方在不同的线程中,则将信号排队到接收方事件队列中,并且发送者线程会立即返回emit()
。
最后。如果您有一个实际上实际上需要等待一段时间的线程(通常需要在for / loop周期内才能进行处理并避免使用pass
进行不必要的CPU调用),请使用{{1} }或QThread的睡眠功能({time.sleep
代表秒,sleep()
代表毫秒,msleep()
代表微秒)。
如果不需要单独的线程(这意味着所涉及的处理不会占用CPU),则可以使用QTimer(或最终使用静态usleep()
)。
永远记住,本机python线程与QT不兼容。一旦使用了QT,计时器和Internet连接,包括其他工作在内的所有内容都必须通过QT本身的模块来完成。原因是QT在C ++中重新定义了与CPython线程不兼容的线程。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。