【问题标题】:_tkinter.tclerror: bad option set tcl value number must be activate, get, configure_tkinter.tclerror: bad option set tcl value number must be activate, get, configure
【发布时间】:2013-10-01 13:38:58
【问题描述】:

使用 Tkinter,我有一个启动外部线程的按钮。还有一个 tkinter 文本框,它通过管道传输到外部线程 stdout 和 stderr。我在执行外部线程时只收到一次此错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
    return self.func(*args)
  File "C:\Python33\lib\tkinter\__init__.py", line 2923, in set
    self.tk.call((self._w, 'set') + args)
_tkinter.TclError: bad option "set TCL VALUE NUMBER": must be activate, cget, configure, delta, fraction, get, identify, or set

即使它没有再次发生,我也很想知道是什么原因造成的。似乎错误不是来自外部线程,而是来自运行 GUI 的主线程。会不会只是一些内部 Tkinter 错误?

【问题讨论】:

    标签: python multithreading tkinter


    【解决方案1】:

    这可能有点晚了,但无论如何......

    我自己的研究发现了在 event_generate 调用中添加 'when="tail"' 的建议,以确保事件正确排队。如果你不这样做,Tk 事件规则可能会对事件队列做一些奇怪的事情。这(还没有?)在 Tkinter 中记录。

    即便如此,我自己的研究(和经验!)也发现 Tkinter 从根本上不是线程安全的。这意味着你不能保证在 Tkinter 自己的线程之外做任何事情都会奏效。当然,最安全的方法是生成事件,但即使这样也会定期抛出异常,这表明 Tkinter 内部对于添加事件不是线程安全的。通常这些异常是可以生存的,所以我使用重试来再次破解,这主要是可行的。

    retries = 3
    done = False
    unknownException = False
    while (retries != 0) and (not done) and (not unknownException):
        try:
            self._applicationWindow.event_generate("<<MyNewEvent>>", when="tail")
            done = True
        except Tk.TclError as err:
            if "application has been destroyed" in err.message:
                # If application is destroyed, this event is not needed
                done = True
            elif ("expected boolean value but got" in err.message) or ("bad option" in err.message): 
                # These are bugs in Tk/Tcl/Tkinter, not in our code.  They seem to be uncommon,
                # and seem to be survivable.  Hopefully retrying will have the system in a
                # slightly different state where this doesn't happen next time.
                print "Tkinter/Tk/Tcl error, retry " + str(retries)
                retries = retries - 1
            else:
                unknownException = True
        except:
            unknownException = True
    
    # Unlock afterwards
    self._eventLock.release()
    
    if not done:
        # If retries haven't helped or we have an exception which isn't one we know about,
        # then pass the exception up the tree.
        raise   
    

    一个非线程安全的 UI 层是一回事 - 我猜它简化了设计,所以它是可以接受的。但是,非线程安全的事件队列应该是您的编程入门课程中的失败等级。如果您得出结论认为 Tkinter 已损坏并且不应该用于任何现实世界的应用程序 - 加入俱乐部。就我而言,任何 Tkinter 问题的正确解决方法是使用另一个适合目的的 UI 层。 :/

    PS。我正在使用 Python 2.7.6。 Python 3 上的 YMMV。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-19
      • 1970-01-01
      • 1970-01-01
      • 2021-07-26
      • 1970-01-01
      • 2017-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多