Custom Tkinter滑块仅在释放时发送值的实现问题
问题解决:滑块释放时才保存最终值到数组
我编写了一个脚本,用于将滑块的值通过数组发送至串口。当前问题是拖动滑块时,每一步的数值都会被添加到数组中,希望实现仅在释放滑块时将最终值存入数组,得到[valueX, valueY, valueZ]的结构。
原代码
from tkinter import * import customtkinter import serial.tools.list_ports import time ports = [] for port in serial.tools.list_ports.comports(): ports.append(port.name) customtkinter.set_appearance_mode("System") # Modes: system (default), light, dark customtkinter.set_default_color_theme("blue") # Themes: blue (default), dark-blue, green customtkinter.deactivate_automatic_dpi_awareness() app = customtkinter.CTk() # create CTk window like you do with the Tk window app.geometry("560x550") app.title('Scara Controller') serialData = [] def slider_event_X(valueX): #print("X", valueX) Dynamic_label1.configure(text=round(valueX)) serialData.append(valueX) def slider_event_Y(valueY): #print("Y", valueY) Dynamic_label2.configure(text=round(valueY)) serialData.append(valueY) def slider_event_Z(valueZ): #print("Z", valueZ) Dynamic_label3.configure(text=round(valueZ)) serialData.append(valueZ) def button_event(): print("Button pressed") print(serialData) COM1 = customtkinter.StringVar(value="COM1") def optionmenu_callback(choice): print("clicked:", choice) combobox = customtkinter.CTkOptionMenu(master=app, values=ports, command=optionmenu_callback, variable=COM1) combobox.place(x=220, y=20) label0 = customtkinter.CTkLabel(app, text="COM Port wählen:", fg_color="transparent", font=("Arial", 20)) label0.place(x=50, y=20) label1 = customtkinter.CTkLabel(app, text="X", fg_color="transparent") label1.place(x=50, y=70) label2 = customtkinter.CTkLabel(app, text="Y", fg_color="transparent") label2.place(x=50, y=120) label3 = customtkinter.CTkLabel(app, text="Z", fg_color="transparent") label3.place(x=50, y=170) Dynamic_label1 = customtkinter.CTkLabel(app, text="180", fg_color="transparent") Dynamic_label1.place(x=380, y=70) Dynamic_label2 = customtkinter.CTkLabel(app, text="180", fg_color="transparent") Dynamic_label2.place(x=380, y=120) Dynamic_label3 = customtkinter.CTkLabel(app, text="180", fg_color="transparent") Dynamic_label3.place(x=380, y=170) slider1 = customtkinter.CTkSlider(master=app, from_=0, to=360, width=300,command=slider_event_X) slider1.place(x=70, y=75) slider2 = customtkinter.CTkSlider(master=app, from_=0, to=360, width=300,command=slider_event_Y) slider2.place(x=70, y=125) slider3 = customtkinter.CTkSlider(master=app, from_=0, to=360, width=300,command=slider_event_Z) slider3.place(x=70, y=175) entryX = entry = customtkinter.CTkEntry(app, placeholder_text="Angle for X", width=80) entryX.place(x=430, y=70) entryY = entry = customtkinter.CTkEntry(app, placeholder_text="Angle for Y", width=80) entryY.place(x=430, y=120) entryZ = entry = customtkinter.CTkEntry(app, placeholder_text="Angle for Z", width=80) entryZ.place(x=430, y=170) button1 = customtkinter.CTkButton(master=app, text="Send", command=button_event) button1.place(x=250, y=250) print(serialData) app.mainloop()
尝试过的无效方案
- 条件判断过滤重复值:
if valueX not in serialData: serialData.append(valueX)
- 借鉴Tkinter绑定方式(未正确适配CustomTkinter):
self.slider = tk.Scale(self.root, from_=0, to=256, orient="horizontal") self.slider.bind("<ButtonRelease-1>", self.updateValue)
解决方法及修改后代码
核心思路:
- 滑块的
command回调仅负责实时更新标签显示,不再向数组添加元素 - 给每个滑块绑定
<ButtonRelease-1>事件,释放时获取最终值并更新数组对应位置 - 初始化数组为固定长度的
[X,Y,Z]结构,避免无序追加
修改后的完整代码:
from tkinter import * import customtkinter import serial.tools.list_ports import time ports = [] for port in serial.tools.list_ports.comports(): ports.append(port.name) customtkinter.set_appearance_mode("System") customtkinter.set_default_color_theme("blue") customtkinter.deactivate_automatic_dpi_awareness() app = customtkinter.CTk() app.geometry("560x550") app.title('Scara Controller') # 初始化数组为[X,Y,Z]结构,对应初始值180 serialData = [180, 180, 180] def slider_event_X(valueX): # 仅更新标签显示 Dynamic_label1.configure(text=round(valueX)) def slider_event_Y(valueY): Dynamic_label2.configure(text=round(valueY)) def slider_event_Z(valueZ): Dynamic_label3.configure(text=round(valueZ)) # 滑块释放时的处理函数 def on_slider_release_X(event): final_value = round(slider1.get()) serialData[0] = final_value def on_slider_release_Y(event): final_value = round(slider2.get()) serialData[1] = final_value def on_slider_release_Z(event): final_value = round(slider3.get()) serialData[2] = final_value def button_event(): print("Button pressed") print(serialData) COM1 = customtkinter.StringVar(value="COM1") def optionmenu_callback(choice): print("clicked:", choice) combobox = customtkinter.CTkOptionMenu(master=app, values=ports, command=optionmenu_callback, variable=COM1) combobox.place(x=220, y=20) label0 = customtkinter.CTkLabel(app, text="COM Port wählen:", fg_color="transparent", font=("Arial", 20)) label0.place(x=50, y=20) label1 = customtkinter.CTkLabel(app, text="X", fg_color="transparent") label1.place(x=50, y=70) label2 = customtkinter.CTkLabel(app, text="Y", fg_color="transparent") label2.place(x=50, y=120) label3 = customtkinter.CTkLabel(app, text="Z", fg_color="transparent") label3.place(x=50, y=170) Dynamic_label1 = customtkinter.CTkLabel(app, text="180", fg_color="transparent") Dynamic_label1.place(x=380, y=70) Dynamic_label2 = customtkinter.CTkLabel(app, text="180", fg_color="transparent") Dynamic_label2.place(x=380, y=120) Dynamic_label3 = customtkinter.CTkLabel(app, text="180", fg_color="transparent") Dynamic_label3.place(x=380, y=170) slider1 = customtkinter.CTkSlider(master=app, from_=0, to=360, width=300, command=slider_event_X) slider1.place(x=70, y=75) # 绑定释放事件 slider1.bind("<ButtonRelease-1>", on_slider_release_X) slider2 = customtkinter.CTkSlider(master=app, from_=0, to=360, width=300, command=slider_event_Y) slider2.place(x=70, y=125) slider2.bind("<ButtonRelease-1>", on_slider_release_Y) slider3 = customtkinter.CTkSlider(master=app, from_=0, to=360, width=300, command=slider_event_Z) slider3.place(x=70, y=175) slider3.bind("<ButtonRelease-1>", on_slider_release_Z) entryX = customtkinter.CTkEntry(app, placeholder_text="Angle for X", width=80) entryX.place(x=430, y=70) entryY = customtkinter.CTkEntry(app, placeholder_text="Angle for Y", width=80) entryY.place(x=430, y=120) entryZ = customtkinter.CTkEntry(app, placeholder_text="Angle for Z", width=80) entryZ.place(x=430, y=170) button1 = customtkinter.CTkButton(master=app, text="Send", command=button_event) button1.place(x=250, y=250) print(serialData) app.mainloop()
方案说明
- 初始数组
serialData固定为[180,180,180],对应X、Y、Z三个轴的初始角度,保持结构稳定 - 滑块拖动时仅更新标签,不会修改数组
- 释放滑块时通过
slider.get()获取当前最终值,替换数组对应索引的元素,确保数组始终是[X,Y,Z]的结构 - 之前的无效方案原因:
- 条件判断无法阻止非重复值的追加,且会破坏数组结构
- Tkinter的绑定方式本身可行,但之前未正确绑定到CustomTkinter的滑块实例,也未处理值的替换逻辑
内容的提问来源于stack exchange,提问作者Finn
相关产品推荐
相关产品推荐

