1,基础案例
先来看段代码。功能是按下Button 1的时候控制台打印1-100,同时lineEdit 1也显示1-100,每隔1秒打印显示一次;按下Button 2的时候控制台打印100-1,同时lineEdit 2也显示100-1,每隔1秒打印显示一次。然而当实际按下按钮1时,控制台确实在打印,然而gui却卡死了,lineEdit也无法显示。
import sys
import time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QThread")
self.resize(300, 400)
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.layout = QtWidgets.QVBoxLayout(self.widget)
self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
self.lineEdit1.setObjectName("lineEdit1")
self.pushButton1 = QtWidgets.QPushButton(self.widget)
self.pushButton1.setObjectName("pushButton1")
self.pushButton1.setText("Button 1")
self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
self.lineEdit2.setObjectName("lineEdit2")
self.pushButton2 = QtWidgets.QPushButton(self.widget)
self.pushButton2.setObjectName("pushButton2")
self.pushButton2.setText("Button 2")
self.layout.addWidget(self.lineEdit1)
self.layout.addWidget(self.pushButton1)
self.layout.addWidget(self.lineEdit2)
self.layout.addWidget(self.pushButton2)
QtCore.QMetaObject.connectSlotsByName(self)
@pyqtSlot()
def on_pushButton1_clicked(self):
for i in range(100):
self.lineEdit1.setText(str(i))
print(i)
time.sleep(1)
@pyqtSlot()
def on_pushButton2_clicked(self):
for i in range(100):
self.lineEdit1.setText(str(100-i))
print(100 - i)
time.sleep(1)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
2,QThread解决方案
单独实现控制台打印很简答,增加两个QThread子类,当按下按钮时创建并运行子类的run方法即可。注意thread1和thread2需要定义为实例属性,不要定义为局部变量。
import sys
import time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot, QThread
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QThread")
self.resize(300, 400)
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.layout = QtWidgets.QVBoxLayout(self.widget)
self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
self.lineEdit1.setObjectName("lineEdit1")
self.pushButton1 = QtWidgets.QPushButton(self.widget)
self.pushButton1.setObjectName("pushButton1")
self.pushButton1.setText("Button 1")
self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
self.lineEdit2.setObjectName("lineEdit2")
self.pushButton2 = QtWidgets.QPushButton(self.widget)
self.pushButton2.setObjectName("pushButton2")
self.pushButton2.setText("Button 2")
self.layout.addWidget(self.lineEdit1)
self.layout.addWidget(self.pushButton1)
self.layout.addWidget(self.lineEdit2)
self.layout.addWidget(self.pushButton2)
QtCore.QMetaObject.connectSlotsByName(self)
@pyqtSlot()
def on_pushButton1_clicked(self):
self.thread1 = QThread1()
self.thread1.start()
@pyqtSlot()
def on_pushButton2_clicked(self):
self.thread2 = QThread2()
self.thread2.start()
class QThread1(QThread):
def __init__(self):
super().__init__()
def run(self):
for i in range(100):
print(i)
time.sleep(1)
class QThread2(QThread):
def __init__(self):
super().__init__()
def run(self):
for i in range(100):
print(100 - i)
time.sleep(1)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
如果需要实现按下按钮后lineEdit同时显示。有两种方法:
(1)将lineEdit对象传给QThread,然后在run方法里设置文本。
import sys
import time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot, QThread
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QThread")
self.resize(300, 400)
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.layout = QtWidgets.QVBoxLayout(self.widget)
self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
self.lineEdit1.setObjectName("lineEdit1")
self.pushButton1 = QtWidgets.QPushButton(self.widget)
self.pushButton1.setObjectName("pushButton1")
self.pushButton1.setText("Button 1")
self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
self.lineEdit2.setObjectName("lineEdit2")
self.pushButton2 = QtWidgets.QPushButton(self.widget)
self.pushButton2.setObjectName("pushButton2")
self.pushButton2.setText("Button 2")
self.layout.addWidget(self.lineEdit1)
self.layout.addWidget(self.pushButton1)
self.layout.addWidget(self.lineEdit2)
self.layout.addWidget(self.pushButton2)
QtCore.QMetaObject.connectSlotsByName(self)
@pyqtSlot()
def on_pushButton1_clicked(self):
self.thread1 = QThread1(self.lineEdit1)
self.thread1.start()
@pyqtSlot()
def on_pushButton2_clicked(self):
self.thread2 = QThread2(self.lineEdit2)
self.thread2.start()
class QThread1(QThread):
def __init__(self, lineEdit):
super().__init__()
self.lineEdit = lineEdit
def run(self):
for i in range(100):
self.lineEdit.setText(str(i))
print(i)
time.sleep(1)
class QThread2(QThread):
def __init__(self, lineEdit):
super().__init__()
self.lineEdit = lineEdit
def run(self):
for i in range(100):
self.lineEdit.setText(str(100 -i))
print(100 - i)
time.sleep(1)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
(2)在QThread里定义信号,run方法里发射信号。信号和lineEdit的setText方法关联
import sys
import time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import pyqtSlot, QThread, pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QThread")
self.resize(300, 400)
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.layout = QtWidgets.QVBoxLayout(self.widget)
self.lineEdit1 = QtWidgets.QLineEdit(self.widget)
self.lineEdit1.setObjectName("lineEdit1")
self.pushButton1 = QtWidgets.QPushButton(self.widget)
self.pushButton1.setObjectName("pushButton1")
self.pushButton1.setText("Button 1")
self.lineEdit2 = QtWidgets.QLineEdit(self.widget)
self.lineEdit2.setObjectName("lineEdit2")
self.pushButton2 = QtWidgets.QPushButton(self.widget)
self.pushButton2.setObjectName("pushButton2")
self.pushButton2.setText("Button 2")
self.layout.addWidget(self.lineEdit1)
self.layout.addWidget(self.pushButton1)
self.layout.addWidget(self.lineEdit2)
self.layout.addWidget(self.pushButton2)
QtCore.QMetaObject.connectSlotsByName(self)
@pyqtSlot()
def on_pushButton1_clicked(self):
self.thread1 = QThread1()
self.thread1.sg[str].connect(self.lineEdit1.setText)
self.thread1.start()
@pyqtSlot()
def on_pushButton2_clicked(self):
self.thread2 = QThread2()
self.thread2.sg[str].connect(self.lineEdit2.setText)
self.thread2.start()
class QThread1(QThread):
sg = pyqtSignal(str)
def __init__(self):
super().__init__()
def run(self):
for i in range(100):
self.sg[str].emit(str(i))
print(i)
time.sleep(1)
class QThread2(QThread):
sg = pyqtSignal(str)
def __init__(self):
super().__init__()
def run(self):
for i in range(100):
self.sg[str].emit(str(100 - i))
print(100 - i)
time.sleep(1)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())