python - Tcl_AsyncDelete 错误。无法终止 Tk
问题描述
我在 ROS 节点中使用 Tkinter 创建 GUI 并将比例值发布到另一个 ROS 节点。我已经做到了这一点。当我尝试关闭此 GUI 并重新运行节点时,问题就出现了。我得到的日志消息如下:
Exception RuntimeError: 'main thread is not in main loop' in <bound method DoubleVar.__del__ of <Tkinter.DoubleVar instance at 0x7f19ea0c3ab8>> ignored
Tcl_AsyncDelete: async handler deleted by the wrong thread
Aborted (core dumped)
据此,我想我将不得不从它自己的线程中终止 Tk。但我不知道该怎么做。我的代码如下:
#!/usr/bin/env python
import rospy
from std_msgs.msg import Float64MultiArray
from Tkinter import *
from calibration_camera_lidar.msg import Euler_val
import tkMessageBox
class slider():
def __init__(self):
rospy.loginfo("init")
rospy.init_node('slider', anonymous=True, disable_signals=True)
self.spub = rospy.Publisher('Slider_values', Euler_val, queue_size=10)
self.final_ev = Euler_val()
self.listener()
def listener(self):
rospy.Subscriber("Euler_values", Float64MultiArray, self.callback)
rospy.spin()
def callback(self, data):
self.eulerval = list(data.data)
self.final_ev.Euler_angles = [self.eulerval[0], self.eulerval[1], self.eulerval[2]]
self.spub.publish(self.final_ev)
rospy.loginfo(self.final_ev)
self.slider_value()
def callback_exit(self):
if tkMessageBox.askokcancel("Quit", "Do you really wish to quit?"):
self.root.destroy()
self.root.quit()
rospy.signal_shutdown("shutdown")
def slider_value(self):
self.root = Tk()
self.root.title("fine tune")
self.root.protocol("WM_DELETE_WINDOW", self.callback_exit)
self.y_var = DoubleVar()
self.y_scale = Scale( self.root, from_=self.eulerval[0]-1, to=self.eulerval[0]+1, length=300, label="yaw", resolution=0.0000000000001, variable = self.y_var, orient=HORIZONTAL, command=self.pub_y)
self.y_scale.set(self.eulerval[0])
self.y_scale.pack(anchor=CENTER)
self.label = Label(self.root)
self.label.pack()
self.root.mainloop()
def pub_y(self, val_y):
self.eulerval[0] = float(self.y_scale.get())
self.final_ev.Euler_angles = [self.eulerval[0], self.eulerval[1], self.eulerval[2]]
self.spub.publish(self.final_ev)
rospy.loginfo(self.final_ev)
if __name__ == '__main__':
try:
slider()
except:
rospy.loginfo("Node terminated.")
如果您能提供帮助,我将不胜感激。谢谢!
解决方案
问题是 rospy 在内部是多线程的,但 Tk非常热衷于只在单个线程中使用。(从技术上讲,可以在多个线程中使用 Tk ——通过适当隔离窗口对象等等——但要正确处理真的很棘手,你可能不希望这样。)
一般来说,最简单的方法是创建两个类,一个只处理 Tk(传入和传出消息都排队),另一个负责桥接其余代码。然后,当您希望 Tk GUI 出现时,您运行一个执行此操作的线程,然后仅通过其队列与该线程对话。这听起来需要做更多的工作,但是除了将 Tk 严格保持在一个线程上之外,您无法击败 Tk 对线程的内部意识。
但是,将关闭顺序稍微更改为这样就足够了。
def callback_exit(self):
if tkMessageBox.askokcancel("Quit", "Do you really wish to quit?"):
self.root.destroy()
rospy.signal_shutdown("shutdown")
sys.exit(0)
假设您在正确的线程中。如果没有,您将需要直接os._exit(0)
代替,并且有充分的理由认为这是危险的(但它可能是必要的)。
推荐阅读
- javascript - 如何修改 Loopback 4 中的错误信息?
- json - 熊猫的嵌套列表列表
- maven - 将自定义属性添加到 pom.properties
- python - 错误消息 Filedialog tkinter / FIFinderSyncExtensionHost 在两者中都实现
- r - system("timedatectl") "查询服务器失败:连接超时"
- javascript - 如果 JSON 数据不存在,如何隐藏 div
- java - 如何在团队城市插件开发jsp中处理表单提交
- php - php-amqplib:如何防止无限加载网页?
- java - Java 多环境最佳实践问题
- javascript - 是否可以在 Zapier Code 中启动服务器