使用 tkinter 在 GUI 上显示程序的输出?

2025-03-26 09:08:00
admin
原创
16
摘要:问题描述:我想在 GUI 上显示程序的“实时”输出(其中打印的所有内容)。如何访问我的输出?以及在文本框中显示它的正确方法是什么?已编辑:我哪里错了?(我希望“hello world”出现在文本框内。(Test2是正在运行的程序))from tkinter import * from subprocess i...

问题描述:

我想在 GUI 上显示程序的“实时”输出(其中打印的所有内容)。如何访问我的输出?以及在文本框中显示它的正确方法是什么?

已编辑:我哪里错了?(我希望“hello world”出现在文本框内。(Test2是正在运行的程序))

from tkinter import *
from subprocess import *

print("Hello world")

def func():
    proc = Popen("Test2.py", stdout=PIPE, shell=True)
    proc = proc.communicate()
    output.insert(END, proc)

Master = Tk()
Check = Button(Master, text="Display output", command=func)
Quit = Button(Master, text="Exit", fg="red", command=Master.quit)
output = Text(Master, width=40, height=8)

Check.pack(padx=20, pady=8)
Quit.pack(padx=20, pady=18)
output.pack()

Master.mainloop()

解决方案 1:

我花时间调试和修改了另一个问题errorwindow.py的答案中的模块,以便它可以在 Python 23 中工作——链接答案中的代码是为 Python 2.x 编写的。注意,我只做了让它在两个版本下运行所需的最少工作。修改后的脚本版本已被命名(尽管它也适用于 Python 2)。errorwindow3k.py

大多数问题都只是由于模块重命名而引起的,但有一个更难解决的问题,原来是由于版本 3 中将 Unicode 字符串切换为默认字符串类型而引起的 — 显然(至少在 Windows 上是这样),进程之间的管道是字节流,而不是 Unicode 字符。幸运的是,在 Python 2 中解码然后在另一端编码数据的“修复”也不会造成影响,这使得纠正问题相当容易。

它的优点在于使用起来非常简单。只需使用import它,从那时起,发送到sys.stderr或的任何输出sys.stdout都会tkinter根据需要出现基于 的输出窗口以显示信息。在您的示例代码中,只需import errorwindow3k在 之前某处插入 即可print("Hello world")

文件errorwindow3k.py

# Code derived from Bryan Olson's source posted in this related Usenet discussion:
#   https://groups.google.com/d/msg/comp.lang.python/HWPhLhXKUos/TpFeWxEE9nsJ
#   https://groups.google.com/d/msg/comp.lang.python/HWPhLhXKUos/eEHYAl4dH9YJ
#
#  See the comments and doc string below.
#
#   Here's a module to show stderr output from console-less Python
#   apps, and stay out of the way otherwise. I plan to make a ASPN
#   recipe of it, but I thought I'd run it by this group first.
#
#   To use it, import the module. That's it. Upon import it will
#   assign sys.stderr.
#
#   In the normal case, your code is perfect so nothing ever gets
#   written to stderr, and the module won't do much of anything.
#   Upon the first write to stderr, if any, the module will launch a
#   new process, and that process will show the stderr output in a
#   window. The window will live until dismissed; I hate, hate, hate
#   those vanishing-consoles-with-critical-information.
#
#   The code shows some arguably-cool tricks. To fit everthing in
#   one file, the module runs the Python interpreter on itself; it
#   uses the "if __name__ == '__main__'" idiom to behave radically
#   differently upon import versus direct execution. It uses tkinter
#   for the window, but that's in a new process; it does not import
#   tkinter into your application.
#
#   To try it out, save it to a file -- I call it "errorwindow.py" -
#   - and import it into some subsequently-incorrect code. For
#   example:
#
#        import errorwindow
#
#        a = 3 + 1 + nonesuchdefined
#
#   should cause a window to appear, showing the traceback of a
#   Python NameError.
#
#   --
#   --Bryan
#   ----------------------------------------------------------------
#
#   martineau - Modified to use subprocess.Popen instead of the os.popen
#               which has been deprecated since Py 2.6. Changed so it
#               redirects both stdout and stderr. Added numerous
#               comments, and also inserted double quotes around paths
#               in case they have embedded space characters in them, as
#               they did on my Windows system.
#
#               Recently updated it to work in both Python 2 and Python 3.

