【问题标题】:Output Console (print function) to Gui TextArea输出控制台(打印功能)到 Gui TextArea
【发布时间】:2021-08-14 11:03:24
【问题描述】:

我在 Windows 上为 Python 3.8 制作了 QtQuick Window Gui 应用程序。我想不通的最后一件事是如何在 Gui 文本区域中显示 Python print()。我想要的是,无论在我的 Python 代码中,无论在哪里打印语句并在运行时执行,我都想将它输出到我的 Gui 应用程序中的 TextArea 中

我阅读了以下帖子,但未能实现它,发生了不同的错误并且比以前更困惑:

最接近和最有用的是这个:

还有其他一些人:

将字符串从 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 并且效果很好。
  • 是的,基本上只是打印出标准输出流和标准错误,我想稍后在没有控制台窗口的情况下打包应用程序,以便用户可以得到一些反馈代码中当前发生的事情

标签: python qt qml qtquick2 pyside2


【解决方案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 的任何特定原因,我的意思是它适用于两者。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-10
  • 1970-01-01
  • 2016-10-04
  • 2021-12-13
相关资源
最近更新 更多