哈喽大家好,我是鹏哥。
今天我们把上周录屏小工具的一些细节进行详细说明下,因此这次的主题是 —— 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编辑运行方式时,勾选以下选项(建议使用这种方法):
~~~下课铃~~~
点击下方诗句,可以留言互动喔
你有你的清欢渡,我有我的不归路。终有弱水替沧海,再把相思寄巫山。