[英]Using Thread in TKinter GUI
我正在研究 Tkinter 桌面應用程序項目。 當我需要使用運行后端代碼的線程時,我開始磕磕絆絆。 我知道為了跨線程共享變量,我們應該使用全局變量。 下面是最小的代碼。
obj = None
class Frame:
def __init__(self, frame):
self.middle_frame = frame
self.start_button = ttk.Button(self.middle_frame, text='Start', command=self.start)
self.start_button.grid(row=0, column=0)
self.stop_button = ttk.Button(self.middle_frame, text='Stop', command=self.stop)
self.stop_button.grid(row=0, column=1)
self.stop_button.config(state='disabled')
def start(self):
self.thread = threading.Thread(target=self.start_connection)
self.thread.start()
self.start_button.config(state='disabled')
self.stop_button.config(state='normal')
def start_connection(self):
global obj
obj = MainManager() # Starts the Backend Loop
def stop(self):
global obj
obj.close_connection() # Want to break the loop here
self.thread.join()
self.stop_button.config(state='disabled')
self.start_button.config(state='normal')
運行此代碼時,我得到obj.close_connection() AttributeError:'NoneType' object has no attribute 'close_connection'
。 但我期待 obj 成為 MainManager() 的對象。 我哪里錯了? 幫我解決這個問題。
您的代碼問題與tkinter
或真正與多線程無關。 問題是MainManager
在__init__
方法中啟動了循環,如下所示:
class MainManager:
def __init__(self):
self.alive = True
# this part runs until stopped
self.start_doing_stuff()
def start_doing_stuff(self):
while self.alive:
sleep(1)
print('doing stuff')
def stop(self):
self.alive = False
這是一個與您的錯誤類似的代碼:
from threading import Thread
from time import sleep
obj = None
class MainManager:
def __init__(self):
self.alive = True
self.start_doing_stuff()
def start_doing_stuff(self):
while self.alive:
sleep(1)
print('doing stuff')
def stop(self):
self.alive = False
def test():
global obj
print('about to assign to my_global')
obj = MainManager()
print('assigned to my_global')
print(f'{obj=}')
t = Thread(target=test)
t.start()
sleep(3)
print(f'{obj=}')
obj.stop()
t.join()
由於__init__
方法在調用stop
方法之前不會終止,因此語句obj = MainManager()
對MainManager()
的調用永遠不會終止,因此不會將obj
分配給。 這意味着當obj.stop()
被調用時, obj
仍然是None
。
這可以通過我使__init__
方法終止,並將長時間運行的代碼放入稍后調用的單獨方法中來解決:
from threading import Thread
from time import sleep
obj = None
class MainManager:
def __init__(self):
self.alive = True
def start_doing_stuff(self):
while self.alive:
sleep(1)
print('doing stuff')
def stop(self):
self.alive = False
def test():
global obj
print('about to assign to my_global')
obj = MainManager()
print('assigned to my_global')
obj.start_doing_stuff()
print(f'{obj=}')
t = Thread(target=test)
t.start()
sleep(3)
print(f'{obj=}')
obj.stop()
t.join()
您是否導入了 MainManager,是否運行了 start_connection()?
此外,您將分配委托給一個線程。 您確定這會影響與主線程相同的obj
嗎? 也許主線程保持“無”並且委托更改了副本中的值。 添加日志或打印語句並確保obj
被分配了MainManager()
對象並打印該對象的內存位置。 在主類中也打印obj
變量的內存位置。 檢查它是否相同。
這是打印變量的內存地址的方式:
print(hex(id(your_variable)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.