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

Tkinter动态创建的重量按钮无法正确增减数值(仅增减1而非预期的5)

Tkinter动态创建的重量按钮无法正确增减数值(仅增减1而非预期的5)

嘿,我看了你的代码,问题其实出在plusminus函数里的判断逻辑上!

你现在是用if entry == weight_entry:来区分是不是重量输入框,但这里的weight_entry是你在全局作用域里定义的第一行的那个输入框对象。而你在add_row()函数里创建的新的重量输入框,是每个行里的局部变量weight_entry,它们和全局的那个根本不是同一个对象,所以这个判断条件永远不成立,自然就走了else分支,每次只加减1啦。

那怎么改呢?给你两个简单的解决思路,选哪个都行:


方法一:给重量输入框加个自定义标识

我们可以给所有重量输入框(包括第一行的和动态创建的)都加一个自定义属性,比如is_weight = True,然后在plusminus里判断这个属性,而不是比较对象是否相等。

步骤如下:

  1. 修改plusminus函数的判断条件:

    def plusminus(increment, entry, row_counter):
        if entry.get() == '': 
            new_value = 0
        else:
            current_value = int(entry.get())
            # 改成判断是否有is_weight属性且为True
            if hasattr(entry, 'is_weight') and entry.is_weight:
                # 重量字段,加减5
                new_value = current_value + 5 if increment else current_value -5
            else:
                # 其他字段(比如组数),加减1
                new_value = current_value +1 if increment else current_value -1
        
        if new_value < 0:
            new_value = 0
    
        entry.delete(0, tk.END)
        entry.insert(0, str(new_value))
    
  2. 给第一行的重量输入框加上标识:

    # 原来的第一行weight_entry创建代码后面加一行
    weight_entry = ttk.Entry(root, text='Weight')
    weight_entry.is_weight = True  # 加这个标识
    
  3. 在add_row()函数里创建新的重量输入框时,也加上这个标识:

    weight_entry = ttk.Entry(root)
    weight_entry.is_weight = True  # 给动态创建的重量输入框加标识
    weight_entry.grid(row=row_counter, column=5, padx=5, pady=5)
    

方法二:在调用plusminus时直接传递是否为重量字段

另一种思路是,在创建按钮的时候,直接告诉plusminus这个操作的是重量还是组数,不用靠输入框对象判断。

  1. 修改plusminus函数,新增一个is_weight参数:

    def plusminus(increment, entry, row_counter, is_weight=False):
        if entry.get() == '': 
            new_value = 0
        else:
            current_value = int(entry.get())
            if is_weight:
                new_value = current_value +5 if increment else current_value -5
            else:
                new_value = current_value +1 if increment else current_value -1
        
        if new_value <0:
            new_value=0
        
        entry.delete(0, tk.END)
        entry.insert(0, str(new_value))
    
  2. 修改第一行的重量按钮的command:

    btn_weightpos = tk.Button(root, text='+', command=lambda: plusminus(True, weight_entry, 0, is_weight=True))
    btn_weightneg = tk.Button(root, text='-', command=lambda: plusminus(False, weight_entry, 0, is_weight=True))
    
  3. 修改add_row()里的重量按钮command:

    btn_weightpos = tk.Button(root, text='+', command=lambda: plusminus(True, weight_entry, row_counter, is_weight=True)) 
    btn_weightneg = tk.Button(root, text='-', command=lambda: plusminus(False, weight_entry, row_counter, is_weight=True))
    

这样不管是哪一行的重量按钮,都会正确触发加减5的逻辑啦!


给你贴一份修改后的完整代码(用方法一的版本)

import tkinter as tk
from tkinter import ttk
from tkinter import *
from PIL import ImageTk, Image
import os
weight_entry='0'
root=tk.Tk()

movement_chest = ["Flat Bench", 'Incline Bench', 'Decline Bench', 'Flat DB Press', "Incline DB Press", 'High-Low Cable Raise', "Low-High Cable Raise",]
files_movement_chest = ["flat_bench.gif", 'incline_bench.gif', 'decline_bench.gif', 'db_flat.gif', "db_incline.gif", 'high_low_cable.gif', "low_high_cable.gif",]
row_counter=1

