输出控制台(打印功能)到 Gui TextArea
Posted
技术标签:
【中文标题】输出控制台(打印功能)到 Gui TextArea【英文标题】:Output Console (print function) to Gui TextArea 【发布时间】:2021-08-14 11:03:24 【问题描述】:我在 Windows 上为 Python 3.8 制作了 QtQuick Window Gui 应用程序。我想不通的最后一件事是如何在 Gui 文本区域中显示 Python print()
。我想要的是,无论在我的 Python 代码中,无论在哪里打印语句并在运行时执行,我都想将它输出到我的 Gui 应用程序中的 TextArea 中
我阅读了以下帖子,但未能实现它,发生了不同的错误并且比以前更困惑:
最接近和最有用的是这个:
How to capture output of Python's interpreter and show in a Text widget?还有其他一些人:
Python/PyQt/Qt Threading: How do I print stdout/stderr right away?
How to Redirect a Python Console output to a QTextBox
How can I flush the output of the print function?
How do I direct console output to a pyqt5 plainTextEdit widget with Python?
Python Printing StdOut As It Received
将字符串从 Python 发送到 QML TextArea 的工作示例代码
main.py
import os
from pathlib import Path
import sys
from vantage import daily
# load GUI libs
from PySide2.QtGui import QGuiApplication
from PySide2.QtCore import QSettings, QObject, Signal, Slot
from PySide2.QtQml import QQmlApplicationEngine
# load app
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
class Backend(QObject):
textwritten = Signal(str, arguments=['writen'])
def __init__(self):
super().__init__()
self.timer = QTimer()
self.timer.setInterval(100)
self.timer.timeout.connect(self.writer)
self.timer.start()
# console output write function
def writer(self):
towrite = 'i am writing'
self.textwritten.emit(str(towrite))
# create an instance of the Python object (Backend class)
back_end = Backend()
# give data back to QML
engine.rootObjects()[0].setProperty('writen', back_end)
# close app
sys.exit(app.exec_())
main.qml
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Controls 2.15
Window
width: 640
height: 480
visible: true
color: "#2f2f2f"
title: qsTr("alpha")
/*print out console text*/
property string texted: "Console Text"
property QtObject writen
ScrollView
id: scrollViewCon
x: 58
y: 306
width: 507
height: 100
ScrollBar.vertical.verticalPadding: 4
ScrollBar.vertical.minimumSize: 0.4
ScrollBar.vertical.contentItem: Rectangle
implicitWidth: 6
implicitHeight: 100
radius: width / 2
color: control.pressed ? "#81e889" : "#f9930b"
TextArea
font.family: control.font
font.pointSize: 8
color:"#f9930b"
wrapMode: TextEdit.Wrap
KeyNavigation.priority: KeyNavigation.BeforeItem
KeyNavigation.tab: textField
placeholderTextColor : "#f9930b"
opacity: 1
text: texted
placeholderText: texted //qsTr("Console")
readOnly: true
background: Rectangle
radius: 12
border.width: 2
border.color: "#f9930b"
Connections
target: writen
function onTextwritten(msg)
texted = msg;
我认为需要发生的是每次 sys.stdout 被 print() 调用时,它都会自己发出一个信号?
保持 main.qml 不变,只更改 main.py
main.py
...
class Backend(QObject):
textwritten = Signal(str, arguments=['writen'])
def __init__(self):
super().__init__()
sys.stdout = self.writer(str(sys.stdout))
def writer(self, message):
#towrite = 'i am writing'
self.textwritten.emit(message)
...
【问题讨论】:
您是坚持使用 print() 还是只需要一种从代码中的任何位置输出文本的方法?如果是后者,我建议看一下 qDebug 和/或 python 日志库。我个人将日志输出重定向到 QPlainTextEdit 并且效果很好。 是的,基本上只是打印出标准输出流和标准错误,我想稍后在没有控制台窗口的情况下打包应用程序,以便用户可以得到一些反馈代码中当前发生的事情 【参考方案1】:print 函数覆盖 sys.stdout,因此解决方案是分配一些 QObject,该 QObject 具有发出信号的 write 方法。为此,您可以使用 contextlib.redirect_stdout:
import os
import sys
from contextlib import redirect_stdout
from functools import cached_property
from pathlib import Path
from PySide2.QtCore import (
QCoreApplication,
QDateTime,
QObject,
Qt,
QTimer,
QUrl,
Signal,
)
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
CURRENT_DIRECTORY = Path(__file__).resolve().parent
class RedirectHelper(QObject):
stream_changed = Signal(str, name="streamChanged", arguments=["stream"])
def write(self, message):
self.stream_changed.emit(message)
class TimerTest(QObject):
@cached_property
def timer(self):
return QTimer(interval=1000, timeout=self.handle_timeout)
def handle_timeout(self):
print(QDateTime.currentDateTime().toString())
def start(self):
self.timer.start()
def main():
ret = 0
redirect_helper = RedirectHelper()
with redirect_stdout(redirect_helper):
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("redirectHelper", redirect_helper)
filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
url = QUrl.fromLocalFile(filename)
def handle_object_created(obj, obj_url):
if obj is None and url == obj_url:
QCoreApplication.exit(-1)
engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
engine.load(url)
timer_test = TimerTest()
timer_test.start()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main()
import QtQuick 2.12
import QtQuick.Controls 2.12
ApplicationWindow
id: root
width: 640
height: 480
visible: true
Flickable
id: flickable
flickableDirection: Flickable.VerticalFlick
anchors.fill: parent
TextArea.flickable: TextArea
id: textArea
anchors.fill: parent
readOnly: true
font.pointSize: 8
color: "#f9930b"
wrapMode: TextEdit.Wrap
placeholderTextColor: "#f9930b"
opacity: 1
placeholderText: qsTr("Console")
background: Rectangle
radius: 12
border.width: 2
border.color: "#f9930b"
ScrollBar.vertical: ScrollBar
Connections
function onStreamChanged(stream)
textArea.insert(textArea.length, stream);
target: redirectHelper
【讨论】:
谢谢 eyllanesc,据我测试,它符合我的要求。效果很好。您将 Scrollview 更改为 flickable 的任何特定原因,我的意思是它适用于两者。以上是关于输出控制台(打印功能)到 Gui TextArea的主要内容,如果未能解决你的问题,请参考以下文章