如何在python中制作删除元素的按钮

问题描述 投票:0回答:1

我正在用Python制作一个简单的任务管理器,但我想不出一种方法可以让按钮删除任务(如果制作完成)。

我尝试制作一个删除项目的功能,但没有成功。由于某种原因,该函数仅删除第一项,然后开始给出错误:

ValueError:list.remove(x):x不在列表中

import json
from tkinter import *

PATH = "data.json"


class Data:
    data: list[dict] = []

    def __init__(self):
        self.read_data()

    def read_data(self):
        with open(PATH, "r") as file:
            self.data = json.load(file)

    def write_data(self):
        with open(PATH, "w") as file:
            json.dump(self.data, file, indent=4)

    def update_ids(self):
        id = 0
        for task in self.data:
            task['id'] = id
            id += 1
        self.write_data()

    def write_task(self, name: str, date: str, importance: str):
        self.data.append({
            "name": name,
            "date": date,
            "importance": importance,
            "id": self.data[-1]['id'] + 1
        })
        self.write_data()

    def get_task(self, id: int) -> dict:
        for task in self.data:
            if task['id'] == id:
                return task

    def __iter__(self):
        for task in self.data:
            yield task

    def delete_task(self, id: int):
        self.data = [task for task in self.data if task['id'] != id]
        self.write_data()


Tasks = Data()


class Window(Tk):
    tasks: list[dict] = []

    def __init__(self):
        super().__init__()
        self.protocol("WM_DELETE_WINDOW", self.on_closing)

        self.create_tasks()
        self.render_tasks()
        self.mainloop()

    def create_tasks(self):
        for task in Tasks:
            label = Label(self, text=f"task :{task['name']} \ndate : {task['date']}", fg=task['importance'])
            button = Button(self, text="Delete")

            pack = {
                "label": label,
                "button": button
            }
            self.tasks.append(pack)

            def function():
                label.destroy()
                button.destroy()
                self.tasks.remove(pack)
                Tasks.delete_task(task['id'])
                self.render_tasks()

            button.config(command=function)

    def render_tasks(self):
        for task in self.tasks:
            task['label'].pack()
            task['button'].pack()

    def on_closing(self):
        Tasks.update_ids()
        self.destroy()


if __name__ == "__main__":
    wnd = Window()

python user-interface tkinter button destroy
1个回答
0
投票

您遇到的问题是如何定义 function() 。您在其中所做的就是引用局部变量(标签、按钮、包……),这些变量在您执行循环时会被修改。循环完成后,这些变量保留最后一次迭代的值,这就是为什么您总是在第一次按时删除最后一个(无论按哪个按钮),而第二次则失败。

您可以做的是为所有这些值找到一些外部存储,以便您可以在删除时引用它们,并使用部分定义每个按钮的命令,以便每个按钮都有它所引用的条目的标识(如此处所解释)。

我对你的程序做了一个非常粗略的修改来展示这个想法。至少您会看到正确的项目从窗口中消失,尽管它缺少数据中的删除:

import json from tkinter import * from functools import partial PATH = "data.json" class Data: data: list[dict] = [] def __init__(self): self.read_data() def read_data(self): with open(PATH, "r") as file: self.data = json.load(file) def write_data(self): with open(PATH, "w") as file: json.dump(self.data, file, indent=4) def update_ids(self): id = 0 for task in self.data: task['id'] = id id += 1 self.write_data() def write_task(self, name: str, date: str, importance: str): self.data.append({ "name": name, "date": date, "importance": importance, "id": self.data[-1]['id'] + 1 }) self.write_data() def get_task(self, id: int) -> dict: for task in self.data: if task['id'] == id: return task def __iter__(self): for task in self.data: yield task def delete_task(self, id: int): self.data = [task for task in self.data if task['id'] != id] self.write_data() Tasks = Data() class Window(Tk): tasks: dict[dict] = {} def __init__(self): super().__init__() self.protocol("WM_DELETE_WINDOW", self.on_closing) self.create_tasks() self.render_tasks() self.mainloop() def create_tasks(self): for task in Tasks: label_text = f"task :{task['name']} \ndate : {task['date']}" label = Label(self, text=label_text, fg=task['importance']) button = Button(self, text="Delete") pack = { "label": label, "button": button } self.tasks[label_text]=pack def function(t): print(t) print(self.tasks[t]) self.tasks[t]['label'].destroy() self.tasks[t]['button'].destroy() #Tasks.delete_task(self.tasks[t]['id']) self.tasks.pop(t) self.render_tasks() button.config(command=partial(function, label_text)) def render_tasks(self): for task in self.tasks.values(): print(task) task['label'].pack() task['button'].pack() def on_closing(self): Tasks.update_ids() self.destroy() if __name__ == "__main__": wnd = Window()
    
© www.soinside.com 2019 - 2024. All rights reserved.