Tcl_AsyncDelete 错误.无法终止 Tk [英] Tcl_AsyncDelete Error. Unable to terminate Tk

查看:34
本文介绍了Tcl_AsyncDelete 错误.无法终止 Tk的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 ROS 节点中使用 Tkinter 创建 GUI 并将比例值发布到另一个 ROS 节点.我已经做到了.当我尝试关闭此 GUI 并重新运行节点时,问题就出现了.我得到的日志信息如下:

I am using Tkinter in a ROS node to create a GUI and publish the scale values to another ROS Node. I have accomplished this. The problem comes when I try to close this GUI and rerun the node. The log message that I get is as follows:

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)

根据this,我想我将不得不终止Tk线.但我不知道该怎么做.我的代码如下:

According to this, I think I will have to terminate Tk from its own thread. But I do not know how to do this. My code is as follows:

#!/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.")

如果您能提供帮助,我将不胜感激.谢谢!

I would be grateful if you could help. Thanks!

推荐答案

问题是 rospy 在内部是多线程的,但 Tk 非常 热衷于只在单线程中使用.(从技术上讲,可以从多个线程使用 Tk — 通过适当隔离窗口对象等 — 但要正确使用真的很棘手,而且您可能不希望那样做.)

The problem is that rospy is internally multithreaded yet Tk is very keen on only being used from a single thread. (Technically, it's possible to use Tk from multiple threads — by appropriate quarantining of window objects and so on — but it's really tricky to get right and you probably don't want that.)

通常最简单的方法是创建两个类,一个处理 Tk(传入和传出消息全部排队),另一个桥接其余的代码.然后,当您希望 Tk GUI 出现时,您可以运行一个线程来执行此操作,然后仅通过其队列与该线程对话.这听起来需要做更多的工作,但是除了将其严格保持在一个线程上之外,您无法打败 Tk 对线程的内部意识.

The easiest approach in general is to make two classes, one that just handles Tk (with incoming and outgoing messages all queued) and the other which does the bridging into the rest of the code. Then, when you want the Tk GUI to appear you run a thread that just does that and then talk to that thread just by its queues. Which sounds like a lot more work, but you can't defeat Tk's internal awareness of threads other than by keeping it strictly on one thread.

但是,可能将关闭顺序稍微更改为这样.

However, it might be enough to change the shutdown sequence a bit to be like this.

    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) 代替,这被认为是危险的(但它可能是必要的).

Assuming that you're in the correct thread. If not, you'll need a direct os._exit(0) instead and that's considered dangerous for good reason (yet it might be necessary).

这篇关于Tcl_AsyncDelete 错误.无法终止 Tk的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