Python - 关于tkinter和更新程序

时间:2014-10-28 23:00:28

标签: python tkinter

基本上,我问的是如何将不断更新的程序显示在tkinter的文本小部件中。

from tkinter import Tk, Frame, Text, BOTH

class FrameApp(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent, background="white")

        self.parent = parent
        self.parent.title("Ethis")
        self.pack(fill=BOTH, expand=1)
        self.centerWindow()
    def centerWindow(self):
        w = 900
        h = 450
        sw = self.parent.winfo_screenwidth()
        sh = self.parent.winfo_screenheight()

        x = (sw - w)/2
        y = (sh - h)/2

        self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y))

    def theText(self):
        w = Text ()
def main():
    root=Tk()
    app = FrameApp(root)
    root.mainloop()


if __name__ == '__main__':
    main()

这是我的tkinter计划。正如您所看到的,我将其置于中心并使用定义为文本(自我)的文本函数进行设置。我已经对theText(self)做了任何事情,因为我不知道从哪里开始。这项工作很好,它正如预期的那样以它的标题在中心启动。

# Money Generator Mark 1
import time

t = 'true'

while t == 'true':
    s = 0
    x = 1
    print ("You have $%s." % (s))
    time.sleep(.75)
    t = 'false'

while t == 'false':         
    s = s + (1 * x)
    print ("You have $%s." % (s))
    time.sleep(.75)
    if s >= 100 and s < 200:
        x = 2 
    if s >= 200:
        x = 4

在这里,我有另一个程序可以正常运行。我把Money Generator称为类似于Cookie Clicker和Candy Box,这些类型的东西。这也适用于命令框,功能和打印到那里。我想知道如何整合这两个独立的程序,以便这里列出的第二个程序将显示在tkinter的窗口中。 这是我的新代码,它有一个新问题。我收到一条错误消息,指出&#39; generate_money&#39;未在theText函数中定义。这些新函数在我的frameApp类中。

def theText(self):
    self.w = Text()
    self.t = threading.Thread(target=generate_money, args=(self.w))
    self.t.daemon = True

def generate_money(textwidget):
    p = subprocess.Popen([sys.executable, os.path.join('window.py', 'moneygenerator.py')], 
                         stdout = subprocess.PIPE)
    for line in p.stdout:
        do_stuff_with(textwidget, line)
    p.close()

1 个答案:

答案 0 :(得分:0)

不幸的是,这比你想要的要复杂一点。

第一部分很简单:您可以使用subprocess模块运行后台脚本并捕获其输出:

p = subprocess.Popen([sys.executable, os.path.join(scriptpath, 'moneygenerator.py')], 
                     stdout = subprocess.PIPE)
for line in p.stdout:
    do_stuff_with(line)
p.close()

问题是在Tkinter回调中执行此操作会阻止整个程序,直到后台程序完成。因此,您不必在每一行上获得更新,而是冻结应用程序,直到操作系统杀死您/显示一个沙滩球/等。

有两种常见的解决方案可以在不阻塞的情况下执行操作:在线程上执行此操作 - 这很容易,但您无法从后台线程访问Tkinter小部件。或者以非阻塞的方式检查子进程的管道 - 如果有一个跨平台的方法可以做到这一点而不会永远阻塞,这将是很好的。 (但是,PyPI上有第三方&#34; async subprocess&#34;包装器,这可能是解决这个问题的另一种方法。)

所以,你需要结合这两个。有一个在子进程上阻塞的线程,并在主线程中以非阻塞的方式发布你可以检查的消息,如queue.Queue

但是,不是自己编写,而是一个名为mtTkinter的好包装器,可以为您完成大部分难题。您可以将后台线程编写为访问窗口小部件是合法的,它将拦截该访问并将其转换为队列帖子。可悲的是,mtTkinter在Python 3中不起作用 - 但它看起来很容易修复;我在几分钟内slapped together a port。虽然我还没有对它进行过多次测试,但我认为这可能是最简单的前进方式。

所以:

from tkinter import Tk, Frame, Text, BOTH
import subprocess
import sys
import threading

# ...

def generate_money(textwidget):
    p = subprocess.Popen([sys.executable, os.path.join(scriptpath, 'moneygenerator.py')], 
                         stdout = subprocess.PIPE)
    for line in p.stdout:
        do_stuff_with(textwidget, line)
    p.close()

# ...

class FrameApp(Frame):
    # ...
    def theText(self):
        self.w = Text()
        self.t = threading.Thread(target=generate_money, args=(self.w,))

你可能想要在退出时添加一些方法告诉self.t提前关闭,或者等待它完成。 (或者,或者,因为你知道它不会留下任何&#34;危险的垃圾&#34;它突然被杀死,你可能只能设置self.t.daemon = True。)但这足以展示基础知识。