Python中如何将print输出信息实时显示到GUI界面?
现在使用得 PYQT5 做的做了一个 GUI 界面,在这个 GUI.py 文件里面 print 打印得信息已经让我重定向到了文本框中,有一个问题,我在调用其他 py 文件的时候(这个 py 文件也有 print 打印信息),无法打印到 GUI 界面下的文本框中,而是打印到了 pycharm 得控制台,有谁能帮我想想思路怎么做可以?
我是通过 os.system(“ python +py 文件”) 调用得。
Python中如何将print输出信息实时显示到GUI界面?
用管道重定向其他进程的 stdout ?
在Python里把print输出实时显示到GUI界面,核心思路是重定向标准输出。这里给你一个完整的Tkinter示例,可以直接运行:
import sys
import tkinter as tk
from tkinter import scrolledtext
from io import StringIO
import threading
class PrintRedirector:
def __init__(self, text_widget):
self.text_widget = text_widget
self.buffer = StringIO()
def write(self, string):
self.buffer.write(string)
# 在主线程中更新GUI
self.text_widget.after(0, self.update_text)
def update_text(self):
text = self.buffer.getvalue()
if text:
self.text_widget.insert(tk.END, text)
self.text_widget.see(tk.END) # 自动滚动到底部
self.buffer.truncate(0)
self.buffer.seek(0)
def flush(self):
pass # 需要实现flush方法
class App:
def __init__(self, root):
self.root = root
root.title("Print输出重定向示例")
# 创建滚动文本框
self.text_area = scrolledtext.ScrolledText(root, wrap=tk.WORD, width=60, height=20)
self.text_area.pack(padx=10, pady=10)
# 重定向print输出
sys.stdout = PrintRedirector(self.text_area)
# 添加测试按钮
btn = tk.Button(root, text="开始测试输出", command=self.start_test)
btn.pack(pady=5)
def start_test(self):
# 在新线程中执行耗时操作,避免阻塞GUI
thread = threading.Thread(target=self.simulate_work)
thread.daemon = True
thread.start()
def simulate_work(self):
for i in range(10):
print(f"正在处理第 {i+1} 个任务...")
import time
time.sleep(0.5) # 模拟耗时操作
print("所有任务完成!")
if __name__ == "__main__":
root = tk.Tk()
app = App(root)
root.mainloop()
这个方案的关键点:
- 创建
PrintRedirector类继承自StringIO,重写write方法 - 在
write方法中捕获输出内容,通过after方法在主线程中更新GUI - 使用
ScrolledText组件支持滚动查看 - 耗时操作放在单独线程,避免GUI卡顿
如果你用PyQt,思路类似,用QTextEdit组件和信号槽机制。核心就是重定向sys.stdout到你的GUI组件。
一句话建议:重定向sys.stdout到自定义的GUI输出组件。
是的,输出重定向就可以了。
用 QProcess()
http://doc.qt.io/qt-5/qprocess.html#readAllStandardOutputpython<br>p = QProcess()<br>p.setProcessChannelMode(QProcess.MergedChannels)<br>p.setProcessEnvironment(QProcessEnvironment.systemEnvironment())<br><br>p.readyRead.connect(GUIoutput)<br>p.start(“ python +py 文件”, QIODevice.ReadWrite)<br><br>def GUIoutput():<br> TextEdit.moveCursor(QTextCursor.End)<br> outputTextEdit.insertPlainText(<br> str(p.readAllStandardOutput(), "utf-8"))<br> TextEdit.moveCursor(QTextCursor.End)<br>
具体自己修改下,代码流程是这样的。
好的,我试试周一的时候,谢谢!
主要已经做了重定向,在当前的 py 代码里面 print 可以直接打印到文本框里面,但是调用其他的 py 文件,这个 py 文件 print 的信息不会打印。
尝试了一下,文本框无法打印想要输出的内容,因为执行的是线程,然后在这个线程下面 用重定向不好使。
贴一下源码
import time
from comm.atc import atLogger, atChat
import subprocess
import sys
import os
import time
import datetime
import requests
import json
import random
from PyQt5.QtWidgets import (QApplication,QWidget,QLabel,QAction,QProgressBar,
QPushButton,QMainWindow,QTextEdit,QGridLayout,QComboBox)
from PyQt5.QtGui import QIcon,QTextCursor
from PyQt5.QtCore import QThread,pyqtSignal,QCoreApplication,QObject,QBasicTimer,Qt,QProcess,QProcessEnvironment,QIODevice
from comm.at import COMPORT
class ThreadAp(QThread):
name = “”“操作 AP 控制”""
apstatus = pyqtSignal()
def run(self):
# url = “http://192.168.104.1/”
# s = requests.session()
# header ={
# “token”:“Ku2vhFFTc9K5V%24Laf2l2V9I%24PqX%249I”,
# “Accept-Encoding”: “gzip, deflate”,
# “Accept-Language”: “zh-CN, zh;q=0.9”,
# “Referer”: “http://192.168.104.1/”,
# “User-Agent”:“Mozilla/5.0(Windows NT10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/67.0.3396.62 Safari/537.36”,
# }
# login = {“method”:“do”,“login”:{“password”:“0KcgeXhc9TefbwK”}}
# response = requests.post(url,data=json.dumps(login),headers=header).text
# jsonload = json.loads(response)
# stok = jsonload[“stok”]
# print(stok)
# setwlanurl = “http://192.168.104.1/stok=%s/ds”%stok
# channelnum = {“method”:“set”,“wireless”:{“wlan_host_2g”:{“channel”:“1”, “mode”: “3”}}}
# channelnum2 ={“method”:“set”,“wireless”:{“wlan_host_2g”:{“channel”:“11”,“mode”:“1”,“bandwidth”:“1”}}}
# channerlpost = requests.post(setwlanurl, data=json.dumps(channelnum))
# print(channerlpost.text)
script = os.getcwd() + r’\network<a target="_blank" href=“http://Network_01.py” rel=“nofollow noopener”>Network_01.py’ # 获取当前路径拼接 Network_01 所在位置
cmd = 'python ’ + ‘-m unittest ‘+script # python +py 所在地址
# r = os.system(cmd) # 执行 runTest.py 文件
r =subprocess.Popen(cmd,shell=True)
-----------------------------------------------------在这个下面加-------------------------------------------------------------------
class ThreadQt(QThread):
name = “”“AT 命令测试线程”""
status = pyqtSignal() #实例化一个无参数信号
steps = pyqtSignal(int) #实例化一个 int 参数信号
times = 2 #设置测试次数参数
def run(self):
for i in range(0, self.times):
n = i + 1
print("------------Test Round : %s on %s------------" % (str(n), COMPORT))
print("--------------------V1.1 测试版------------------")
print("---------------------" + datetime.datetime.fromtimestamp(time.time()).strftime(
“%Y-%m-%d-%H-%M-%S”) + “------------------”)
time.sleep(0.2)
script = os.getcwd() + r’<a target="_blank" href=“http://runTest.py” rel=“nofollow noopener”>runTest.py’ #获取当前路径拼接 runTest 所在位置
cmd = 'python ’ + script #python +py 所在地址
os.system(cmd) #执行 runTest.py 文件
time.sleep(1) #休眠 1 秒
print("-----------------------第%s 遍测试已完成--------------------"%n)
print("\n")
step = n*(100/self.times) #计算百分比
self.steps.emit(step) #发射 step 信号给进度条槽
try:
os.system('python ‘+os.getcwd()+r’\config<a target="blank" href=“http://SendMail.py” rel=“nofollow noopener”>SendMail.py’)#获取当前路径拼接 SendMail 所在位置
print(“邮件发送成功”)
except:
print(“Error: 无法发送邮件”)
time.sleep(0.5)
print(“自动化全部测试完毕,请查看 result 文件下的 Html 报告”)
self.status.emit()#发射 step 信号给开始测试 slotStart 槽
class EmittingStream(QObject):
textWritten = pyqtSignal(str) #实例化一个 str 参数信号
def write(self, text):
self.textWritten.emit(str(text))#发射一个 str 参数信号给 normalOutputWritten 槽
class MainWindow(QMainWindow):
name = “”“主界面”""
def init(self):
super().init()
self.title = “” #初始化界面工具名称
self.left = 300
self.top = 300
self.width = 750
self.height = 500
self.imge = ‘’ #初始化界面工具图标
self.initUI()
def initUI(self):
self.setWindowTitle(self.title) #设置 GUI 界面名称
self.setGeometry(self.left, self.top, self.width, self.height) #设置 GUI 界面大小
self.setWindowIcon(QIcon(self.imge)) #设置 GUI 界面图标
self.textedit = QTextEdit(self) #添加一个 text 文本框
self.textedit.move(300, 50)
self.textedit.resize(400, 350)
self.textedit.setObjectName(“textedit”) #设置一个 text 文本框名字
self.textedit.setReadOnly(True) #设置文本框只读模式
self.settingAction = QAction(QIcon(), ‘&DUT 串口参数’, self) #添加一个菜单栏属性
self.versionAction = QAction(QIcon(), ‘&联盛德发布\n’
‘V1.1 测试版’, self) #添加一个菜单栏属性
self.Secondwindow = Secondwindow() #实例化第二个 GUI 界面对象
self.settingAction.triggered.connect(self.Secondwindow.show) #这是点击串口参数弹出另一个 GUI 界面
mainMenu = self.menuBar()
fileMenu = mainMenu.addMenu(‘设置’) #添加一个菜单栏
viewMenu = mainMenu.addMenu(‘版本’)
fileMenu.addAction(self.settingAction)
viewMenu.addAction(self.versionAction)
self.button = QPushButton(‘AT 测试’, self) #添加一个开始测试按钮
self.button.move(50, 70)
self.exitbu = QPushButton(‘退出’, self) #添加一个退出按钮
self.exitbu.move(90, 350)
self.button2 = QPushButton(‘加网测试’, self) #添加一个开始测试按钮
self.button2.move(170, 70)
self.exitbu.clicked.connect(QCoreApplication.instance().quit) #为退出按钮链接退出快捷功能
self.thread = ThreadQt() #实例化 ThreadQt 线程对象
self.threadAP = ThreadAp() #实例化 ThreadAp 线程对象
self.button.clicked.connect(self.slotStart)
self.button2.clicked.connect(self.startAp)
self.thread.status.connect(self.slotEnd)
self.thread.steps.connect(self.doAction)
self.threadAP.apstatus.connect(self.endAp)
self.pbar = QProgressBar(self)
self.pbar.setGeometry(50, 450, 700, 25) # 从左上角 30-50 的界面,显示一个 200*25 的界面
self.setWindowFlags(Qt.WindowMinimizeButtonHint) # 禁止最大化
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)# 重定向输出
sys.stderr = EmittingStream(textWritten=self.normalOutputWritten)
def slotStart(self):
try:
os.remove(os.getcwd()+r’\config\time.txt’)
except:
pass
self.pbar.setValue(0)
self.button.setText(“自动化测试中”)
self.button.setEnabled(False)
self.thread.start()
def slotEnd(self):
self.button.setText(“测试”)
self.button.setEnabled(True)
def doAction(self,steps):
self.pbar.setValue(steps)
def startAp(self):
self.pbar.setValue(0)
self.button2.setText(“自动化测试中”)
self.button2.setEnabled(False)
self.threadAP.start()
# try:
# self.threadmail.start()
# except:
# pass
def endAp(self):
self.button2.setText(“测试”)
self.button2.setEnabled(True)
def del(self):
sys.stdout = sys.stdout
sys.stderr = sys.stderr
def normalOutputWritten(self, text):
cursor = self.textedit.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.insertText(text)
self.textedit.setTextCursor(cursor)
self.textedit.ensureCursorVisible()
def main():
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec())
if name == ‘main’:
main()
用 os.system 启动程序。程序输出数据都丢到 sys.stdout。怎么拿出来动态存在一个变量,不太清楚。
用 r=subprocess.Popen 可以用 r.communicate()拿数据。
你可以先写小脚本,再慢慢改。
嗯嗯,用 os.popen()获取到内容,我需要 read 一下然后打印出来,这样能实现但是就不是实时同步了,等待测试执行完毕后,可以打印出信息。
谁说不能实时了?
fp = os.popen(‘run script’)
for line in iter(fp.readline, ‘’):
print(line, end=’’)
按行输出
fp = os.popen(cmd) rd = fp.readlines() for i in rd: print(i) 我是这样的不实时,感谢大佬 为小弟解了难题,爱你么么!!!