class Toolbar(Frame):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.master.title("Workout Tracker")
        menubar = Menu(self.master)
        self.master.config(menu=menubar)

        fileMenu = Menu(menubar)
        fileMenu.add_command(label="Exit", command=self.onExit)
        menubar.add_cascade(label="File", menu=fileMenu)

    def onExit(self):
        self.quit()

# Create a variable to hold the image reference
image_label = None
img = None

# Set button function
def plusminus(increment, entry, row_counter):
    if entry.get() == '': 
        new_value = 0
    else:
        current_value = int(entry.get())  # Get the current value from the entry widget
        # 修改判断逻辑:检查输入框是否有is_weight标识
        if hasattr(entry, 'is_weight') and entry.is_weight:
            # If the entry widget is the weight field, change the value by 5
            if increment:
                new_value = current_value + 5
            else:
                new_value = current_value - 5
        else:
            # For other fields like sets, change by 1
            if increment:
                new_value = current_value + 1
                print(entry)
            else:
                new_value = current_value - 1
        
    if new_value < 0:
        new_value = 0

    entry.delete(0, tk.END)  # Clear the entry
    entry.insert(0, str(new_value))  # Insert the new value


def on_combobox_select(event=None, row_counter=0):  # Allow for manual function call (no event)
    global image_label, img  # Use global variables
    # 修复动态行下拉框选值的问题:获取当前触发事件的下拉框的选中值
    motion = Dropdown.get() if event is None else event.widget.get()
    
    # Remove the old image if it exists
    if image_label:
        image_label.destroy()
    
    # Find the index of the selected motion in movement_chest
    if motion in movement_chest:
        index = movement_chest.index(motion)  # Get the index of the selected motion
        
        # Get the corresponding filename for the selected motion
        img_path = files_movement_chest[index]
        
        # Check if the image file exists and load it
        if os.path.exists(img_path):
            img = ImageTk.PhotoImage(Image.open(img_path))
        else:
            print(f"Image file '{img_path}' not found.")
            img = None
        
        # Only add the label if the image is loaded correctly
        if img:
            image_label = Label(root, image=img)
            image_label.grid(row=row_counter, column=0, columnspan=3, sticky="nsew")  # Use grid here with spanning
    else:
        img_path = "workout.gif"
        if os.path.exists(img_path):
            img = ImageTk.PhotoImage(Image.open(img_path))
        else:
            print("Image file 'workout.gif' not found.")
            img = None
        if img:  # Only add the label if the image is loaded correctly
            image_label = Label(root, image=img)
            image_label.grid(row=row_counter, column=0, columnspan=3, sticky="nsew")  # Use grid here with spanning

