我们如何根据订阅的主题消息的变化动态改变Tkinter标签小部件中的文本?

How do we dynamically change the text in label widget of Tkinter according to the change of subscribed topic message?

我想根据我的节点订阅的主题消息更改我的标签文本。但问题是标签中的文字并没有随着主题消息的变化而变化。下面给出了我的部分代码:(我使用代码从 https://bytes.com/topic/python/answers/629499-dynamically-displaying-time-using-tkinter-label 动态更改标签中的文本)

v = StringVar()
v.set(distance)
self.clock = Label(frame, font=('times', 20, 'bold'), bg='green', textvariable = v)
self.clock.pack(fill=BOTH, expand=1)
rate = rospy.Rate(2)

while not rospy.is_shutdown():
    rospy.Subscriber("distance", Float32, self.callback)
    v.set(distance)
    print("distance = %f", distance)
    frame.update_idletasks()
    rate.sleep()

好吧,您的代码(或者至少是您发布的部分)看起来很乱。

ROS 说话,

  • define your subscriber in the initialization of the node(不在里面 while 循环,它会创建多个订阅者!)
  • create a callback to get the messages在那个话题下交流阅读留言
  • update your label相应地。

话虽这么说,但这里有一个代码的示例:(填空)

#!/usr/bin/env python
import rospy
from std_msgs.msg import Float32

def callback(data):
    distance = data.data
    rospy.loginfo(rospy.get_caller_id() + "distance = ", distance )
    #here update your label, I assume the following (maybe not correct)
    v = StringVar()
    v.set(distance)
    self.clock = Label(frame, font=('times', 20, 'bold'), bg='green', textvariable = v)
    self.clock.pack(fill=BOTH, expand=1)

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("distance", Float32, self.callback)  
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()


if __name__ == '__main__':
    listener()

共享示例 ROS 订阅者以读取 1 个传感器并使用 tkinter 和 Class 显示结果。显示将更新 1/秒或您设置的任何值。

import tkinter as tk
from tkinter import ttk
import time
from random import randint
import rospy
from std_msgs.msg import Int16

"""
subscribes to a ROS topic (/front_angle_low_res) which in my case is outputing an integer result and displays the result in a tkinter window

credit: https://www.pythontutorial.net/tkinter/tkinter-after/
credit: https://www.youtube.com/watch?v=EAAd5vXA8lE&t=260s

before running make sure to $ rostopic echo /front_angle_low_res to make sure data is available
This script can be started from the folder it resides in with $ python3 sensor_display.py

"""

class Display_Sensor_1(tk.Tk):

    def __init__(self):
        super().__init__()
        self.sub = rospy.Subscriber("/front_angle_low_res", Int16, self.callback_sensor_1)
        self.sensor_1_data = tk.IntVar()

        # configure the root window
        self.title('Sensor 1 Data')
        self.resizable(0, 0)
        self.geometry('250x80')
        self['bg'] = 'black'
        
        # change the background color to black
        self.style = ttk.Style(self)
        self.style.configure('TLabel', background='black', foreground='red')
        self.label = ttk.Label(self, text=self.get_sensor_data(), font=('Digital-7', 20))
        self.label.pack(expand=True)
        self.label.after(1000, self.update)     # schedule an update every 1 second

    def callback_sensor_1(self, data):   
        self.sensor_1_data = data.data
        #print(self.sensor_1_data)
        #rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)

    def get_sensor_data(self):
        return self.sensor_1_data

    def update(self):
        """ update the label every 1 second """
        self.label.configure(text=self.get_sensor_data())
        self.label.after(1000, self.update)     # schedule another timer
 
if __name__ == "__main__":
    rospy.init_node('listener', anonymous=True)
    sensor = Display_Sensor_1()
    sensor.mainloop()

gist link