对失效的tkinter(PythonGUI)小部件的调用挂起

2024-10-02 10:25:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用tkinter拨一个GUI,当我的应用程序关闭时,我试图通过清理所有线程来成为一个负责任的公民。我的应用程序是多线程的,有一个轮询引擎定期将更新发送回我的显示器。我使用资源锁定来控制对共享资源的访问(下面的示例代码中没有显示)。问题是,在关闭应用程序窗口后,我经常被剩余的线程卡住。你知道吗

我试着在下面的代码中展示我正在使用的东西:“update”的回调是异步的。问题是,在我检查“self.\u active”查看底层小部件的状态和调用“。。。frameWidget.configure文件(样式=…“和”。。。varToUpdate.set文件(…”,tkinter引擎可能已将这些小部件的状态更改为某种风格的“失效”/“无响应”。你知道吗

使用锁没有帮助。我还没有找到一种方法来控制小部件的状态,以防止它们“死亡”,直到我可以清理东西。事件通知看起来很简单:它们告诉您发生了一个事件,但不允许您延迟小部件-“死亡”直到您可以完成清理。你知道吗

真正的问题似乎是配置小部件样式的调用(“self.frameWidget.configure配置(style=stylename)“)并更新IntVar(”self.varToUpdate.set设置(值)“)只需在GUI关闭时挂起/阻止即可。
这些方法调用永远不会返回,而不是产生异常或什么也不产生。(在我看来这不是一个好行为。)

所以。怎么处理?有什么想法吗?我真的很喜欢以某种方式将一段代码指定为“原子”的功能,这样我就可以保证在检查“.\u active”之后立即运行对象操作,但我在Python中没有看到类似的情况。即使我能做到这一点,我也不确定tkinker引擎实际上是如何更新对象的,所以这可能无法解决问题。我错过什么了吗?你知道吗

是的,我对Python还不熟悉,等等。。。我有Java的背景,所以我认为我写的很多东西肯定是“非pythonic”的。我很高兴听到你的见解,我可以改善这里的事情,以利用语言的优势。你知道吗

示例代码!你知道吗

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)

Tags: 代码in引擎selfevent应用程序for部件
2条回答

在这种特殊情况下,将线程分配为守护进程是有效的,除非我们真正关闭应用程序,否则这并没有真正的帮助。如果我只是关上一扇窗户或一个框架呢?然后我们陷入了调用这些失效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对象之后关闭对象。你知道吗

将后台线程设置为守护进程运行得很好

t = Thread(target=self.pollData)
t.daemon = True
t.start()

当主线程退出时,线程“t”结束

我仍然觉得tkinter方法在这种情况下的表现很差,它通过阻塞/挂起而不是引发异常

相关问题 更多 >

    热门问题