# Create a function that adds a new row of widgets
def add_row():
    global row_counter
    
    # Add row-specific widgets like motion dropdown, weight entry, set entry, etc.
    label_dropdown = tk.Label(root, text='Motion')
    label_dropdown.grid(row=row_counter, column=4, pady=(15, 0), sticky='n')

    # Create a new row of widgets for motion
    motion_dropdown = ttk.Combobox(
        root,
        values=movement_chest,
        state="readonly",
    )
    motion_dropdown.grid(row=row_counter, column=4, padx=5, pady=5)
    motion_dropdown.bind("<<ComboboxSelected>>", lambda event: on_combobox_select(event, row_counter))
    
    # Create weight entry for this row
    label_weight = tk.Label(root, text='Weight')
    label_weight.grid(row=row_counter, column=5, pady=(15, 0), sticky='n')

    weight_entry = ttk.Entry(root)
    weight_entry.is_weight = True  # 给动态创建的重量输入框加标识
    weight_entry.grid(row=row_counter, column=5, padx=5, pady=5)
    
    # Buttons for incrementing/decrementing weight
    btn_weightpos = tk.Button(root, text='+', command=lambda: plusminus(True, weight_entry, row_counter)) 
    btn_weightpos.grid(row=row_counter, column=5, padx=(0, 19), pady=(0, 8), sticky='s')
    
    btn_weightneg = tk.Button(root, text='-', command=lambda: plusminus(False, weight_entry, row_counter))
    btn_weightneg.grid(row=row_counter, column=5, padx=(19, 0), pady=(0, 8), sticky='s')
    
    # Create set entry for this row
    label_set = tk.Label(root, text='Sets')
    label_set.grid(row=row_counter, column=6, pady=(15, 58), sticky='n')

    set_entry = ttk.Entry(root)
    set_entry.grid(row=row_counter, column=6, padx=5, pady=5)
    
    # Buttons for incrementing/decrementing sets
    btn_setpos = tk.Button(root, text='+', command=lambda: plusminus(True, set_entry, row_counter)) 
    btn_setpos.grid(row=row_counter, column=6, padx=(0, 19), pady=(0, 8), sticky='s')
    
    btn_setneg = tk.Button(root, text='-', command=lambda: plusminus(False, set_entry, row_counter))
    btn_setneg.grid(row=row_counter, column=6, padx=(19, 0), pady=(0, 8), sticky='s')

    # Increment row_counter for the next row
    row_counter += 1

# Dropdown (Combobox)
Dropdown = ttk.Combobox(
    root,
    values=movement_chest,
    state="readonly",
)
label_dropdown = tk.Label(root, text='Motion')
label_dropdown.grid(row=0, column=4, pady=(70, 0), sticky='n')
Dropdown.grid(row=0, column=4, padx=5, pady=5)
Dropdown.bind("<<ComboboxSelected>>", on_combobox_select)

# Weight field
label_weight = tk.Label(root, text='Weight')
weight_entry = ttk.Entry(root, text='Weight')
weight_entry.is_weight = True  # 给第一行的重量输入框加标识
label_weight.grid(row=0, column=5, pady=(70, 0), sticky='n')
weight_entry.grid(row=0, column=5, padx=5, pady=5)
# button to increment the weight value
btn_weightpos = tk.Button(root, text='+', command=lambda: plusminus(True, weight_entry, 0))  # Using lambda to pass argument
btn_weightpos.grid(row=0, column=5, padx=(0, 19), pady=(0, 65), sticky='s')
# button to decrement the weight value
btn_weightneg = tk.Button(root, text='-', command=lambda: plusminus(False, weight_entry, 0))
btn_weightneg.grid(row=0, column=5, padx=(19, 0), pady=(0, 65), sticky='s')

# Set field
label_set = tk.Label(root, text='Sets')
set_entry = ttk.Entry(root, text='Sets')
label_set.grid(row=0, column=6, pady=(70, 0), sticky='n')
set_entry.grid(row=0, column=6, padx=5, pady=5)
# button to increment the set value
btn_setpos = tk.Button(root, text='+', command=lambda: plusminus(True, set_entry, 0))  # Using lambda to pass argument
btn_setpos.grid(row=0, column=6, padx=(0, 19), pady=(0, 65), sticky='s')
# button to decrement the set value
btn_setneg = tk.Button(root, text='-', command=lambda: plusminus(False, set_entry, 0))
btn_setneg.grid(row=0, column=6, padx=(19, 0), pady=(0, 65), sticky='s')

# Manually trigger the combobox selection to load the default image (workout.gif)
on_combobox_select()
# Add "Add Row" button
add_row_button = tk.Button(root, text="Add Row", command=add_row)
add_row_button.grid(row=0, column=7, padx=5, pady=5)

# Initial row setup (first row)

root.mainloop()

(另外我还顺手改了on_combobox_select里的motion获取逻辑,原来动态行的下拉框选的时候,会错误拿到第一行下拉框的值,现在改成获取当前触发事件的下拉框的选中值了,这个小问题也顺便修复了~)


备注:内容来源于stack exchange,提问作者anon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:13:06