这是我的未完成的程序:
我创建了一个Frame()带有输入字段和按钮的类。
Frame()
然后我有一个+按钮,它通过将对象添加到空列表中来创建此类的新实例。对象.pack()本身在初始化时,因此它们出现在窗口中。
+
.pack()
编辑:添加了您可以尝试的工作代码:
import tkinter as tk from tkinter import ttk import tkinter.font as tkFont class JobItem: def __init__(self, parent): self.frame = tk.Frame(parent, bd=2, relief=tk.GROOVE) self.frame.pack(side=tk.TOP, fill=tk.X, padx=2, pady=2) self.nameLabel = ttk.Label(self.frame, text="Description:") self.nameLabel.grid(column=0, row=0, sticky=tk.W, padx=5, pady=5) self.nameEntry = ttk.Entry(self.frame) self.nameEntry.grid(column=1, row=0, sticky=tk.W, padx=5, pady=5) self.jobTypeLabel = ttk.Label(self.frame, text="Job type:") self.jobTypeLabel.grid(column=3, row=0, sticky=tk.W, padx=5, pady=5) self.selected_job = tk.StringVar() self.job_type_cb = ttk.Combobox(self.frame, textvariable=self.selected_job, state='readonly') self.job_type_cb['values'] = ['Still', 'Animation', 'Model production'] self.job_type_cb.current(0) self.job_type_cb.grid(column=4, row=0, sticky=tk.W, padx=5, pady=5) self.x = ttk.Button(self.frame, text="X", command=self.delete_itself) self.x.grid(column=5, row=0, sticky=tk.E, padx=5, pady=5) # v v v This method is what I don't know how to do properly v v v def delete_itself(): pass job_items = list() def add_jobItem(): job_items.insert(len(job_items), JobItem(itemListContainer)) root=tk.Tk() root.title('Estimate generator') root.geometry('800x500') headerFrame = tk.Frame(root, height=100) headerFrame.pack(side=tk.TOP, fill=tk.X) jobNameLabel = ttk.Label(headerFrame, text="Project name: ") jobNameLabel.pack(side=tk.LEFT) jobNameEntry = ttk.Entry(headerFrame) jobNameEntry.pack(side=tk.LEFT, expand=True, fill=tk.X) buttonFont = tkFont.Font(weight="bold") plusButton = tk.Button(headerFrame, text='+', command=add_jobItem, font=buttonFont, fg='#656565', height=0, width=10) plusButton.pack(side=tk.RIGHT, padx=(100,2), pady=2) # Item List Frame itemListContainer = tk.Frame(root) itemListContainer.pack(side=tk.TOP, fill=tk.BOTH, expand=True) root.mainloop()
如何让给X定实例上的按钮不仅删除打包元素,还删除job_items列表中的对象?我们如何知道它在列表中占据什么索引?或者也许我应该采取不同的方法?
X
job_items
我建议传递一个JobItem将在内部执行的函数delete_itself:
JobItem
delete_itself
class JobItem: def __init__(self, parent, on_delete=None): self.on_delete = on_delete ... def delete_itself(self): # destroy the frame self.frame.destroy() # call self.on_delete if it is not None if self.on_delete: # pass JobItem itself to self.on_delete self.on_delete(self) job_items = list() def del_jobItem(item): # remove the job item from job_items list job_items.remove(item) def add_jobItem(): # can use job_items.append(...) instead #job_items.insert(len(job_items), JobItem(itemListContainer, del_jobItem)) job_items.append(JobItem(itemListContainer, del_jobItem)) ...
要在点击 X 按钮时删除 job_items 列表中的对象并移除界面上的相应项,您需要传递到 delete_itself 方法中该项在 job_items 列表中的索引。为了实现这一点,您可以在创建 JobItem 实例时,将该实例与其索引绑定。具体而言,您可以通过 command 将索引作为参数传递给 delete_itself 方法,这样它就可以删除对应的列表项。
command
我们可以改进代码,利用 lambda 来将 index 传递给删除方法。更新后的代码如下:
lambda
index
import tkinter as tk from tkinter import ttk import tkinter.font as tkFont class JobItem: def __init__(self, parent, index): self.index = index # 记录当前对象的索引 self.frame = tk.Frame(parent, bd=2, relief=tk.GROOVE) self.frame.pack(side=tk.TOP, fill=tk.X, padx=2, pady=2) self.nameLabel = ttk.Label(self.frame, text="Description:") self.nameLabel.grid(column=0, row=0, sticky=tk.W, padx=5, pady=5) self.nameEntry = ttk.Entry(self.frame) self.nameEntry.grid(column=1, row=0, sticky=tk.W, padx=5, pady=5) self.jobTypeLabel = ttk.Label(self.frame, text="Job type:") self.jobTypeLabel.grid(column=3, row=0, sticky=tk.W, padx=5, pady=5) self.selected_job = tk.StringVar() self.job_type_cb = ttk.Combobox(self.frame, textvariable=self.selected_job, state='readonly') self.job_type_cb['values'] = ['Still', 'Animation', 'Model production'] self.job_type_cb.current(0) self.job_type_cb.grid(column=4, row=0, sticky=tk.W, padx=5, pady=5) self.x = ttk.Button(self.frame, text="X", command=lambda: self.delete_itself(index)) self.x.grid(column=5, row=0, sticky=tk.E, padx=5, pady=5) def delete_itself(self, index): # 从界面和列表中删除该项 self.frame.destroy() # 删除界面元素 del job_items[index] # 从job_items列表中删除对应项 job_items = list() def add_jobItem(): job_items.append(JobItem(itemListContainer, len(job_items))) root = tk.Tk() root.title('Estimate generator') root.geometry('800x500') headerFrame = tk.Frame(root, height=100) headerFrame.pack(side=tk.TOP, fill=tk.X) jobNameLabel = ttk.Label(headerFrame, text="Project name: ") jobNameLabel.pack(side=tk.LEFT) jobNameEntry = ttk.Entry(headerFrame) jobNameEntry.pack(side=tk.LEFT, expand=True, fill=tk.X) buttonFont = tkFont.Font(weight="bold") plusButton = tk.Button(headerFrame, text='+', command=add_jobItem, font=buttonFont, fg='#656565', height=0, width=10) plusButton.pack(side=tk.RIGHT, padx=(100, 2), pady=2) # Item List Frame itemListContainer = tk.Frame(root) itemListContainer.pack(side=tk.TOP, fill=tk.BOTH, expand=True) root.mainloop()
索引传递:在 JobItem 的 __init__ 构造函数中,新增了一个 index 参数来标记每个 JobItem 对象在 job_items 列表中的位置。这个 index 会在点击 X 按钮时传递给 delete_itself 方法。
__init__
删除方法:
self.frame.destroy()
Frame
del job_items[index]
现在,当您点击 X 按钮时,相关的 JobItem 将被从界面和 job_items 列表中删除。