2014-10-28 21 views
0

基本上,我問的是如何將不斷更新的程序顯示到tkinter的文本小部件中。Python - 關於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程序。正如你所看到的,我已經將它集中並設置了一個定義爲文本(自我)的文本函數。我對文本(自我)做了任何事情,因爲我不知道從哪裏開始。這個效果很好,如預期的那樣,它的中心是標題。

# 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的窗口中。 這是我的新代碼有一個新問題。我收到一個錯誤,指出'generate_money'沒有在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

看起來您已經縮進了'generate_money'函數,因此它是'FrameApp'類的一部分。不要這樣做。這使'generate_money'成爲你的'FrameApp'對象的一個​​方法,而不是一個頂層函數。 (你可以做這個工作,但是你必須爲這個方法增加一個'self'參數,並且把它稱爲'self.generate_money'而不是'generate_money',這裏沒有很好的理由去做這件事。) – abarnert 2014-10-29 00:12:01

+0

另外,如果你希望在後臺線程中拋出一個'NameError',除了'do_stuff_with'函數外,你還得編寫一個'do_stuff_with'函數。 – abarnert 2014-10-29 00:12:26

+0

對不起,最後一個問題。我在課堂外移動了generate_money。不過,我仍然對do_stuff_with的內容感到困惑。我會以某種方式使用text.get()從線程獲取線條,然後使用text.insert()將它們插入到文本框中。 – TastyOs 2014-10-29 01:11:35

回答

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上有第三方「異步子進程」封裝,這可能是解決此問題的替代方法。)

因此,您需要結合這兩個這些。有一個線程可以阻塞子進程,並在可以在主線程中以非阻塞方式檢查的東西上發佈消息,如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)。但這足以顯示基本知識。

+0

非常感謝您的回覆。但我遇到了一個問題。我在這裏發佈新代碼的問題,所以我會更新線程。 – TastyOs 2014-10-28 23:58:36