1

我目前正在使用 easygui 运行脚本来接收用户输入。在命令行中运行的旧脚本只会在命令行中打印用户需要知道的任何内容,但我已将其更改为在需要输入时在新的 easygui 框中输出通知。

我想做的是有进度,正在运行的函数里面的每个动作,在它们完成时打印到一个文本框中。在命令行中我可以使用print "text",但我不能让它在easygui中实时发生。目前我正在附加一个列表,所以我有一个文本框,一旦一切完成,就会显示函数的结果,但我希望在注释过程完成时弹出大文本框窗口并打印出该行。这是可行的吗?

这是我添加列表的方式:

result_list = []
record_str = "\n Polling has completed for 502."
result_list.append(record_str)
eg.textbox("Polling Status", "Daily polling completion status:", result_list)
4

1 回答 1

4

我认为除了textbox修改模块之外,没有任何简单的方法可以让 EasyGUI 的功能做你想做的事情。因为它是一个函数而不是一个类,你甚至不能从它派生一个子类以便轻松地重用它的代码。

但是,Tkinter使用我曾经在comp.lang.python新闻组的一个线程中找到的一些代码的增强版本,创建一个单独的窗口是完全可行的,它只显示发送给它的文本行。

原始代码旨在仅捕获和显示stderr来自通常没有stderr输出句柄的 GUI 应用程序的输出,因此该模块被命名为errorwindow. 但是,我对其进行了修改,以便能够在我开发的一个基于应用程序的应用程序中同时重定向stderrstdout此类窗口easygui,但我从未有机会重命名它或更新其中的评论以提及stdout重定向。;¬)

无论如何,该模块通过定义和创建一个类文件类的两个实例来工作,OutputPipe当它被import编辑时命名并将它们分配给通常在 Python GUI 应用程序(在 Windows 上)中sys.stdout的I/O 流文件对象。当输出首次发送到其中任何一个时,相同的模块将作为单独的 Python 进程启动,其、和I/O 句柄与原始进程通过管道传输。sys.stderrNone.pywstdinstdoutstderr

有很多事情要做,但如果不出意外,稍微研究一下它可能会给你一些关于如何做你想做easygui的事情的想法。textbox希望这可以帮助。

注意:发布的代码适用于 Python 2.x ,如果有人感兴趣,在我对另一个问题的回答中,有一个修改后的版本可以在 Python 2 和 3 中运行。

文件errorwindow.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
#
#   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.

"""
    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
import thread
import os

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
    from Tkinter import BOTH, END, Frame, Text, TOP, YES
    import tkFont
    import Queue

    queue = Queue.Queue(100)

    def read_stdin(app, bufsize=4096):
        fd = sys.stdin.fileno()  # gets file descriptor
        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)
            # argv[0]: name of this script (not used)
            # argv[1]: name of script that imported this module
            # argv[2]: name of redirected stream (optional)
            if len(sys.argv) < 3:
                title = "Output Stream from %s" % (sys.argv[1],)
            else:
                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 copy 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, ())

        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()
                    if not data:
                        data = '[EOF]'
                        go = False
                    log_insert(END, data)
                    log_see(END)
                except Queue.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 __getattr__(self, attr):
            if attr == 'pipe':  # pipe attribute hasn't been created yet
                # 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
                # they have embedded space characters.
                command = '"%s" "%s" "%s" "%s"' % (sys.executable,                # command
                                                   __file__,                      # argv[0]
                                                   os.path.basename(sys.argv[0]), # argv[1]
                                                   self.name)                     # argv[2]

                # sample command and arg values on receiving end:
                #   E:\Program Files\Python\python[w].exe                         # command
                #   H:\PythonLib\TestScripts\PyRemindWrk\errorwindow.py           # argv[0]
                #   errorwindow.py                                                # argv[1]
                #   stderr                                                        # argv[2]

                # execute this script as __main__ with a stdin PIPE for sending output to it
                try:
                    # had to make stdout and stderr PIPEs too, to make it 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.txt', 'wt') as info:
                        info.write('msg:' + msg)
                        traceback.print_exc(file=info)
                    sys.exit('fatal error occurred spawning output process')

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

        def write(self, data):
            with self.lock:
                self.pipe.write(data)  # 1st reference to pipe attr will cause it to be created

    # redirect standard output streams in the process importing the module
    sys.stderr = OutputPipe('stderr')
    sys.stdout = OutputPipe('stdout')
于 2013-08-06T22:06:02.920 回答