如何使用 Python 将控制台输出定向到 pyqt5 plainTextEdit 小部件?

2022-01-12 00:00:00 python pyqt5 displayobject

问题描述

我正在尝试在 PyQt5 的 QplainTextEdit 小部件中显示 python 脚本的控制台输出.

I am trying to display console output of a python script in a QplainTextEdit widget in PyQt5.

我收到此错误:

TypeError:调用元类库时出错元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类

TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

我已经在 pyqt GUI 文件中定义了我的对象,并且我相信我拥有所有的导入.

I have defined my objects in the pyqt GUI file and I believe that I have all the imports.

我已经修改了这个问题的代码:

I have amended the code in this question:

from PyQt5.QtCore import QRectF, Qt
from PyQt5.QtWidgets import QFileDialog, QPlainTextEdit
from PyQt5 import QtCore, QtGui, QtWidgets
from PIL import Image, ImageQt, ImageEnhance
# from PyQt5.QtGui import Qt
from pyqtgraph.examples.text import text

from covid19gui_V3 import Ui_MainWindow
import os
import sys

input_img = Image.open("/home/ironmantis7x/Documents/Maverick_AI/Python/keras-covid-19/maverickAI30k.png")
text_edit = QPlainTextEdit()

class EmittingStream(QtCore.QObject):

    textWritten = QtCore.pyqtSignal(str)
    def write(self, text):
        self.textWritten.emit(str(text))

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    textWritten = QtCore.pyqtSignal(str)
    def __init__(self, parent=None, **kwargs):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.ShowIButton.clicked.connect(self.do_test)
        self.chooseStudy.clicked.connect(self.do_choosestudy)
        self.RunButton_3.clicked.connect(self.do_runstudy)
        self.scene = QtWidgets.QGraphicsScene(self)
        self.graphicsView.setScene(self.scene)
        w, h = input_img.size
        self.pixmap_item = self.scene.addPixmap(QtGui.QPixmap())
        # self.graphicsView.fitInView(QRectF(0, 0, w, h), Qt.KeepAspectRatio)
        self.graphicsView.update()
        self.plainTextEdit.update()
        self.level = 1
        self.enhancer = None
        self.timer = QtCore.QTimer(interval=500, timeout=self.on_timeout)
        sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)

    def write(self, text):
        self.textWritten.emit(str(text))

    @QtCore.pyqtSlot()
    def do_test(self):
        # input_img = Image.open("/home/ironmantis7x/Documents/Maverick_AI/Python/keras-covid-19/maverickAI30k.png")
        self.enhancer = ImageEnhance.Brightness(input_img)
        self.timer.start()
        self.ShowIButton.setDisabled(True)

    @QtCore.pyqtSlot()
    def on_timeout(self):
        if self.enhancer is not None:
            result_img = self.enhancer.enhance(self.level)
            qimage = ImageQt.ImageQt(result_img)
            self.pixmap_item.setPixmap(QtGui.QPixmap.fromImage(qimage))
        if self.level > 7:
            self.timer.stop()
            self.enhancer = None
            self.level = 0
            self.ShowIButton.setDisabled(False)
        self.level = 1
        self.ShowIButton.setDisabled(False)

    @QtCore.pyqtSlot()
    def do_choosestudy(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.AnyFile)
        if dlg.exec_():
            filenames = dlg.selectedFiles()
            f = open(filenames[0], 'r')

    @QtCore.pyqtSlot()
    def do_runstudy(self):
        os.system("df -h")
        # filetext = open('screenout.txt').read()
        # filetext.close()
        # textViewValue = self.plainTextEdit.toPlainText()
        # QPlainTextEdit.appendPlainText(self, str(textViewValue))
        # sys.stdout = self(textWritten=self.textWritten)
        self.normalOutputWritten(text_edit)

    def __del__(self):
        # Restore sys.stdout
        sys.stdout = sys.__stdout__

    def normalOutputWritten(self, text_edit):
        #cursor = self.plainTextEdit.textCursor()
        #cursor.movePosition(QtGui.QTextCursor.End)
        #cursor.insertText(text_edit)
        self.plainTextEdit.appendPlainText(text_edit)
        #self.plainTextEdit.ensureCursorVisible()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

