[英]PyQt5 threading GUI does not work
我正在嘗試加載一些需要30秒鍾以上的數據。 在這段時間內,我希望用戶看到一個小的GUI,上面寫着“正在加載。”,然后是“正在加載...”,然后是“正在加載...”,然后是“正在加載”。 等。我已經讀了一些書,我想我必須把它放在一個單獨的線程中。 我發現有人遇到類似問題,暗示解決方案在正確的位置:
t = threading.Thread(target=self.test)
t.daemon = True
t.start()
在文件的下部,我具有測試功能
def test(self):
tmp = InfoMessage()
while True:
print(1)
和InfoMessage函數
from PyQt5 import uic, QtCore, QtGui, QtWidgets
import sys
class InfoMessage(QtWidgets.QDialog):
def __init__(self, msg='Loading ', parent=None):
try:
super(InfoMessage, self).__init__(parent)
uic.loadUi('ui files/InfoMessage.ui',self)
self.setWindowTitle(' ')
self.o_msg = msg
self.msg = msg
self.info_label.setText(msg)
self.val = 0
self.timer = QtCore.QTimer()
self.timer.setInterval(500)
self.timer.timeout.connect(self.update_message)
self.timer.start()
self.show()
except BaseException as e:
print(str(e))
def update_message(self):
self.val += 1
self.msg += '.'
if self.val < 20:
self.info_label.setText(self.msg)
else:
self.val = 0
self.msg = self.o_msg
QtWidgets.QApplication.processEvents()
def main():
app = QtWidgets.QApplication(sys.argv) # A new instance of QApplication
form = InfoMessage('Loading ') # We set the form to be our MainWindow (design)
app.exec_() # and execute the app
if __name__ == '__main__': # if we're running file directly and not importing it
main() # run the main function
當我單獨運行InfoMessage函數時,它可以正常工作,並且每0.5秒更新一次,等等。但是,當我將此樂趣作為加載文件的一部分時,GUI為空白並且顯示不正確。 我知道由於其中存在打印語句,它停留在測試功能中。
有人可以指出我正確的方向嗎? 我想我缺少幾個步驟。
首先,有兩種方法可以做到這一點。 一種方法是使用Python內置的線程模塊。 另一種方法是使用QThread庫,該庫與PyQT集成得多。 通常,我建議使用QThread在PyQt中進行線程化。 但是僅當與PyQt有任何交互時才需要QThread。
其次,我從InfoMessage
刪除了processEvents()
,因為在您的特定情況下它沒有任何作用。
最后,將您的線程設置為守護程序意味着您的線程將永遠不會停止。 對於大多數功能而言並非如此。
import sys
import threading
import time
from PyQt5 import uic, QtCore, QtWidgets
from PyQt5.QtCore import QThread
def long_task(limit=None, callback=None):
"""
Any long running task that does not interact with the GUI.
For instance, external libraries, opening files etc..
"""
for i in range(limit):
time.sleep(1)
print(i)
if callback is not None:
callback.loading_stop()
class LongRunning(QThread):
"""
This class is not required if you're using the builtin
version of threading.
"""
def __init__(self, limit):
super().__init__()
self.limit = limit
def run(self):
"""This overrides a default run function."""
long_task(self.limit)
class InfoMessage(QtWidgets.QDialog):
def __init__(self, msg='Loading ', parent=None):
super(InfoMessage, self).__init__(parent)
uic.loadUi('loading.ui', self)
# Initialize Values
self.o_msg = msg
self.msg = msg
self.val = 0
self.info_label.setText(msg)
self.show()
self.timer = QtCore.QTimer()
self.timer.setInterval(500)
self.timer.timeout.connect(self.update_message)
self.timer.start()
def update_message(self):
self.val += 1
self.msg += '.'
if self.val < 20:
self.info_label.setText(self.msg)
else:
self.val = 0
self.msg = self.o_msg
def loading_stop(self):
self.timer.stop()
self.info_label.setText("Done")
class MainDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(MainDialog, self).__init__(parent)
# QThread Version - Safe to use
self.my_thread = LongRunning(limit=10)
self.my_thread.start()
self.my_loader = InfoMessage('Loading ')
self.my_thread.finished.connect(self.my_loader.loading_stop)
# Builtin Threading - Blocking - Do not use
# self.my_thread = threading.Thread(
# target=long_task,
# kwargs={'limit': 10}
# )
# self.my_thread.start()
# self.my_loader = InfoMessage('Loading ')
# self.my_thread.join() # Code blocks here
# self.my_loader.loading_stop()
# Builtin Threading - Callback - Use with caution
# self.my_loader = InfoMessage('Loading ')
# self.my_thread = threading.Thread(
# target=long_task,
# kwargs={'limit': 10,
# 'callback': self.my_loader}
# )
# self.my_thread.start()
def main():
app = QtWidgets.QApplication(sys.argv)
dialog = MainDialog()
app.exec_()
if __name__ == '__main__':
main()
隨意詢問有關此代碼的任何后續問題。
祝好運。
編輯:更新以顯示如何在線程完成時運行代碼。 請注意,新參數已添加到long_task
函數中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.