标题PyQt5开发之捕获控制台输出
**放在前面:**此文章非原创,参考了多份文章在python中获取当前控制台输出
多线程
输出重定向至QTexeEdit
写这份文章的目的是为了自己方便查找。
如有侵权,请联系删除。
一、拟解决问题
在训练神经网络时,每个epoch的详细信息会出现在控制台上让我们查看,但是在开发软件时训练神经网络模型我们没办法看到控制台的输出信息,这时如果能够捕获print的打印信息,将其现在在多行文本编辑器里就可以解决了。
二、实行方案
1. stdout重定向
from io import StringIO # 导入两个库
import sys
sys.stdout = buffer = StringIO() # 将输出重定向至 变量buffer中
print("Hello World") # 打印hello world ,这时无法看到打印的具体信息,因为打印信息存放在 buffer中,为了查看是否是这样的,我们改变输出重定向的位置,将输出信息保存在stdout.txt中
sys.stdout = open('./stdout.txt', 'a') # 改变输出重定向位置
print(buffer.getvalue()) # buffer.getvalue()是获取buffer中的内容,字符串类型
print("Hello Python") # 再打印 hello python
整个过程,PyCharm中的输出为空,
stdout.txt文件中的内容如下:
使用下面代码即可将输出的信息显示在QTextEdit中。
Mytext = QTextEdit(window)
Mytext.setText(buffer.getvalue())
存在问题:
无法实时获取打印信息
2. 重定向至QTextEdit
import sys
import time
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication, QTextEdit
class EmitStr(QObject):
'''
定义一个信号类,
sys.stdout有个write方法,通过重定向,
每当有新字符串输出时就会触发下面定义的write函数,
进而发出信号
text:新字符串,会通过信号传递出去
'''
textWrit = pyqtSignal(str)
def write(self, text):
self.textWrit.emit(str(text))
class MyWidget(QWidget): # 定义一个窗体类,继承于QWidget
def __init__(self):
super().__init__()
self.step_up() # 构建一个QTextEdit, 以及对窗体的一些基本设置
sys.stdout = EmitStr(textWrit=self.outputWrite) # 输出结果重定向
sys.stderr = EmitStr(textWrit=self.outputWrite) # 错误输出重定向
def outputWrite(self, text):
self.te.append(text) # 输出的字符追加到 QTextEdit 中
def step_up(self):
self.setWindowTitle('输出重定向')
self.resize(500,500)
self.te = QTextEdit(self)
self.te.move(10,10)
def MyPrint(self): # 定义个持续打印函数,用于验证
for i in range(10):
print(i)
time.sleep(0.5)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
w = MyWidget()
w.show()
w.MyPrint()
sys.exit(app.exec())
现象:
界面出现假死现象,等待打印函数运行结束之后,才会把输出内容append到QTextEdit中。
3. 使用多线程
经过上面两步的操作,已将输出内容追加到QTextEdit中,对于界面假死现象,使用多线程处理,在线程中来运行比较耗时的程序,比如此时的模拟持续输出的打印函数。
关于多线程,只需用引入from PyQt5.Qt import QThread
即可
只需用在下列代码中重新run()函数,即把比较耗时的代码放在run()中。
介绍QThread的两种方法:
start():启动线程
finished:线程结束时会发出信号
class MyThread(QThread):
def __init__(self):
super().__init__()
def run(self):
for i in range(10):
print(i)
time.sleep(0.5)
完整代码如下:
import sys
import time
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QWidget, QApplication, QTextEdit
from PyQt5.Qt import QThread
class EmitStr(QObject):
'''
定义一个信号类,
sys.stdout有个write方法,通过重定向,
每当有新字符串输出时就会触发下面定义的write函数,
进而发出信号
text:新字符串,会通过信号传递出去
'''
textWrit = pyqtSignal(str)
def write(self, text):
self.textWrit.emit(str(text))
class MyWidget(QWidget): # 定义一个窗体类,继承于QWidget
def __init__(self):
super().__init__()
self.step_up() # 构建一个QTextEdit, 以及对窗体的一些基本设置
sys.stdout = EmitStr(textWrit=self.outputWrite) # 输出结果重定向
sys.stderr = EmitStr(textWrit=self.outputWrite) # 错误输出重定向
def outputWrite(self, text):
self.te.append(text) # 输出的字符追加到 QTextEdit 中
def step_up(self):
self.setWindowTitle('输出重定向')
self.resize(500,500)
self.te = QTextEdit(self)
self.te.move(10,10)
class MyThread(QThread):
def __init__(self):
super().__init__()
def run(self):
for i in range(10):
print(i)
time.sleep(0.5)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
w = MyWidget()
mythread = MyThread()
mythread.start()
mythread.finished.connect(lambda: print('完成打印'))
w.show()
sys.exit(app.exec())