我有一个PyQt GUI,其中包含一个
QTextEdit
在代码执行期间显示print语句的框。我选择通过重定向来执行此操作
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
类中定义,如下所示:
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."""