我正在移植一个程序(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 ++。
提前致谢
答案 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__
中查看其用法