基本上,我问的是如何将不断更新的程序显示在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()
答案 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
。)但这足以展示基础知识。