【问题标题】:Python - Regarding tkinter and a updating programPython - 关于 tkinter 和更新程序
【发布时间】:2014-12-24 13:07:59
【问题描述】:

基本上,我在问如何将一个不断更新的程序显示到 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) 的文本函数对其进行设置。我对 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 的窗口中。 这是我的新代码,有一个新问题。我收到一条错误消息,指出 theText 函数中未定义“generate_money”。这些新功能在我的 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()

【问题讨论】:

  • 看起来您已经缩进了 generate_money 函数,使其成为 FrameApp 类的一部分。不要那样做。这使得 generate_money 成为您的 FrameApp 对象的方法,而不是顶级函数。 (您可以完成这项工作,但您必须在方法中添加一个self 参数,并将其称为self.generate_money 而不是generate_money,而且没有充分的理由这样做在这里。)
  • 另外,如果你想让它真正做任何事情,除了在后台线程中引发 NameError 之外,你将不得不编写一个 do_stuff_with 函数。
  • 抱歉,最后一个问题。我已经将 generate_money 移到了课堂之外。但是,我仍然对为 do_stuff_with 放置什么感到困惑。我会以某种方式使用 text.get() 从线程中获取行,然后 text.insert() 将它们插入到文本框中。
  • 你不需要使用text.get();文本小部件中的任何内容都已经在文本小部件中,对吗?只需在末尾插入新行。 (另外,请注意变量在这里被称为textwidget,在类中被称为self.t;它在任何地方都没有被称为text......)

标签: python tkinter


【解决方案1】:

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

第一部分很简单:您可以使用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 上有第三方“异步子进程”包装器,这可能是解决此问题的另一种方法。)

所以,您需要结合两者。有一个线程阻塞子进程并发布消息,您可以在主线程中以非阻塞方式检查,例如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 提前关闭,或者在退出时等待它完成。 (或者,或者,因为你知道它不会留下任何“危险垃圾”突然被杀死,你可以只设置self.t.daemon = True。)但这足以展示基础知识。

【讨论】:

  • 非常感谢您的回复。虽然我遇到了一个问题。我在这里发布新代码时遇到问题,所以我会更新线程。
猜你喜欢
  • 2011-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多