You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

解决方法及修改后代码

核心思路:

  1. 滑块的command回调仅负责实时更新标签显示,不再向数组添加元素
  2. 给每个滑块绑定<ButtonRelease-1>事件,释放时获取最终值并更新数组对应位置
  3. 初始化数组为固定长度的[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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:37:00