当前位置: 首页 > 面试题库 >

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

仲孙阳
2023-03-14
问题内容

我想在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()

问题答案:

我花时间调试和修改了errorwindow.py我对另一个问题的0)答案中的模块,因此它可以在Python
2 3中工作—链接答案中的代码是针对Python
2.x编写的。请注意,我只做了使它在两个版本下都能正常工作的最低要求。该脚本的修改后的版本已被命名errorwindow3k.py(尽管事实也适用于Python
2)。


大多数问题仅是由于模块重命名所致,但是更难弄清楚的原因是,切换到Unicode字符串是版本3中的默认字符串类型-显然(无论如何在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 ====\n\n')
            self.logwidget.see(END)
            self.after(200, self.start_thread, ())  # Start 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 just 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:\Python3\python[w].exe                                      # executable
                #   C:\vols\Files\PythonLib\Stack Overflow\errorwindow3k.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\n' %
                            (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 files.
    try:
        os.remove(DEBUG_FILENAME)  # Delete previous file, if any.
    except Exception:
        pass
    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')

如果您对它的工作方式有任何疑问,请随时在评论中提问。



 类似资料:
  • 基本上,我正在Python中的一个订阅计数器应用程序的“草案”上工作。我使用YouTube数据API从YouTube获取数据,然后循环这段代码以更新订阅者计数。但是由于我的GUI代码在循环之后,它永远不会开始,因为循环是无限的,永远不会结束。我尝试将GUI部分放在代码之前,以获得子计数,但没有定义任何变量,因此返回错误。所以基本上,我的问题是如何重新组织它,使其工作,子计数在GUI中更新。我听说过

  • 我试图使一个客户端-服务器包成一个应用程序。因此,当应用程序打开时,服务器会自动进入待机/监听模式。问题是当运行服务器套接字时,它直到之后才显示gui。我希望gui和服务器套接字同时发生。 我已经注释掉了代码行,它按照预期工作,直到 我读过关于线程来解决这个问题的文章,但是我看到的例子都没有给出足够清晰的答案。我对python和编程还是相当陌生的。谢啦

  • 问题内容: 我有以下代码(python2.7): “ longrunning” bash脚本的输出是实时捕获的(显示在控制台中),但是Tkinter窗口仅在子进程结束后显示! 如何在子进程启动之前实时显示窗口并更新其内容? 问题答案: 终于我找到了解决方案。窗口构建后,必须添加: 然后,在小部件中插入每行之后,还必须仅在小部件上使用相同的方法强制刷新。

  • 我想在docker容器中运行Firefox(或任何图形应用程序)。 我的要求:当我启动容器时,我应该创建一个虚拟显示器,启动VNC服务器,然后启动GUI应用程序。这意味着容器成功启动后,我可以通过VNC客户端连接到容器内运行的GUI应用程序。当我关闭应用程序时,容器应该自动停止。 尝试1:我从这里的例子开始https://hub.docker.com/r/devopsil/vnc-firefox/

  • 问题内容: 我想要一个函数,当单击一个按钮时,它将使用URLLIB从Web上获取图像,并使用TKINTER在GUI中显示它。 我是URLLIB和TKINTER的新手,所以我在执行此操作时遇到了非常困难的时光。 对此进行了尝试,但是它显然不起作用,因为它使用了文本框,只会显示文本。 问题答案: 我不使用python 3,但是我可以给出在python 2.5+中有效的答案。我认为代码将在python

  • 本文向大家介绍Python中使用Tkinter模块创建GUI程序实例,包括了Python中使用Tkinter模块创建GUI程序实例的使用技巧和注意事项,需要的朋友参考一下 使用Tkinter模块来创建简单的GUI程序。 Tkinter的Widgets有:Button、Canvas、Checkbutton、Entry、Frame、Label、Listbox、Menu、Menubutton、Messa