我正在将一个用 C++ 编写并嵌入了 Python 和 TCL 解释器的程序(VMD,Visual Molecular Dynamics)移植到 Python 3.x。它的大部分 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;
}
但是函数 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++ 端。
提前致谢
最佳答案
看起来这是等价的:
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.coroutine
def update_root(root):
while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT):
yield
编辑:我刚刚阅读了您关于没有小部件的评论。我知道 root.tk
对象是通过调用 tkinter._tkinter.create
创建的 tkinter._tkinter.TkappType
实例,但我不知道不要认为它是全局性的。我很确定它是核心 Tcl 解释器。您可以通过调用 create
创建您自己的。虽然没有记录,但您可以在 tkinter.Tk.__init__
关于python - 替代 tkinter.dooneevent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28934079/