哈嘍大家好,我是鵬哥。
今天我們把上週錄屏小工具的一些細節進行詳細說明下,因此這次的主題是 —— QThread的正確使用。
1
寫在前面
我們先回顧下上次博客是如何實現pyqt5的多線程功能的?
class WorkThread(QThread):
def __init__(self, n):
super(WorkThread, self).__init__()
self.n = n
def run(self):
XXXXX
簡單來說,就是通過繼承QThread類,並修改run方法來實現的。但是有一次在網上看帖子時,發現QT大神們說:
不要將業務邏輯代碼放到QThread類中,QThread類是用於管理線程的(大致是這個意思)
那要怎麼實現多線程纔是正確科學的呢?答案是使用moveToThread()方法來實現。
2
效果展示
這裏爲了重點演示多線程代碼,因此將錄屏功能代碼進行了註釋。以上功能通過點擊錄屏(自定義或全屏)來 啓動線程,點擊結束錄屏來結束線程。
3
知識串講(敲黑板啦)
爲了實現QT5的多線程功能,這裏有2個知識點需要學習和了解。
(1)信號與槽
signal = pyqtSignal(str)
首先需要在自己的類中,使用pyqtSignal()方法來定義一個信號變量,其中如果要傳遞的信號是str類,則需要聲明下str;如果是int類的信號,則這樣定義:
signal = pyqtSignal(int)
在信號定義後,自然要有個槽來接受信號,即使用以下代碼:
# 創建線程
self.workobject = WorkObject(n)
# 連接線程
self.workobject.signal.connect(self.myprint)
myprint()函數是我自己定義的,主要是爲了將接受的信號進行打印。
一般開發GUI界面時,都會用到信號與槽,因此需要好好了解下玩法。
(2)多線程的實現
# 將自己線程交於QThead類來管理
self.workthread = QThread()
self.workobject.moveToThread(self.workthread)
# 啓動線程
self.workthread.started.connect(self.workobject.run)
self.workthread.start()
這裏就將我們自己的線程,通過moveToThread方法交於了QThread類,並由它來管理我們的線程,包括啓動線程、線程運行、線程停止等。
另外,在自己線程運行時,如果再次運行一個新的線程,即我在點擊錄屏後再次點擊錄屏,就會報錯,錯誤內容如下:
QThread: Destroyed while thread is still running
因此如果要啓動一個新的線程,需要self.workthread.quit()。
4
示例代碼
# coding=utf-8
# @Auther : "鵬哥賊優秀"
# @Date : 2019/12/3
# @Software : PyCharm
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import time
import win32api,win32con
class WorkObject(QObject):
signal = pyqtSignal(str)
def __init__(self, n):
super(WorkObject, self).__init__()
self.n = n
def run(self):
if self.n == 1:
Minimize_Window()
# Recording(1)
self.signal.emit('已選擇自定義錄屏')
elif self.n == 2:
Minimize_Window()
# Recording(2)
self.signal.emit('已選擇全屏錄屏')
def Minimize_Window():
win32api.keybd_event(91, 0, 0, 0)
time.sleep(0.5)
win32api.keybd_event(40, 0, 0, 0)
time.sleep(0.5)
win32api.keybd_event(91, 0, win32con.KEYEVENTF_KEYUP, 0)
win32api.keybd_event(40, 0, win32con.KEYEVENTF_KEYUP, 0)
class Ui_Mainwindow():
def setupUi(self, top):
# 垂直佈局類QVBoxLayout
layout = QVBoxLayout(top)
# 添加錄屏相關按鈕
button1 = QPushButton("自定義錄屏")
layout.addWidget(button1)
button2 = QPushButton("全屏錄屏")
layout.addWidget(button2)
button3 = QPushButton("停止錄屏")
layout.addWidget(button3)
self.text = QPlainTextEdit('歡迎使用!By 鵬哥賊優秀')
layout.addWidget(self.text)
button1.clicked.connect(lambda: self.work(1))
button2.clicked.connect(lambda: self.work(2))
button3.clicked.connect(self.stop)
def work(self, n):
# 創建線程
self.workobject = WorkObject(n)
# 連接線程
self.workobject.signal.connect(self.myprint)
# 將自己線程交於QThead類來管理
self.workthread = QThread()
self.workobject.moveToThread(self.workthread)
# 啓動線程
self.workthread.started.connect(self.workobject.run)
self.workthread.start()
def stop(self):
print('已選擇結束錄屏')
# StopRecording()
# 結束線程
self.workthread.quit()
def myprint(self,n):
print(n)
self.text.setPlainText(n)
if __name__ == "__main__":
app = QApplication(sys.argv)
top = QWidget()
top.setWindowTitle('錄屏小工具')
top.resize(300, 170)
ui = Ui_Mainwindow()
ui.setupUi(top)
top.show()
sys.exit(app.exec_())
5
小技巧
這裏我還想講一些QT5編程時用到的小技巧:如何定位調試gui界面類的錯誤 ?比如如果我們的代碼有問題,在運行GUI時會出現如下現象:
但是你是無法從控制檯上看到錯誤日誌。
這裏有2個方法來解決這一問題。
A、通過cmd窗口來運行,這樣錯誤日誌會打印在cmd窗口上了;
B、在pycharm編輯運行方式時,勾選以下選項(建議使用這種方法):
~~~下課鈴~~~
點擊下方詩句,可以留言互動喔
你有你的清歡渡,我有我的不歸路。終有弱水替滄海,再把相思寄巫山。