tkinter2 -after和thread實現TK窗體的條件更新

在tkinter做GUI的過程中,經常有這樣的需求:某些條件下窗體需要有響應變化。比如持續監聽輸入內容,直到輸入內容做退出動作或者顯示輸入內容並繼續要求輸入。
Use tkinter without mainloop頁面,作者介紹了三種方式實現,下面就after方法thread實現進行詳細介紹。

2 after方法

2.1 after與after_cancel

def after(self, ms, func=None, *args):
“”“Call function once after given time.
MS specifies the time in milliseconds.
FUNC gives the function which shall be called.
Additional parameters are given as parameters to the function call. Return identifier to cancel scheduling with after_cancel.”""

after實際上相當於一個定時器,作用是一段時間後(ms)繼續調用func函數。其餘參數是func函數的參數,用after_cancel函數取消調用func函數。

2.2 示例

2.2.1 需求

TkInter GUI持續監聽the bash input輸入內容。如果輸入內容爲’exit’就結束while循環,如果輸入內容不是’exit’,我們在GUI添加輸入內容相對應的label。

2.2.2 代碼

from tkinter import *

ROOT = Tk()

def ask_for_userinput():
    user_input = input("Give me your command! Just type \"exit\" to close: ")
    if user_input == "exit":
        ROOT.after_cancel(ask_for_userinput)
    else:
        label = Label(ROOT, text=user_input)
        label.pack()
        ROOT.after(100, ask_for_userinput)

LABEL = Label(ROOT, text="Hello, world!")
LABEL.pack()
ROOT.after(1000, ask_for_userinput)
ROOT.mainloop()

2.2.3 GUI

在這裏插入圖片描述

3 thread實現

3.1 簡介

threading.Thread(target=函數名,args=(調用參數,注意最後要有一個‘,’))可以實例化一個多線程對象。

  1. 啓動方法:先setDaemaon(True),後通過start開啓。

在python中,主線程結束後,會默認等待子線程結束後,主線程才退出。
如果你忘記殺死子線程,那麼好了,你殺主線程的時候其就會掛起等待直至子線程結束,所以爲了避免這樣的情況,python有兩個函數管理線程:join和setDaemon。其中join會在設定的子線程thread結束後接着往後運行;而 setDaemaon(True)確保主線程結束時,殺死把子線程thread。
一般情況下,在start前面加一下setDaemon(True) 。
原文鏈接:https://blog.csdn.net/sm9sun/article/details/53743116

  1. 配合主線程隊列使用,可以在線程間傳遞信息,用於更新主界面UI。

Queue的方法:首先通過empty方法判斷隊列是否爲空,如果不爲空就進入while循環,然後就從隊列中取出第一條消息msg,配合地,我們往消息隊列中存入消息,消息可以對應主界面UI的變化,執行完了這條消息,就繼續判斷隊列是否仍有消息,如果有就繼續執行第二條消息,若無消息則退出while循環。
這樣我們就在主線程建立了一個消息隊列,每隔一段時間去查看消息隊列,有沒有什麼消息是需要主線程去做的。有一點需要特別注意,主線程消息隊列裏也不要乾耗時操作,該隊列僅僅用來更新UI。
https://blog.csdn.net/yingshukun/article/details/78838395

3.2 示例

3.2.1 需求

  • TkInter 主界面持續監聽Toplevel內輸入內容。如果輸入內容爲’exit’就結束while循環關閉Toplevel,如果輸入內容不是’exit’,我們在主界面添加輸入內容相對應的label。

3.2.2 代碼

from tkinter import *
import threading,queue

class App(threading.Thread):

    def __init__(self, top):
        self.notify_queue = queue.Queue()
        self.top = Toplevel(top)
        self.loop_active = True
   		#在UI線程啓動消息隊列循環
        self.process_msg()
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.start()


    def run(self):
        while self.loop_active:
            user_input = input("Give me your command! Just type \"exit\" to close: ")
            label = Label(self.top, text=user_input)
            label.pack()
            if user_input == "exit":
                #loop_active = False
                self.notify_queue.put(1)
        self.top.destroy()
                
    def process_msg(self):
        self.top.after(400,self.process_msg)
        while not self.notify_queue.empty():
            try:
                msg = self.notify_queue.get()
                print(msg)
                if msg == 1:
                    self.loop_active = False
                    print(self.loop_active)
            except queue.Empty:
                pass
        
ROOT = Tk()
APP = App(ROOT)
ROOT.mainloop()

3.2.3 GUI

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章