Tkinter Entry组件新增数据时替换列表项而非追加的问题排查
Hey Lucy, I see exactly what's going on here—your job_list keeps getting replaced instead of appending new entries because of a small but critical mistake in how you're initializing your lists. Let's break this down and fix it step by step.
The Root Cause
Take a look at your store_job method:
def store_job(self): self.job_list = [] # This resets the list EVERY time you click the button! self.customer_list = [] self.job_list.append(self.job_number.get()) self.customer_list.append(self.customer_name.get()) for i in self.job_list: print (i)
Every time you click "Enter Job", you're creating brand new empty lists for job_list and customer_list. That means any previous entries get wiped out immediately before adding the new one. The same problem applies to cost_list in your calculate method—you're resetting it every time too, so only the latest cost gets stored.
The Fix
Move the initialization of your lists to the __init__ method so they're only created once when the GUI starts, not every time you add a job. Here's how to adjust your code:
Step 1: Initialize Lists in __init__
Add these lines inside your __init__ function, right after you set up self.cb:
# Initialize empty storage lists ONCE when the app launches self.job_list = [] self.customer_list = [] self.cost_list = []
Step 2: Update store_job to Append Only
Remove the list reset lines from store_job—now it will add to the existing lists instead of replacing them:
def store_job(self): # Add new entries to the pre-initialized lists self.job_list.append(self.job_number.get()) self.customer_list.append(self.customer_name.get()) # Optional: Print all jobs to confirm they're being stored correctly print("Current job numbers:", self.job_list)
Step 3: Fix calculate to Stop Resetting cost_list
Similarly, remove the self.cost_list = [] line from calculate so it appends new costs instead of overwriting:
def calculate(self): self.distance_calc = int(self.distance.get()) self.min_calc = int(self.min_spent.get()) self.cost = 0 # ... (keep your existing cost calculation logic here) ... self.cost_list.append(self.cost) print("Current job costs:", self.cost_list) self.enter_next()
Full Modified Code
Here's the complete updated code with all fixes applied, plus a bonus feature for the "Show All" button:
from tkinter import * class EntryGUI: def __init__(self, parent): self.cb = IntVar() # Initialize storage lists ONCE here self.job_list = [] self.customer_list = [] self.cost_list = [] self.job_number_label= Label(parent, text = "Job number:") self.job_number_label.grid(row = 1, column = 0) self.job_number = Entry(parent) self.job_number.focus() self.job_number.grid(row=1, column = 1) self.customer_name_label = Label(parent, text = "Customer name:") self.customer_name_label.grid(row = 2, column = 0) self.customer_name = Entry(parent) self.customer_name.grid(row=2, column = 1) self.distance_label= Label(parent, text = "Distance Travelled (km):") self.distance_label.grid(row = 3, column = 0) self.distance = Entry(parent) self.distance.grid(row=3, column = 1) self.min_spent_label= Label(parent, text = "Minutes spent on Virus protection:") self.min_spent_label.grid(row = 4, column = 0) self.min_spent = Entry(parent) self.min_spent.grid(row=4, column = 1) wof_tune= Checkbutton(parent, variable = self.cb, text = "check if WOF and tune is required", onvalue = 100, offvalue = 0) wof_tune.grid(row = 5, column = 0) self.enter = Button(parent, text = "Enter Job", command = lambda:[self.store_job(),self.calculate()]) self.enter.grid(row = 6, column = 0) self.show_all = Button(parent, text = "Show All", command=self.display_jobs) # Linked to new display function self.show_all.grid(row = 6, column = 1) def store_job(self): # Append to existing lists instead of resetting self.job_list.append(self.job_number.get()) self.customer_list.append(self.customer_name.get()) print("Stored jobs:", self.job_list) def calculate(self): self.distance_calc = int(self.distance.get()) self.min_calc = int(self.min_spent.get()) self.cost = 0 # Travel cost calculation if self.distance_calc <= 5: self.cost = 10 else: self.distance_calc = self.distance_calc - 5 self.distance_calc = self.distance_calc / 2 self.cost = self.distance_calc + 10 # Add virus protection and WOF/tune costs self.cost = self.cost + (self.min_calc * 0.8) self.cost = self.cost + int(self.cb.get()) self.cost_list.append(self.cost) print("Calculated costs:", self.cost_list) self.enter_next() def enter_next(self): self.job_number.delete(0,END) self.customer_name.delete(0, END) self.distance.delete(0, END) self.min_spent.delete(0, END) self.enter.configure(state = NORMAL) # Added method to display all jobs when "Show All" is clicked def display_jobs(self): # Create a new window to show all job details job_window = Toplevel() job_window.title("All Jobs") # Display table headers Label(job_window, text="Job Number", font=("Arial", 10, "bold")).grid(row=0, column=0, padx=10, pady=5) Label(job_window, text="Customer Name", font=("Arial", 10, "bold")).grid(row=0, column=1, padx=10, pady=5) Label(job_window, text="Total Cost", font=("Arial", 10, "bold")).grid(row=0, column=2, padx=10, pady=5) # Populate job data for idx, (job_num, cust_name, cost) in enumerate(zip(self.job_list, self.customer_list, self.cost_list), start=1): Label(job_window, text=job_num).grid(row=idx, column=0, padx=10, pady=2) Label(job_window, text=cust_name).grid(row=idx, column=1, padx=10, pady=2) Label(job_window, text=f"${cost:.2f}").grid(row=idx, column=2, padx=10, pady=2) if __name__=="__main__": root = Tk() show_label = EntryGUI(root) root.mainloop()
Bonus Improvements
I added a display_jobs method and linked it to the "Show All" button so you can view all stored jobs and their formatted costs in a new window.
Another thing to consider: adding input validation to your Entry fields (like checking that distance/minutes are numbers) to avoid ValueError when users enter non-numeric data. For example, you could use a validation command to only allow digits in those fields.
内容的提问来源于stack exchange,提问作者Lucy

