Pyqt5使用多线程解决界面卡顿并将命令行输出重定向到UI

先使用qtdesigner画两个按钮和两个text,用来检测功能。

Pyqt5使用多线程解决界面卡顿并将命令行输出重定向到UI_第1张图片

在使用pyuic将其转换为py文件。

先给按钮2定义一个简单的函数,运行。

import thread_update
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import *
import sys, os
import time


class MyThreadUpdate(thread_update.Ui_MainWindow):
    def __init__(self):
        super(MyThreadUpdate, self).__init__()

    def retranslateUi(self, MainWindow):
        super(MyThreadUpdate, self).retranslateUi(MainWindow)
        ui.pushButton_2.clicked.connect(self.buttonsec_clicked)

    def buttonsec_clicked(self):
        chr_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
        for element in chr_list:
            time.sleep(1)
            print(element)
        print('end')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    ui = MyThreadUpdate()
    ui.setupUi(MainWindow)
    MainWindow.show()

    sys.exit(app.exec_())

会发现执行函数过程中UI界面卡死,如图所示:

Pyqt5使用多线程解决界面卡顿并将命令行输出重定向到UI_第2张图片

 可以通过qt的QThread来解决。代码如下:

import thread_update
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import *
import sys, os
import time


class ButtonOne(QThread):
    def __init__(self):
        super(ButtonOne, self).__init__()

    def write(self, text):
        self.signalForText.emit(text)

    def run(self):
        for i in range(15):
            time.sleep(1)
            print(i)
        print('end')


class ButtonSec(QThread):
    def __init__(self):
        super(ButtonSec, self).__init__()

    def run(self):
        chr_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
        for element in chr_list:
            time.sleep(1)
            print(element)
        print('end')


class MyThreadUpdate(thread_update.Ui_MainWindow):
    def __init__(self):
        super(MyThreadUpdate, self).__init__()
        self.thread_buttonsec = ButtonSec()
        self.thread_buttonone = ButtonOne()

    def retranslateUi(self, MainWindow):
        super(MyThreadUpdate, self).retranslateUi(MainWindow)
        ui.button_1.clicked.connect(self.buttonone_clicked)
        ui.pushButton_2.clicked.connect(self.buttonsec_clicked)

    def buttonone_clicked(self):
        self.thread_buttonone.start()

    def buttonsec_clicked(self):
        self.thread_buttonsec.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    ui = MyThreadUpdate()
    ui.setupUi(MainWindow)
    MainWindow.show()

    sys.exit(app.exec_())

这样在点击按钮UI界面也不会卡顿。

下面实现将命令行输出重定向到UI界面上

import thread_update
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import *
import sys, os
import time


class ButtonOne(QThread):
    _signalForText = pyqtSignal(str)

    def __init__(self):
        super(ButtonOne, self).__init__()

    def write(self, text):
        self.signalForText.emit(text)

    def run(self):

        for i in range(15):
            time.sleep(1)
            print(i)
        print('end')

    @property
    def signalForText(self):
        return self._signalForText


class ButtonSec(QThread):
    def __init__(self):
        super(ButtonSec, self).__init__()

    def run(self):
        chr_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
        for element in chr_list:
            time.sleep(1)
            print(element)
        print('end')


class MyThreadUpdate(thread_update.Ui_MainWindow):
    def __init__(self):
        super(MyThreadUpdate, self).__init__()
        self.thread_buttonsec = ButtonSec()
        self.thread_buttonone = ButtonOne()
        self.thread_buttonone.signalForText.connect(self.updateText)
        sys.stdout = self.thread_buttonone

    def retranslateUi(self, MainWindow):
        super(MyThreadUpdate, self).retranslateUi(MainWindow)
        ui.button_1.clicked.connect(self.buttonone_clicked)
        ui.pushButton_2.clicked.connect(self.buttonsec_clicked)

    def updateText(self, text):
        cursor = self.text_1.textCursor()
        cursor.insertText(text)
        self.text_1.setTextCursor(cursor)
        self.text_1.ensureCursorVisible()

    def buttonone_clicked(self):
        self.thread_buttonone.start()

    def buttonsec_clicked(self):
        self.thread_buttonsec.start()
        # chr_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
        # for element in chr_list:
        #     time.sleep(1)
        #     print(element)
        # print('end')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    ui = MyThreadUpdate()
    ui.setupUi(MainWindow)
    MainWindow.show()

    sys.exit(app.exec_())


实现效果如下:
Pyqt5使用多线程解决界面卡顿并将命令行输出重定向到UI_第3张图片

 如果想要在1按钮函数运行结束之前,按钮处于不可点击状态也可以通过信号实现。简略代码如下

button1函数部分在添加一个信号,并在函数执行结束之后在发射

class ButtonOne(QThread):
    _signal = pyqtSignal()
    _signalForText = pyqtSignal(str)

    def __init__(self):
        super(ButtonOne, self).__init__()

    def write(self, text):
        self.signalForText.emit(text)

    def run(self):

        for i in range(15):
            time.sleep(1)
            print(i)
        print('end')
        self._signal.emit()

    @property
    def signalForText(self):
        return self._signalForText

UI界面部分代码,在点击按钮之后将按钮设为不可点击状态,同时在接收到信号时候将按钮设置为可以点击状态.

    def buttonone_clicked(self):
        self.button_1.setEnabled(False)
        self.thread_buttonone.start()
        self.thread_buttonone._signal.connect(self.enableButtonOne)

    def enableButtonOne(self):
        self.button_1.setEnabled(True)    

你可能感兴趣的:(python,qt5)