20895


ラベルの更新をしたいのですが、１つの関数で2回更新したいのですがsleepのような時間の要する関数を使ってもラベルのテキストは更新されないのです。それは、mainloopの最後に到達したときに更新されるからかなと考えたのですが、更新させる方法はありますでしょうか？

以下のコードは直面した問題を抽象化したものです。sleepは時間のかかる処理とでも置き換えてください。実際にこのコードを実行すると、この問題に直面すると思います。

[code]

    from Tkinter import *
    import time
    
    class Window:
        def __init__(self):
            self.flg = False
            self.root = Tk()
            self.txt = StringVar()
            Button(self.root, text="test", command=self.changeLabel).pack()
            self.txt.set("hoge")
            Label(self.root, textvariable=self.txt).pack()
    
        def changeLabel(self):
            self.txt.set("hogehoge")
            time.sleep(2) # sleepのような時間のかかる処理がしたい
            self.txt.set("hogehogehoge")
    
    if __name__ == '__main__':
        w = Window()
        w.root.mainloop()
    
[/code]

よろしくお願いします。


CC BY-SA 3.0
2016-01-13T05:46:44.797
20876
2016-01-14T06:41:55.390
2016-01-14T03:07:09.943
2521
13818
question
python tkinter
Tkinterでのラベルの更新


change_label()を呼び出すと`self.text`は実際に"hogehoge"になりますが、TkはそのLabel
widgetをもう一回表示するチャンスがない、なぜなら機能復帰がこないから。

`sleep(2)`のすぐ前に`print`をすると端末で確認できます

[code]

    class Window:
        def __init__(self):
            self.flg = False
            self.root = Tk()
            self.text = StringVar()
            self.text.set('spam')
            self.button = Button(self.root,
                                 text = 'test',
                                 command = self.change_label)
            self.button.pack()
            self.label = Label(self.root, textvariable = self.text)
            self.label.pack()
    
        def change_label(self):
            self.text.set('BACON')
            print self.text.get()
            time.sleep(2) # 機能復帰はまだですね…
            self.text.set('eggs')
    
    if __name__ == '__main__':
        w = Window()
        w.root.mainloop()
    
[/code]

端末では:

[code]

    ceverett@changa:~/Code/python/tk$ ./tk_label.py 
    BACON
    
[/code]

`change_label()`を呼び出したが機能復帰をTkのmainloopにくるまでは画面(Tk Window)がマヒします

[code]

    def change_label(self):
        if self.text.get() == 'spam':
            self.text.set('eggs')
        elif self.text.get() == 'eggs':
            self.text.set('spam')
    
[/code]

これでchang_label()はtoggle buttonににります


CC BY-SA 3.0
2016-01-13T15:20:41.650
20890
2016-01-13T15:20:41.650
2371
20876
answer


スレッドを分けるのが適切と思います。

[code]

    from Tkinter import *
    import threading
    from time import sleep
    
    class Window:
        def __init__(self):
            self.flg = False
            self.root = Tk()
            self.txt = StringVar()
            Button(self.root, text="test", command=self.changeLabel ).pack()
            self.txt.set("hoge")
            Label(self.root, textvariable=self.txt).pack()
    
        def changeLabel(self):
            self.txt.set("Start...")
            t = threading.Thread(target=FunctionThatTakeALotOfTime, args=(self,))
            t.start()
    
    def FunctionThatTakeALotOfTime(w):
        sleep(2)
        w.txt.set("Finished!")
    
    if __name__ == '__main__':
        w = Window()
        w.root.mainloop()
    
[/code]

処理の内容によっては、必要に応じて同時に2つ以上関数が実行されないような処理を追加してください。(処理実行中はコマンド実行ボタンを無効化するなど。)


CC BY-SA 3.0
2016-01-13T22:54:33.300
20895
2016-01-14T06:41:55.390
2016-01-14T06:41:55.390
6092
6092
20876
answer