我計劃用 tkinter 做一個簡單的測驗,它將用新的輸入改變左邊的文本。但似乎執行緒并不像我想象的那樣容易。輸入2次后仍然掛起。
from tkinter import *
import threading
win = Tk()
label1 = Label(win, text="this is a test on the left")
label1.pack(side=LEFT)
label2 = Label(win, text="this is a test on the right")
label2.pack(side=RIGHT)
def set_text():
while(True):
content=input("let enter the substuition:")
label1.config(text = content)
win.after(100, set_text)
setTextthr=threading.Thread(target = set_text)
setTextthr.start()
win.mainloop()
如果您能指出它發生的原因以及如何解決,這會給您留下深刻的印象。謝謝
uj5u.com熱心網友回復:
關于執行緒與 tkinter 的結合,有一些不成文的規則。其中之一是不要觸摸tkinter 執行緒之外的任何小部件。這條線違反了這條規則。
label1.config(text = content)
為此,您可以使用不在 tkintertkinter.StingVar的主事件回圈中直接使用的 a 。
以下行也違反了規則,因為它參考了 tk.Tk() 的實體。
win.after(100, set_text)
此外,在after一段時間內從函式內部呼叫自身會創建一個您已經使用whileloop. 因此,它同時是不必要的和錯誤的。下面是一個作業示例,它有其局限性。對于另一種方法,您可以查看this或this。
from tkinter import *
import threading
win = Tk()
var = StringVar(value="this is a test on the left")
label1 = Label(win,textvariable=var)
label1.pack(side=LEFT)
label2 = Label(win, text="this is a test on the right")
label2.pack(side=RIGHT)
def set_text():
while(True):
content=input("let enter the substuition:")
var.set(content)
setTextthr=threading.Thread(target = set_text)
setTextthr.start()
win.mainloop()
uj5u.com熱心網友回復:
在事件驅動程式中從執行緒獲取資料的常用方法(就像使用tkinter)是使用一些更新回圈 ( .after) 來安排對包含來自執行緒的資料的資料容器(queue.Queue或簡單的list)的檢查。然后另外檢查執行緒是否處于活動狀態,如果不是,您可以停止更新回圈,因為沒有什么可以更新了。還可以使用一些標志 ( threading.Event) 在銷毀視窗時停止執行緒回圈。唯一的問題是input使用它使得最后至少Enter必須按下鍵。
代碼示例(代碼注釋中的解釋):
import tkinter as tk
import threading
import queue
# this is the function that will run in another thread
def ask_input(q): # argument is the queue
# here check if the event is set, if it is
# don't loop anymore, however it will still wait
# for input so that has to be entered and
# then the thread will stop
while not event.is_set():
user_input = input('New content: ')
# put the user entered data into the queue
q.put(user_input)
# the function that will update the label
def update_label(q, t): # pass in the the queue and thread
# this loop simply gets the last item in the queue
# otherwise (not in this case perhaps) it may be a little
# too slow in updating since it only runs every 100 ms
# so it need to catch up
while not q.empty():
# get data from the queue
text = q.get()
# here it is save to update the label since it is the same
# thread where all of the tkinter runs
label.config(text=text)
# check if thread still runs (in this case this specific check
# is unnecessary since the thread is stopped only after
# the main window is closed)
if t.is_alive():
# schedule the next call with the same queue and thread
root.after(100, update_label, q, t)
# the function that initiates the thread
def start_thread():
# create a queue to pass as the argument to the thread and updater
_queue = queue.Queue()
# create and start a thread
thread = threading.Thread(target=ask_input, args=(_queue,))
thread.start()
# start updating the label
update_label(_queue, thread)
# check if the code is run without importing
if __name__ == '__main__':
root = tk.Tk()
# set this attribute so that the window always stays on top
# so that you can immediately see the changes in the label
root.attributes('-topmost', True)
# create the event
event = threading.Event()
# if window is destroyed set event which will break the loop
root.bind('<Destroy>', lambda _: event.set())
label = tk.Label(root)
label.pack()
start_thread()
root.mainloop()
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/350129.html
