小能豆

如何使用其方法从列表中删除对象?

py

这是我的未完成的程序:

5GmOQ.gif

我创建了一个Frame()带有输入字段和按钮的类。

然后我有一个+按钮,它通过将对象添加到空列表中来创建此类的新实例。对象.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列表中的对象?我们如何知道它在列表中占据什么索引?或者也许我应该采取不同的方法?


阅读 26

收藏
2024-12-02

共2个答案

小能豆

我建议传递一个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))

...
2024-12-02
小能豆

要在点击 X 按钮时删除 job_items 列表中的对象并移除界面上的相应项,您需要传递到 delete_itself 方法中该项在 job_items 列表中的索引。为了实现这一点,您可以在创建 JobItem 实例时,将该实例与其索引绑定。具体而言,您可以通过 command 将索引作为参数传递给 delete_itself 方法,这样它就可以删除对应的列表项。

我们可以改进代码,利用 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()

关键改动:

  1. 索引传递:在 JobItem__init__ 构造函数中,新增了一个 index 参数来标记每个 JobItem 对象在 job_items 列表中的位置。这个 index 会在点击 X 按钮时传递给 delete_itself 方法。

  2. 删除方法

  3. delete_itself 中,通过 self.frame.destroy() 删除界面上的该项(即该 Frame)。
  4. 使用 del job_items[index]job_items 列表中删除该项。

这样做的好处:

  • 动态索引:每次添加新项时,job_items 列表的索引会随着新项的添加自动更新,因此删除操作时可以准确定位到相应的索引。
  • 删除界面和列表项:删除时不仅移除界面上的组件,还会从列表中删除对应的对象,保持一致性。

现在,当您点击 X 按钮时,相关的 JobItem 将被从界面和 job_items 列表中删除。

2024-12-02