PyQT:在窗口中获取实时打印输出 [英] PyQT: get real time print output in window

查看:66
本文介绍了PyQT:在窗口中获取实时打印输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 GUI,用于在按下按钮my_button"时调用函数my_function".

I'm working on a GUI for calling a function 'my_function' when the button 'my_button' is pushed.

此函数以迭代方式处理数据.它包含一个for"循环,并且在每次迭代时打印出一条消息,显示我的函数的进度.我希望此打印件实时显示在我的 GUI 中(在此示例中为 textEdit 小部件).我怎么能这样做?

This function processes data iteratively. It contains a 'for' loop, and at each iteration it prints out a message that shows the progress of my function. I would like this prints to be displayed in my GUI (in this example in a textEdit widget), in real time. How could I do that?

我想说明一下,我需要实时显示.我在网上找到了一些解决方案,但只有在函数完成执行时才会出现所有打印.我需要实时显示打印件以了解功能进度.预先感谢您的提示!

I would like to make it clear that I need real time display. I found some solutions online, but all prints only appear when the function finishes execution. I need the prints to display in real time in order to appreciate the function progress. Thanks in advance for your tips!

这是一个最小的可复制示例(我通过 qt 设计器获得了模板):

Here's a minimal reproductible example (I obtained the template via qt designer):

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(163, 225)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.formLayout = QtWidgets.QFormLayout(self.centralwidget)
        self.formLayout.setObjectName("formLayout")
        self.my_button = QtWidgets.QPushButton(self.centralwidget)
        self.my_button.setObjectName("my_button")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.my_button)
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit.setObjectName("textEdit")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.textEdit)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 163, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.my_button.clicked.connect(self.my_function)

    def my_function(self):
        for idx in range(10):
            print('Executing iteration '+str(idx)+' ...')
            time.sleep(1) # replaces time-consuming task
        print('Finished!')

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.my_button.setText(_translate("MainWindow", "Execute"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

推荐答案

Qt 的黄金法则:不要在 GUI 的主线程中执行消耗大量时间的任务,因为它们会阻塞 Qt 的事件循环.

Golden rule of Qt: You should not execute tasks that consume a lot of time in the main thread of the GUI since they block the event loop of Qt.

考虑到上述情况,必须在另一个线程中执行耗时的任务,并通过信号将信息发送到GUI线程.

Considering the above, you must execute the time-consuming task in another thread and send the information to the GUI thread through signals.

另一方面,您不应修改 Qt Designer 生成的类,而是创建另一个类,该类继承自适当的小部件并填充初始类.

On the other hand you should not modify the class generated by Qt Designer, instead create another class that inherits from the appropriate widget and is filled in with the initial class.

import threading
import time

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(163, 225)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.formLayout = QtWidgets.QFormLayout(self.centralwidget)
        self.formLayout.setObjectName("formLayout")
        self.my_button = QtWidgets.QPushButton(self.centralwidget)
        self.my_button.setObjectName("my_button")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.my_button)
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        self.textEdit.setObjectName("textEdit")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.textEdit)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 163, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.my_button.setText(_translate("MainWindow", "Execute"))


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    valueChanged = QtCore.pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.valueChanged.connect(self.on_value_changed)
        self.my_button.clicked.connect(self.on_clicked)

    @QtCore.pyqtSlot()
    def on_clicked(self):
        threading.Thread(target=self.my_function, daemon=True).start()

    @QtCore.pyqtSlot(int)
    def on_value_changed(self, value):
        self.textEdit.append("Value: {}".format(value))

    def my_function(self):
        for idx in range(10):
            self.valueChanged.emit(idx)
            print("Executing iteration " + str(idx) + " ...")
            time.sleep(1)  # replaces time-consuming task
        print("Finished!")


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

这篇关于PyQT:在窗口中获取实时打印输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