替代 tkinter.dooneevent

Cai*_* S. 5 c++ python tk-toolkit tkinter python-3.x

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

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;
}
Run Code Online (Sandbox Code Playgroud)

然而该函数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 does not believe中的答案没有帮助,因为我没有用户可能创建的所有窗口的列表。

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

提前致谢

Luc*_*iel 4

看起来这是等价的:

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.
Run Code Online (Sandbox Code Playgroud)

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

@asyncio.coroutine
def update_root(root):
    while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT):
        yield
Run Code Online (Sandbox Code Playgroud)

编辑:我刚刚读到你关于没有小部件的评论。我知道该root.tk对象是tkinter._tkinter.TkappType通过调用创建的实例tkinter._tkinter.create,并且我不认为它是全局的。我很确定它是核心 Tcl 解释器。您也许可以通过调用 来创建自己的create。虽然没有记录,但您可以查看它的用法tkinter.Tk.__init__