Tcl_AsyncDelete Error. Unable to terminate Tk

断了今生、忘了曾经 提交于 2019-12-11 16:04:41

问题


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)

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!


回答1:


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.)

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)

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).



来源:https://stackoverflow.com/questions/52144361/tcl-asyncdelete-error-unable-to-terminate-tk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!