在 PyQT5 中,存在 Progress Bar 這個控件,它的作用是顯示當前任務的百分比。
對於這樣一個控件,最合適的使用場景就是拿來當計時器,或者下載進度條之類。
有兩種典型的 Progress Bar 卡死原因:
1. 沒有爲 Progress Bar 開闢線程
2. 沒有將對 Progress Bar 的操作移到主線程進行
1. 沒有爲 Progress Bar 開闢線程
以用作計時器爲例,需要爲 Progress Bar 的任務開一個線程,以避免在計時期間,界面無法進行任何操作。如果在主界面裏計時10s,那麼在這10s內,界面就會處在類似於鎖定的狀態,只有當10s計時結束,才能進行別的操作。
如下面這段代碼所示,通過操作線程 t 的 pause, resume,來實現對 countDownSingal 的操作,而不是直接把 countDownSingal 放在主線程中操作。
def init_thread(self):
self.t = threading.Thread(target=self.countDownSingal)
self.__flag = threading.Event()
self.__flag.set()
self.__running = threading.Event()
self.__running.set()
self.t.setDaemon(True)
self.t.start()
self.pause()
def countDownSingal(self):
......
pass
2. 沒有將對 Progress Bar 的操作移到主線程進行
就算開了線程,依然會存在這個問題。當我們在線程中改變 Progress Bar 的值,會發現依然會卡死。這是由於要對界面進行的操作,必須在主線程中完成。那麼在支線程中想要對界面操作,就需要發出信號,並由主線程接收信號,再去做修改。
通過自定義一個信號,例如叫 _time_signal,並將它與最終主線程上的界面操作方法 changeTimeBar connect 起來,在支線程中發射信號,由主線程接收信號,並對 Progress Bar 進行操作,可以完成避免卡死的問題。
_time_signal = QtCore.pyqtSignal()
def signal(self, Form):
self._time_signal.connect(self.changeTimeBar)
def countDownSingal(self):
while self.__running.isSet():
self.__flag.wait()
while (self.count_down):
self.__flag.wait()
self._time_signal.emit()
self.count_down -= 1
time.sleep(1)
def changeTimeBar(self):
......
pass