我怎样才能使它正常工作?

How can I make this work correctly?

我确实对该主题进行了研究,这是我在发布问题之前用来尝试解决问题的主要资源之一:如何捕获 Python 解释器的输出并显示在 Text 小部件中?

I indeed DID do research into the topic and this is one of the main resources I used to try to solve the issue before I posted my question: How to capture output of Python's interpreter and show in a Text widget?

我在帖子中修改了我的代码,以反映我用来帮助我解决问题的链接中的代码建议.

I have revised my code in the post to reflect code suggestions in the link I used to help me with my issue.

我仍然无法让它正确运行.我现在收到此错误:

I am still unable to get this to run correctly. I now get this error:

self.plainTextEdit.appendPlainText(text_edit) 类型错误:appendPlainText(self, str):参数 1 具有意外类型'QPlainTextEdit'

self.plainTextEdit.appendPlainText(text_edit) TypeError: appendPlainText(self, str): argument 1 has unexpected type 'QPlainTextEdit'


解决方案

我有一个用户界面,TableManagerWindow,我一直在 Qt 设计器中维护和开发.通过 pyuic 转换为 *.py 文件后,我能够实现您在上面提供的链接中提出的 Ferdinand Beyer 的建议.将文本打印到终端的简单按钮,它确实通过 append() 附加到 QTextEdit 小部件.由于某种原因,不确定这是否适合您,但我可以保证它也对我有用.我不够精明,无法了解导致您的问题的细微差别,但我想我会把它放在这里以防万一.如果它无关紧要,管理员可以随意删除它,但它确实有效.

I have a user interface, TableManagerWindow, that I've been maintaining and developing in Qt designer. After converting via pyuic to a *.py file, I was able to implement what Ferdinand Beyer had suggested in the link you provided above. Simple button to print text to terminal and it indeed does get appended to the QTextEdit widget via append(). Not sure this fits the bill for you for some reason, but I can vouch that it worked for me as well. I'm not savvy enough to get the nuance that is causing your issue, but figured I'd put this here just in case. Admins feel free to delete this if it's extraneous, but it works.

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

# Define a stream, custom class, that reports data written to it, with a Qt signal
class EmittingStream(QtCore.QObject):

    textWritten = QtCore.pyqtSignal(str)

    def write(self, text):
        self.textWritten.emit(str(text))

class Ui_TableManagerWindow(object):
    def setupUi(self, TableManagerWindow):
        #define all of my widgets, layout, etc here
        .
        .
        .
        # Install a custom output stream by connecting sys.stdout to instance of EmmittingStream.
        sys.stdout = EmittingStream(textWritten=self.output_terminal_written)

        # Create my signal/connections for custom method
        self.source_dir_button.clicked.connect(self.sourceDirButtonClicked)

        self.retranslateUi(TableManagerWindow)
        QtCore.QMetaObject.connectSlotsByName(TableManagerWindow)


    def retranslateUi(self, TableManagerWindow):
        .
        .
        .

    #custom method that prints to output terminal.  The point is to have this emmitted out to my QTextEdit widget.
    def sourceDirButtonClicked(self):
        for i in range(10):
            print("The Source DIR button has been clicked " + str(i) + " times")

    #custom method to write anything printed out to console/terminal to my QTextEdit widget via append function.
    def output_terminal_written(self, text):
        self.output_terminal_textEdit.append(text)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    TableManagerWindow = QtWidgets.QMainWindow()
    ui = Ui_TableManagerWindow()
    ui.setupUi(TableManagerWindow)
    TableManagerWindow.show()
    sys.exit(app.exec_())

相关文章