"""
    Import this module into graphical Python apps to provide a
    sys.stderr. No functions to call, just import it. It uses
    only facilities in the Python standard distribution.

    If nothing is ever written to stderr, then the module just
    sits there and stays out of your face. Upon write to stderr,
    it launches a new process, piping it error stream. The new
    process throws up a window showing the error messages.
"""
import subprocess
import sys
try:
    import thread
except ModuleNotFoundError:  # Python 3
    import _thread as thread
import os

EXC_INFO_FILENAME = 'exc_info.txt'

if __name__ == '__main__':  # When spawned as separate process.
    # create window in which to display output
    # then copy stdin to the window until EOF
    # will happen when output is sent to each OutputPipe created
    try:
        from Tkinter import BOTH, END, Frame, Text, TOP, YES
        import tkFont
        import Queue
    except ModuleNotFoundError:  # Python 3
        from tkinter import BOTH, END, Frame, Text, TOP, YES
        import tkinter.font as tkFont
        import queue as Queue

    Q_EMPTY = Queue.Empty  # An exception class.
    queue = Queue.Queue(1000)  # FIFO

    def read_stdin(app, bufsize=4096):
        fd = sys.stdin.fileno()  # File descriptor for os.read() calls.
        read = os.read
        put = queue.put
        while True:
            put(read(fd, bufsize))

    class Application(Frame):
        def __init__(self, master=None, font_size=8, text_color='#0000AA', rows=25, cols=100):
            Frame.__init__(self, master)
            # Create title based on the arguments passed to the spawned script:
            #   argv[0]: name of this script (ignored)
            #   argv[1]: name of script that imported this module
            #   argv[2]: name of redirected stream (optional)
            if len(sys.argv) < 2:
                title = "Output stream from unknown source"
            elif len(sys.argv) < 3:
                title = "Output stream from %s" % (sys.argv[1],)
            else:  # Assume it's a least 3.
                title = "Output stream '%s' from %s" % (sys.argv[2], sys.argv[1])
            self.master.title(title)
            self.pack(fill=BOTH, expand=YES)
            font = tkFont.Font(family='Courier', size=font_size)
            width = font.measure(' ' * (cols+1))
            height = font.metrics('linespace') * (rows+1)
            self.configure(width=width, height=height)
            self.pack_propagate(0)  # Force frame to be configured size.

            self.logwidget = Text(self, font=font)
            self.logwidget.pack(side=TOP, fill=BOTH, expand=YES)
            # Disallow key entry, but allow text copying with <Control-c>
            self.logwidget.bind('<Key>', lambda x: 'break')
            self.logwidget.bind('<Control-c>', lambda x: None)
            self.logwidget.configure(foreground=text_color)
            self.logwidget.insert(END, '==== Start of Output Stream ====

')
            self.logwidget.see(END)
            self.after(200, self.start_thread)  # Start queue polling thread.

        def start_thread(self):
            thread.start_new_thread(read_stdin, (self,))
            self.after(200, self.check_q)

        def check_q(self):
            log = self.logwidget
            log_insert = log.insert
            log_see = log.see
            queue_get_nowait = queue.get_nowait

            go = True
            while go:
                try:
                    data = queue_get_nowait().decode()  # Must decode for Python 3.
                    if not data:
                        data = '[EOF]'
                        go = False
                    log_insert(END, data)
                    log_see(END)
                except Q_EMPTY:
                    self.after(200, self.check_q)
                    go = False

    app = Application()
    app.mainloop()

else: # when module is first imported
    import traceback

    class OutputPipe(object):
        def __init__(self, name=''):
            self.lock = thread.allocate_lock()
            self.name = name

        def flush(self):  # no-op.
            pass

        def __getattr__(self, attr):
            if attr == 'pipe':  # Attribute doesn't exist, so create it.
                # Launch this module as a separate process to display any output
                # it receives.
                # Note: It's important to put double quotes around everything in
                # case any have embedded space characters.
                command = '"%s" "%s" "%s" "%s"' % (sys.executable,                # executable
                                                   __file__,                      # argv[0]
                                                   os.path.basename(sys.argv[0]), # argv[1]
                                                   self.name)                     # argv[2]
                #
                # Typical command and arg values on receiving end:
                #   C:Python3python[w].exe                                      # executable
                #   C:olsFilesPythonLibStack Overflowerrorwindow3k.py       # argv[0]
                #   errorwindow3k_test.py                                         # argv[1]
                #   stderr                                                        # argv[2]

                # Execute this script directly as __main__ with a stdin PIPE for sending
                # output to it.
                try:
                    # Had to also make stdout and stderr PIPEs too, to work with pythonw.exe
                    self.pipe = subprocess.Popen(command, bufsize=0,
                                                 stdin=subprocess.PIPE,
                                                 stdout=subprocess.PIPE,
                                                 stderr=subprocess.PIPE).stdin
                except Exception:
                    # Output exception info to a file since this module isn't working.
                    exc_type, exc_value, exc_traceback = sys.exc_info()
                    msg = ('%r exception in %s
' %
                            (exc_type.__name__, os.path.basename(__file__)))
                    with open(EXC_INFO_FILENAME, 'wt') as info:
                        info.write('fatal error occurred spawning output process')
                        info.write('exeception info:' + msg)
                        traceback.print_exc(file=info)

                    sys.exit('fatal error occurred')

            return super(OutputPipe, self).__getattribute__(attr)

        def write(self, data):
            with self.lock:
                data = data.encode()   # Must encode for Python 3.
                self.pipe.write(data)  # First reference to pipe attr will cause an
                                       # OutputPipe process for the stream to be created.


    # Clean-up any left-over debugging file.
    try:
        os.remove(EXC_INFO_FILENAME)  # Delete previous file, if any.
    except Exception:
        pass

    # Redirect standard output streams in the process that imported this module.
    sys.stderr = OutputPipe('stderr')
    sys.stdout = OutputPipe('stdout')

如果您对其工作原理有任何疑问,请随时在评论中提问。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2023  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1450  
  引言PLM(产品生命周期管理)合规性管理在汽车行业正扮演着日益关键的角色。随着汽车产业的不断发展,法规要求愈发严格,消费者对产品质量和安全性的期望也持续攀升。汽车企业需要在整个产品生命周期内确保合规,从设计研发阶段到生产制造,再到产品的售后使用与回收处理。这不仅关乎企业能否避免巨额罚款和法律诉讼,更影响着企业的品牌声誉...
plm是什么意思   4  
  引言企业的可持续发展如今已成为全球关注的焦点,这不仅关乎企业自身的长期生存与繁荣,更对整个社会和环境的健康发展有着深远影响。在实现可持续发展目标的征程中,企业面临着诸多复杂的挑战,涵盖了从资源管理、环境保护到社会责任履行等多个维度。而产品生命周期管理(PLM)系统作为一种强大的数字化工具,正逐渐展现出其在助力企业达成可...
plm软件有哪些   4  
  PLM(Product Lifecycle Management)软件在制造业中扮演着至关重要的角色,它贯穿于产品从概念设计到退役处理的整个生命周期,为企业提供了集成化的管理平台,有效提升了企业的创新能力、生产效率和产品质量。以下将详细阐述 PLM 软件在制造业中的五大核心应用场景。产品设计与研发管理在产品设计与研发阶...
国产plm软件排名   4  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用