替换为tkinter.dooneevent

时间:2015-03-09 01:43:07

标签: python c++ python-3.x tkinter tk

我正在移植一个程序(VMD,Visual Molecular Dynamics),它是用C ++编写的,并且嵌入了Python和TCL解释器,用于Python 3.x.其大多数UI使用TCL / TK框架和OpenGl进行硬编码,因此UI刷新是手动完成的。当Python解释器运行时,可以动态创建新窗口,甚至可以使用Tkinter将新菜单添加到主UI。在这种情况下,通过定期调用Python端的一些代码来刷新所有TK事件(见下文)。这可以确保所有更新都是线程安全的,不会破坏解释器。

int PythonTextInterp::doTkUpdate() {
    // Don't recursively call into dooneevent - it makes Tkinter crash for
    // some infathomable reason.
    if (in_tk) return 0;
    if (have_tkinter) {
        in_tk = 1;
        int rc = evalString(
          "import Tkinter\n"
          "while Tkinter.tkinter.dooneevent(Tkinter.tkinter.DONT_WAIT):\n"
          "    pass\n"
        );
        in_tk = 0;
        if (rc) {
            return 1; // success
        }
        // give up
        have_tkinter = 0;
    }
    return 0;
}

然而,函数tkinter.dooneevent已从Python 3中删除,我无法找到它的替代品。我尝试调用低级Tcl_DoOneEvent(TCL_DONT_WAIT)但是当我动态创建一个新窗口时,我最终崩溃了Python解释器,错误为Fatal Python error: PyEval_RestoreThread: NULL tstate

tkinter woes when porting 2.x code to 3.x, 'tkinter' module attribute doesn't exist中的答案没有用,因为我没有可能由用户创建的所有窗口的列表。

在这种情况下,有没有人对如何清除TK事件有任何建议?它可以是Python端,也可以是C ++。

提前致谢

1 个答案:

答案 0 :(得分:1)

看起来这是等价的:

root = tkinter.Tk()

# Here's your event handler. Put it in a loop somewhere.
root.tk.dooneevent(tkinter._tkinter.DONT_WAIT)
# I don't know if it's possible to access this method without a Tk object.

现在,我不知道如何将其转换为您的代码 - 您是否拥有可以访问dooneevent的根Tk对象?我对python 2 tkinter一点都不熟悉,所以我不知道我的代码到底有多均匀地映射到你的代码。但是,当我做一些与你非常相似的事情时,我发现了这一点 - 尝试将tkinter事件循环集成到asyncio事件循环中。我能够创建一个在循环中调用此方法的协程,每次都会产生(并偶尔休眠),以便GUI保持响应,而不会阻止使用tkinter._tkinter.create()的asyncio事件循环。

@asyncio.coroutine
def update_root(root):
    while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT):
        yield
编辑:我刚刚阅读了关于没有小部件的评论。我知道root.tk对象是通过调用tkinter._tkinter.TkappType创建的tkinter._tkinter.create实例,我不认为它是全局的。我很确定它是核心Tcl解释器。您可以通过致电create来创建自己的。虽然没有记录,但您可以在tkinter.Tk.__init__

中查看其用法