【问题标题】:2 issues: Python Pickle .dat append to list and tkinter checkbutton issue2 个问题:Python Pickle .dat 附加到列表和 tkinter 检查按钮问题
【发布时间】:2021-08-27 13:15:32
【问题描述】:

我在使用这个应用程序时遇到了很多问题,因为我还不够好,但我几乎完成了它,只想完成它,这样我就可以继续进行一些稍低级别的项目。

这是一个 tkinter 待办事项应用程序。

您可以将任务添加到列表框

对于每个Task,都有一些相关的属性,其中包括:``self.value = vandself.connectivity = c. The hierarchy of the tasks displayed in the listbox is determined by the value of val_var```(例如,值越高越高在列表中将显示)。

任务和相关属性由用户在创建另一个任务时的输入确定。

Task 附加到列表 task_list 并且在用户向列表中添加了超过 1 个任务后,下次添加任务时,用户可以选择检查与其以某种方式连接的现有任务。

列表已排序,因此具有最高值的任务 (val_var) 显示在列表框的顶部,而具有最低值的任务显示在列表框的底部。 您可以“保存任务”,然后在稍后启动应用程序,然后您可以“加载任务”。

问题 1:

从已保存的 .dat 文件加载任务后,它会按照保存的顺序显示在列表框中。 但是,如果您现在想添加另一个任务,至少会发生两件事:

  1. 现在加载到列表框中的任务现在在添加新任务时显示为复选按钮。
  2. 当您添加另一个任务时(这也是在加载 .dat 文件之后),列表框将删除刚刚加载的内容,并且列表框将只显示新添加的任务。

我对能够从 .dat 文件加载 Tasks 实例然后将它们附加到 task_list 以便它们成为应用程序当前会话/实例的一部分很感兴趣,但我不知道如何做到这一点。

问题 2:

在已将任务添加到列表框的给定会话中,可以使用“删除任务”按钮将它们从列表框中删除。 Listbox 中选中的任务被删除,但与task_list 中删除的任务不同。

要测试我的意思,可以将几个任务添加到列表框,然后删除一个。请注意,在尝试创建另一个新任务时,刚刚从列表框中删除的任务仍将显示为选中按钮 - 但是,刚刚删除的另一个不是的任务现在已作为选中按钮消失。

对于这些问题的任何帮助将不胜感激。

代码如下:

from tkinter import Tk, Frame, Button, Entry, Label, OptionMenu, Toplevel, StringVar, Checkbutton, DoubleVar
import tkinter.messagebox 
import pickle

root = Tk()

task_list = []

class Task:
    def __init__(self, n, i, h, v, c): 
        self.name = n
        self.impact = i
        self.hours = h
        self.value = v
        self.connectivity = c

def open_add_task():
    taskwin = Toplevel(root)

    #NAME
    titlelabel = Label(taskwin, text='Title task concisely:').grid(column=1, row=0)
    name_entry = Entry(taskwin, width=40, justify='center')
    name_entry.grid(column=1, row=1)

    #IMPACT
    impactlabel = Label(taskwin, text='Impact').grid(column=1, row=2)
    imp_var = StringVar(value=0)
    OptionMenu(taskwin, imp_var, *range(0, 10+1)).grid(column=1, row=3, sticky='ns')

    #HOURS(required)
    hourlabel = Label(taskwin, text='Whole hours \n required').grid(column=1, row=16)
    hour_entry = Entry(taskwin, width=4, justify='center')
    hour_entry.grid(column=1, row=17)

    #CONNECTIVITY
    C_lab = Label(taskwin,text="Connectivity to other tasks").grid(column=1, row=18)
    placement=19
    vars = [] # list to hold the DoubleVar used by Checkbutton
    for task in task_list:
        # add a DoubleVar to the list
        vars.append(DoubleVar())
        # use the task.value as the "onvalue" option
        Checkbutton(taskwin, text=task.name, variable=vars[-1], onvalue=task.value, offvalue=0).grid(column=1, row=placement, sticky="w")
        placement+=1

    def add_task():
        if name_entry.get() != '': # If textbox inputfield is NOT empty do this

            #CONNECTIVITY
            connectivity = sum(v.get() for v in vars)/10 +1 #if no connectivity the rest below is multiplied by 1
            #VALUE
            val_var = ((((int(imp_var.get())/5) + 1) * (connectivity)+(float(hour_entry.get())/10))) #-(float(hour_entry.get())/20) #-hours fra højere rangerende opgaver skal minusses urgency_var # c = 1+task1(int(imp_var.get())+(int(man_var))+task2(repeat)+task3(repeat)


            task_list.append(Task(name_entry.get(), imp_var.get(), hour_entry.get(), val_var, connectivity))
            reload()
            taskwin.destroy()
        else:
            tkinter.messagebox.showwarning(title='Whoops', message='You must enter a task')

    Add_button = Button(taskwin, text='Add', command=add_task).grid(column=1, row=placement, sticky="ew")
    placement+=1

def reload():
    task_list.sort(key=lambda a: a.value, reverse=True)
    listbox_tasks.delete(0, tkinter.END)

    for x in task_list:
        listbox_tasks.insert(tkinter.END, x.name)

def delete_task():
    try:
        task_index = listbox_tasks.curselection()[0]
        listbox_tasks.delete(task_index)
        tasks = listbox_tasks.get(0, listbox_tasks.size())
        pickle.dump(tasks, open('Todo.dat', 'wb'))
        del task_list[0]
    except:
        tkinter.messagebox.showwarning(title='Error', message='You must select a task to delete')

def save_tasks():
    tasks = listbox_tasks.get(0, listbox_tasks.size())
    pickle.dump(tasks, open('Todo.dat', 'wb'))

def load_tasks():
    try:
        tasks = pickle.load(open('Todo.dat', 'rb'))
        listbox_tasks.delete(0, tkinter.END)
        for task in tasks:
            listbox_tasks.insert(tkinter.END, task)
    except:
        tkinter.messagebox.showwarning(title='Error', message='You have no tasks')

# Create UI
your_tasks_label = Label(root, text='Your tasks:', font=('roboto',11, 'bold'), justify='center')
your_tasks_label.pack(pady=5)


scrollbar_tasks = tkinter.Scrollbar(root)
scrollbar_tasks.pack(side=tkinter.RIGHT, fill=tkinter.Y)

listbox_tasks = tkinter.Listbox(root, height=10, width=45, font=('', 11, 'bold'), fg=('grey'), justify='center') # tkinter.Listbox(where it should go, height=x, width=xx)
listbox_tasks.pack(padx=5, pady=5)

listbox_tasks.config(yscrollcommand=scrollbar_tasks.set)
scrollbar_tasks.config(command=listbox_tasks.yview)

#BUTTONS
New_Task_Button = Button(root, text='New Task', width=42, command=open_add_task)
New_Task_Button.pack()

button_delete_task = Button(root, text='Delete task', width=42, command=delete_task)
button_delete_task.pack()


button_save_tasks = Button(root, text='Save tasks', width=42, command=save_tasks)
button_save_tasks.pack()

button_load_tasks = Button(root, text='Load tasks', width=42, command=load_tasks)
button_load_tasks.pack(pady=5)

root.mainloop()

【问题讨论】:

  • 你能删除不必要的图片,让你的帖子更简洁吗?
  • 怎么不够简洁?你不认为这些图片有助于更清楚地理解我所描述的内容吗?
  • 虽然我很欣赏您为提出问题所付出的努力,但有太多的图片让您阅读您的帖子很烦人,读者将无法理解您的问题。这可能是您仍然没有得到任何答案的原因之一。你的问题应该始终是重点。您只需要包含可能对可以回答您的问题的人有用的必要详细信息。
  • @Art 谢谢你的建议,我已经删除了图片,并尽我所能尽量简洁。

标签: python-3.x list tkinter pickle tkinter.checkbutton


【解决方案1】:

你的问题很简单。您需要保存 Task 类的对象,而不是保存列表框中的字符串。

这就是说你永远不应该像你所做的那样给出裸的 except 子句,总是指定你想要捕获的异常。如果不这样做,您将很难找到确切的问题。

例如在您的代码块中:

try:
     tasks = pickle.load(open('Todo.dat', 'rb'))
     listbox_tasks.delete(0, tkinter.END)
     for task in tasks:
         listbox_tasks.insert(tkinter.END, task)
except:
     tkinter.messagebox.showwarning(title='Error', message='You have no tasks')

这里的异常发生在找不到文件的时候。但是现在如果有一个空文件,并且如果一切顺利并且没有引发异常,那么即使文件中没有任务,也不会显示该消息。更合适的做法是检查文件中是否有任何内容,然后显示消息。

我也经常看到你重写东西。例如这里:

def delete_task():
    ...
    tasks = listbox_tasks.get(0, listbox_tasks.size())
    pickle.dump(tasks, open('Todo.dat', 'wb'))
    ...

你真的需要写和你在save函数下写的一样的东西吗?

这是您更正后的代码:

...
task_list = []

class Task:
    def __init__(self, n, i, h, v, c): 
        self.name = n
        self.impact = i
        self.hours = h
        self.value = v
        self.connectivity = c

...

def reload():
    task_list.sort(key=lambda a: a.value, reverse=True)
    listbox_tasks.delete(0, tkinter.END)

    for x in task_list:
        listbox_tasks.insert(tkinter.END, x.name)


def delete_task():
    try:
        task_index = listbox_tasks.curselection()[0]
        listbox_tasks.delete(task_index)
        task_list.pop(task_index)
        save_tasks()
        
    except IndexError:
        tkinter.messagebox.showwarning(title='Error', message='You must select a task to delete')


def save_tasks():

    with open('Todo.dat', 'wb') as pk:
        pickle.dump(task_list, pk)


def load_tasks():
    global task_list
    try:
        with open('Todo.dat', 'rb') as pk:
            task_list = list(pickle.load(pk))

        reload()
            
    except Exception as e:  # FileNotFound Error
        print(e)
        tkinter.messagebox.showwarning(title='Error', message='You have no tasks')

# Create UI
your_tasks_label = Label(root, text='Your tasks:', font=('roboto',11, 'bold'), justify='center')
your_tasks_label.pack(pady=5)

...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 2016-12-04
    • 1970-01-01
    • 2020-11-18
    相关资源
    最近更新 更多