我有一个PyQt GUI,其中包含一个 QTextEdit 在代码执行期间显示print语句的框。我选择通过重定向来执行此操作 sys.stdout ,按照以下这样的帖子:
QTextEdit
sys.stdout
将python控制台输出打印到Qtextedit
它非常适合记录打印语句,以便用户可以看到执行过程中发生的事情,但是我希望在代码运行时更新它,而不是写入缓冲区并在最后打印出所有内容。例如,在此代码中,单击“运行”按钮将等待5秒钟以打印“正在运行...”和“完成”。函数运行后,我希望它显示'Running ...',等待5秒,然后显示'Done'。
以下是我编写的代码的基础知识:
import sys import time from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication, QTextEdit from PyQt5 import QtCore, QtGui class Stream(QtCore.QObject): """Redirects console output to text widget.""" newText = QtCore.pyqtSignal(str) def write(self, text): self.newText.emit(str(text)) class GenMast(QMainWindow): """Main application window.""" def __init__(self): super().__init__() self.initUI() # Custom output stream. sys.stdout = Stream(newText=self.onUpdateText) def onUpdateText(self, text): """Write console output to text widget.""" cursor = self.process.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.insertText(text) self.process.setTextCursor(cursor) self.process.ensureCursorVisible() def closeEvent(self, event): """Shuts down application on close.""" # Return stdout to defaults. sys.stdout = sys.__stdout__ super().closeEvent(event) def initUI(self): """Creates UI window on launch.""" # Button for generating the master list. btnGenMast = QPushButton('Run', self) btnGenMast.move(450, 100) btnGenMast.resize(100, 100) btnGenMast.clicked.connect(self.genMastClicked) # Create the text output widget. self.process = QTextEdit(self, readOnly=True) self.process.ensureCursorVisible() self.process.setLineWrapColumnOrWidth(500) self.process.setLineWrapMode(QTextEdit.FixedPixelWidth) self.process.setFixedWidth(400) self.process.setFixedHeight(150) self.process.move(30, 100) # Set window size and title, then show the window. self.setGeometry(300, 300, 600, 300) self.setWindowTitle('Generate Master') self.show() def genMastClicked(self): """Runs the main function.""" print('Running...') time.sleep(5) print('Done.') if __name__ == '__main__': # Run the application. app = QApplication(sys.argv) app.aboutToQuit.connect(app.deleteLater) gui = GenMast() sys.exit(app.exec_())
我首先尝试 flush=True 在print语句中进行设置。但是,我遇到了错误 'Stream' object has no attribute 'flush' ,所以我继续在我创建 flush 的 Stream 类中定义,如下所示:
flush=True
'Stream' object has no attribute 'flush'
flush
Stream
class Stream(QtCore.QObject): """Redirects console output to text widget.""" newText = QtCore.pyqtSignal(str) def write(self, text): self.newText.emit(str(text)) def flush(self): sys.stdout.flush()
哪个产生了错误RecursionError:超出了最大递归深度。 这是我的理解用完的地方,因为我已经尝试了其他方法来刷新打印缓冲区,但它们似乎都有这个问题。 关于我做错的任何建议?
发布于 2018-12-13 14:20:49
这种情况下的问题与flush相关,但是使用了time.sleep()。 time.sleep()是一个阻塞任务,不允许Qt事件循环运行,从而阻止信号正常工作和GUI更新,解决方案是使用QTimer和QEventLoop替换该GUI睡眠。
def genMastClicked(self): """Runs the main function.""" print('Running...') loop = QEventLoop() QTimer.singleShot(5000, loop.quit) loop.exec_() print('Done.')
完整代码:
import sys import time from PyQt5.QtCore import QObject, pyqtSignal, QEventLoop, QTimer from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication, QTextEdit from PyQt5.QtGui import QTextCursor class Stream(QObject): """Redirects console output to text widget.""" newText = pyqtSignal(str) def write(self, text): self.newText.emit(str(text)) class GenMast(QMainWindow): """Main application window.""" def __init__(self): super().__init__() self.initUI() # Custom output stream. sys.stdout = Stream(newText=self.onUpdateText) def onUpdateText(self, text): """Write console output to text widget.""" cursor = self.process.textCursor() cursor.movePosition(QTextCursor.End) cursor.insertText(text) self.process.setTextCursor(cursor) self.process.ensureCursorVisible() def closeEvent(self, event): """Shuts down application on close.""" # Return stdout to defaults. sys.stdout = sys.__stdout__ super().closeEvent(event) def initUI(self): """Creates UI window on launch.""" # Button for generating the master list. btnGenMast = QPushButton('Run', self) btnGenMast.move(450, 100) btnGenMast.resize(100, 100) btnGenMast.clicked.connect(self.genMastClicked) # Create the text output widget. self.process = QTextEdit(self, readOnly=True) self.process.ensureCursorVisible() self.process.setLineWrapColumnOrWidth(500) self.process.setLineWrapMode(QTextEdit.FixedPixelWidth) self.process.setFixedWidth(400) self.process.setFixedHeight(150) self.process.move(30, 100) # Set window size and title, then show the window. self.setGeometry(300, 300, 600, 300) self.setWindowTitle('Generate Master') self.show() def genMastClicked(self): """Runs the main function.""" print('Running...') loop = QEventLoop() QTimer.singleShot(5000, loop.quit) loop.exec_() print('Done.') if __name__ == '__main__': # Run the application. app = QApplication(sys.argv) app.aboutToQuit.connect(app.deleteLater) gui = GenMast() sys.exit(app.exec_())
发布于 2019-10-10 15:32:00
您好,请问前辈解决了吗?我也遇见了这样一个问题,现在是自己定义了一个信号,能够实现简单的print的截获,但是不能实时的截获terminal的信息。报错误也是报在了UI上,就是说不能刷新。因为在深度学习训练过程中,terminal的显示是不断有信息被打印出来的,包括loss,准确率等等。
屏蔽掉如下两行,就正常输出,不过是在terminal的打印,给你截图看看啊
下面是完整代码
class EmittingStream(QtCore.QObject): textWritten = QtCore.pyqtSignal(str) def write(self, text): self.textWritten.emit(str(text)) class AI_Workstation(QtWidgets.QMainWindow): def __init__(self, parent=None): super(AI_Workstation, self).__init__() sys.stdout = EmittingStream(textWritten=self.normalOutputWritten) sys.stderr = EmittingStream(textWritten=self.normalOutputWritten) self._createUI() self.Config = Configuration() self.N = 0 self._connect() self.show() # def __del__(self): # # Restore sys.stdout # sys.stdout = sys.__stdout__ # sys.stderr = sys.__stderr__ def _createUI(self): self.ui = MainUI.Ui_MainWindow() self.ui.setupUi(self) self.ui.retranslateUi(self) # 创建信号槽事件 def _connect(self): # 打印超参数 self.ui.pushButton_Print.clicked.connect(self.parameterInit) # 信号槽机制 self.ui.pushButton_Train.clicked.connect(self.trainNow) self.ui.pushButton_Test.clicked.connect(self.testNow) self.ui.pushButton_Inference.clicked.connect(self.inferenceNow) def parameterInit(self): self.lr_value = self.ui.lineEdit_Lr.text() # 获取文本框内容 self.opt_value = self.ui.comboBox_Opt.currentText() self.numworkers_value = self.ui.lineEdit_Workers.text() self.maxepoch_value = self.ui.lineEdit_MaxEpoch.text() self.nclass_value = self.ui.lineEdit_Class.text() self.Config.LR=self.lr_value self.N=self.N+1 self.ui.label_PrecentProc.setText(str(self.N)) # 给label设定text参数 self.ui.horizontalSlider.setValue(self.N) # 给horizontalSlider设定value参数 print(u'打印训练参数:\n' + u'学习率: ' + self.Config.LR + u'优化方式: ' + self.opt_value + u'多线程: ' + self.numworkers_value) for line in open("./records/20190814103634/loss.txt"): print(line.strip()) def normalOutputWritten(self, text): """Append text to the QTextEdit."""