[英]Calls to defunct tkinter (python GUI) widgets are hanging
我正在使用tkinter撥打GUI,並且試圖通過關閉應用程序時清理所有線程來成為負責任的公民。 我的應用程序是多線程的,輪詢引擎會定期將更新發送回我的顯示器。 我正在使用資源鎖定來控制對共享資源的訪問(以下示例代碼中未顯示)。 問題是,關閉應用程序窗口后,我經常被剩余的線程卡住。
我試圖在下面的代碼中顯示我正在使用的內容:“更新”的回調是異步的。 問題是,在我檢查“ self._active”基礎窗口小部件的狀態的時間與我對“ ... frameWidget.configure(style = ...”和“ ... varToUpdate.set(...“),tkinter引擎可能已將這些小部件的狀態更改為某種“已終止” /“無響應”的樣式。
使用鎖沒有幫助。 我還沒有找到一種方法來控制小部件的狀態,以防止它們“死亡”,直到我能清理干凈為止。 事件通知看起來很簡單:它們告訴您事件已經發生,但是它們不允許您延遲小部件“死亡”,直到您完成清理為止。
真正的問題似乎在於,配置小部件樣式(“ self.frameWidget.configure(style = stylename)”)和更新IntVar(“ self.varToUpdate.set(value)”)的調用只是掛起/ GUI關閉時阻止。
這些方法調用不會產生異常,也不會產生任何結果,而不會返回。 (這對我來說似乎不是好行為。)
所以。 該如何處理? 有任何想法嗎? 我真的很喜歡以某種方式將一大段代碼指定為“原子的”功能,這樣我可以保證在檢查“ ._active”之后立即確保對象操作可以運行,但是我在Python中沒有看到類似的東西。 即使我能做到這一點,我也不知道tkinker引擎實際上如何更新對象,因此可能無法解決問題。 我想念什么嗎?
是的,我是python的新手,bla bla bla ...我來自Java背景,因此我認為我所寫的大部分內容絕對是“非Python的”。 我很高興聽到您對我將如何改進此處的功能以利用語言優勢的見解。
示例代碼!
from tkinter import *
from tkinter import ttk
from myutil import Subscriber
threshold = 20
deactivationEvents = ("Deactivate", "Destroy", "Unmap")
activationEvents = ("Activate", "Map")
# class implements/inherits "listener pattern" functionality
class MyClass(Subscriber)
def __init__(self, parentWidget):
self._active = False
self.frame = ttk.LabelFrame(parentWidget, text='something')
self.varToUpdate = IntVar()
self.bar = ttk.Progressbar(self.frame, orient=VERTICAL)
self.bar.config(mode='determinate', maximum=100, variable=self.varToUpdate)
self.moreThings()
self.bindWidgetEvents():
. more
. code
. here
# I'm using a simple boolean flag to control access here
# I've tried using threading.Lock as well, to no avail
def update(self, value):
stylename = "{}.TFrame".format("Normal" if value > threshold else "Alarm")
if self._active:
self.frame.configure(style=stylename)
self.varToUpdate.set(value)
def bindWidgetEvents(self):
widgets = [self.bar, self.frame]
self.bindActivationEvents(widgets)
self.bindDeactivationEvents(widgets)
def bindActivationEvents(self, widgets):
def activate(event):
self._active = True
for widget in widgets:
for event in activationEvents:
widget.bind("<{}>".format(event), activate)
def bindDeactivationEvents(self, widgets):
def deactivate(event):
self._active = False
for widget in widgets:
for event in deactivationEvents:
widget.bind("<{}>".format(event), deactivate)
將后台線程設置為守護程序就可以了
t = Thread(target=self.pollData)
t.daemon = True
t.start()
主線程退出時,線程“ t”結束
我仍然覺得在這種情況下,tkinter方法通過阻止/掛起而不是引發異常而表現不佳
盡管在特定情況下可以將線程分配為守護程序,但是除非我們實際上關閉應用程序,否則這實際上並沒有幫助。 如果我只是關閉窗戶或框架怎么辦? 然后,我們陷入了調用這些已失效的GUI項目並掛起線程的問題。
我們需要一種阻止這些方法被調用的方法,但是我們不能依靠先檢查后調用的解決方案,因為它們不是原子操作。
這是另一個想法...人們對此有何看法?
# The tkinter GUI objects were hanging indefinitely upon calls to their methods after
# the window was closed, so we will replace them with dummy objects that will recieve
# those calls instead
def deactivate(self):
self._active = False
self.varToUpdate = Stub() # we could probably just reinitialize an IntVar
self.bar = Stub()
self.frame = Stub()
class Stub(object):
def __init__(self):
pass
def config(self, **kwargs):
pass
def set(self, value):
pass
當調用現在不存在的對象時,我們也可以簡單地刪除對象並添加處理以捕獲產生的異常...
def deactivate(self):
self._active = False
del self.varToUpdate
del self.bar
del self.frame
不幸的是,即使有了這些解決方案,我認為仍然有可能在對GUI對象的調用完成后關閉對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.