如何解决是否将类集成到我现有的代码中? Tkinter,蟒蛇 3
我有这个 GUI 应用程序,我已经痴迷了一个多星期,我认为它比我迄今为止获得的有限编程/python 知识所能管理的要难一些 - 但是,我只能'不要停止思考它,我无法弄清楚它让我发疯。
我用 Tkinter 创建了一个 GUI,这是一个 Todo-list 应用程序。但是,应用程序中的每个任务都必须有一些与之相关的信息。
假设我们创建了一个名为“家庭作业”的任务。
我想将一些属性与家庭作业相关联。
因此,其中一些属性将是 “影响”,它代表在 0-10 的范围内完成任务的影响(例如 10:如果我不这样做,我的课程就会失败) t 完成我的家庭作业任务。)和截止日期 - 这是不言自明的。这些只是我想要的 2 个属性(不过还会有更多)。
据我所知,这将是利用 classes 的好时机。
如果我理解正确,我将不得不创建一个 class Task:
,然后将 Task
的每个实例的属性设置为某物。
我在熟悉类之前创建了 GUI,我想与给定任务关联的一些属性信息在创建任务后已经可以在 GUI 中指定(没有任何功能),但我不知道如何使用该信息并将其连接到给定的任务,以便它具有我想要的功能。
我希望能够输入一个任务,指定一些与该任务相关的属性,然后我希望能够“召唤”该任务及其相关属性以进行一些简单的数学和/或排序。 我只希望用户看到该任务本身 - 计算/排序将在幕后进行。
我的问题: 我应该用类来做这件事,还是有一种更初级的方法可以更容易地实现到我现有的代码中? 我真的,真的很想弄清楚如何解决这个问题,因此任何合格的指示或正确的方向或示例、解释等都将受到真正的赞赏。
这是我的代码:
from tkcalendar import *
import tkinter.messageBox # Import the messageBox module
import pickle # Module to save to .dat
import tkinter as tk
TASKS_FILE = "tasks.dat" ##Where the task strings are saved
task_list = [] ##Don't kNow what I am doing yet
impact_number = [] ##Don't kNow if this Could be useful
root = tk.Tk() # ?????
root.title('SmaTodo') # Name of the program/window
# ROOT WINDOW
# Gets the requested values of the height and widht.
windowWidth = root.winfo_reqwidth()
windowHeight = root.winfo_reqheight()
# Gets both half the screen width/height and window width/height
positionRight = int(root.winfo_screenwidth()/2 - windowWidth/2)
positionDown = int(root.winfo_screenheight()/2 - windowHeight/2)
# Positions the window in the center of the page.
root.geometry("+{}+{}".format(positionRight,positionDown))
def new_task():
def add_task():
global task
global impact_window
task = entry_task.get() # we get the task from entry_task and we get the input from the entry_task type-field with .get()
if task != '': # If textBox inputfield is NOT empty do this:
listBox_tasks.insert(tkinter.END,task)
entry_task.delete(0,tkinter.END) #
task_window.destroy()
else:
tkinter.messageBox.showwarning(title='Whoops',message='You must enter a task')
task_window.destroy()
task_window = tk.Toplevel(root)
task_window.title('Add a new task')
task_label = tk.Label(task_window,text = 'Title your task concisely:',justify='center')
task_label.pack()
# Entry for tasks in new window
entry_task = tk.Entry(task_window,width=50,justify='center')
entry_task.pack()
# Add task button in new window
button_add_task = tk.Button(task_window,text='Add task',width=42,command=lambda: [add_task(),impact()])
button_add_task.pack()
def impact():
global impact_next_button
global impact_window
global impact_label
global impact_drop
global options
global select
impact_window = Toplevel(root)
impact_window.title('Impact')
options = StringVar()
options.trace_add
task_label = tk.Label(impact_window,text=str(task),font='bold')
task_label.pack()
impact_label = tk.Label(impact_window,text = 'Specify below the impact of completing this task \n (10 being the highest possible impact)',justify='center')
impact_label.pack()
impact_drop = OptionMenu(impact_window,options,'0','1','2','3','4','5','6','7','8','9','10')
impact_drop.pack()
impact_next_button = tk.Button(impact_window,text='Next',command=connectivity)
impact_next_button.pack(side=tkinter.RIGHT)
def select():
global impact_next_button
global impact_window
global impact_label
global impact_drop
global options
impact_number.append(str(task) + options.trace_add('write',lambda *args: print(str(task)+' '+ 'impact' + ' ' + options.get())))
options.set(options.get())
def connectivity():
impact_window.destroy()
clicked = StringVar()
clicked.set('Select')
global connectivity_next_button
global connectivity_window
global connectivity_label
global connectivity_drop
connectivity_window = Toplevel(root)
connectivity_window.title('Connectivity')
task_label = tk.Label(connectivity_window,font='bold')
task_label.pack()
connectivity_label = tk.Label(connectivity_window,text = 'Specify below the connectivity this task has to other tasks\n (e.g. tasks you can not complete unless you have completed this task)',justify='center')
connectivity_label.pack()
# var1 = Intvar()
Checkbutton(connectivity_window,text="Each task from list must be 'checkable' in this window").pack() # variable=var1).pack()
connectivity_next_button = tk.Button(connectivity_window,command=lambda: [Proximity(),select()])
connectivity_next_button.pack(side=tkinter.RIGHT)
def Proximity():
connectivity_window.destroy()
global proximity_button
global proximity_window
global proximity_label
global proximity_drop
global cal
global proximity_output_date
proximity_window = Toplevel(root)
proximity_window.title('Proxmity')
task_label = tk.Label(proximity_window,font='bold')
task_label.pack()
proximity_label = tk.Label(proximity_window,text = 'Specify a deadline for when this task must be completed',justify='center')
proximity_label.pack()
cal = Calendar(proximity_window,selectmode='day',year=2021,month=4,day=27)
cal.pack()
def get_date():
proximity_output_date.config(text=cal.get_date())
proximity_date_button = tk.Button(proximity_window,text='Pick date',command=get_date)
proximity_date_button.pack()
proximity_output_date = tk.Label(proximity_window,text='')
proximity_output_date.pack()
proximity_button = tk.Button(proximity_window,command=manageability)
proximity_button.pack(side=tkinter.RIGHT)
def manageability():
print('Deadline:'+' '+cal.get_date())
proximity_window.destroy()
clicked = StringVar()
clicked.set('Select')
global manageability_next_button
global manageability_window
global manageability_label
global manageability_drop
manageability_window = Toplevel(root)
manageability_window.title('Manageability')
task_label = tk.Label(manageability_window,font='bold')
task_label.pack()
manageability_label = tk.Label(manageability_window,text = 'Specify how difficult this task is to complete \n (0 being extremely difficult and 10 being extremely easy)',justify='center')
manageability_label.pack()
manageability_drop = OptionMenu(manageability_window,clicked,'10')
manageability_drop.pack()
manageability_next_button = tk.Button(manageability_window,command=urgency)
manageability_next_button.pack(side=tkinter.RIGHT)
def urgency():
pass
def delete_task():
try:
task_index = listBox_tasks.curselection()[0]
listBox_tasks.delete(task_index)
except:
tkinter.messageBox.showwarning(title='Oops',message='You must select a task to delete')
def save_tasks():
tasks = listBox_tasks.get(0,listBox_tasks.size())
pickle.dump(tasks,open('tasks.dat','wb'))
# Create UI
your_tasks_label = tk.Label(root,text='THESE ARE YOUR TASKS:',font=('Roboto',10,'bold'),justify='center')
your_tasks_label.pack()
frame_tasks = tkinter.Frame(root)
frame_tasks.pack()
scrollbar_tasks = tkinter.Scrollbar(frame_tasks)
scrollbar_tasks.pack(side=tkinter.RIGHT,fill=tkinter.Y)
listBox_tasks = tkinter.ListBox(frame_tasks,height=10,10),justify='center') # tkinter.ListBox(where it should go,height=x,width=xx)
listBox_tasks.pack()
listBox_tasks.config(yscrollcommand=scrollbar_tasks.set)
scrollbar_tasks.config(command=listBox_tasks.yview)
try:
tasks = pickle.load(open('tasks.dat','rb'))
listBox_tasks.delete(0,tkinter.END)
for task in tasks:
listBox_tasks.insert(tkinter.END,task)
except:
tkinter.messageBox.showwarning(title='Phew',message='You have no tasks')
# Add task button
button_new_task = tkinter.Button(root,text='New task',command=new_task)
button_new_task.pack()
button_delete_task = tkinter.Button(root,text='Delete task',command=delete_task)
button_delete_task.pack()
button_save_tasks = tkinter.Button(root,text='Save tasks',command=save_tasks)
button_save_tasks.pack()
root.mainloop() # Runs the program - must be at the very buttom of the code
这里的一些人已经帮了我很多,我真的很感激。
解决方法
所以我做了一些示例代码:
from tkinter import Tk,Frame,Button,Entry,Label,Canvas,Scrollbar,OptionMenu,Toplevel,StringVar
import pickle
class Task:
def __init__(self,name,type_,importance):
self.name = name
self.type = type_
self.importance = importance
try:
with open('saved_tasks.dat','rb') as file:
task_list = pickle.load(file)
except FileNotFoundError and EOFError:
with open('saved_tasks.dat','w') as file:
pass
print('Could not locate the file or the file was empty. A new file was created.')
task_list = []
task_types = ['Misc','Math','Science','Economics','Biology','Homework']
def show_tasks():
for widget in task_frame.winfo_children():
widget.destroy()
for task in task_list:
Label(task_frame,text=f'{task.name} | Type: {task.type} | Importance: {task.importance}').pack(fill='x')
def open_add_task():
win = Toplevel(root)
win.focus_force()
Label(win,text='Write task name').grid(column=0,row=0)
Label(win,text='Choose type of task').grid(column=1,text='Choose importance of task').grid(column=2,row=0)
entry = Entry(win)
entry.grid(column=0,row=1,sticky='ew')
type_var = StringVar(value=task_types[0])
OptionMenu(win,type_var,*task_types).grid(column=1,sticky='nsew')
imp_var = StringVar(value=1)
OptionMenu(win,imp_var,*range(1,10+1)).grid(column=2,sticky='nsew')
def add_task():
task_list.append(Task(entry.get(),type_var.get(),imp_var.get()))
show_tasks()
Button(win,text='Add Task',command=add_task).grid(column=0,row=2,columnspan=3,sticky='nsew')
def sort_tasks():
type_ = sort_type.get()
importance = sort_imp.get()
order = asc_desc_var.get()
for widget in task_frame.winfo_children():
widget.destroy()
for task in task_list if order == 'Ascending' else task_list[::-1]:
if type_ == 'All' and importance == 'Any':
Label(task_frame,text=f'{task.name} | Type: {task.type} | Importance: {task.importance}').pack(fill='x')
elif type_ == 'All':
if importance == task.importance:
Label(task_frame,text=f'{task.name} | Type: {task.type} | Importance: {task.importance}').pack(fill='x')
elif type_ != 'All':
if type_ == task.type and importance == 'Any':
Label(task_frame,text=f'{task.name} | Type: {task.type} | Importance: {task.importance}').pack(fill='x')
elif type_ == task.type and importance == task.importance:
Label(task_frame,text=f'{task.name} | Type: {task.type} | Importance: {task.importance}').pack(fill='x')
root = Tk()
btn_frame = Frame(root)
btn_frame.pack(fill='x')
sort_type = StringVar(value='All')
OptionMenu(btn_frame,sort_type,'All',*task_types).grid(column=0,row=0,sticky='nsew')
sort_imp = StringVar(value='Any')
OptionMenu(btn_frame,sort_imp,'Any',10+1)).grid(column=1,sticky='nsew')
asc_desc_var = StringVar(value='Ascending')
OptionMenu(btn_frame,asc_desc_var,'Ascending','Descending').grid(column=2,sticky='nsew')
Button(btn_frame,text='Sort',command=sort_tasks).grid(column=0,text='Add New',command=open_add_task).grid(column=3,rowspan=2,sticky='nsew')
task_frame_main = Frame(root)
task_frame_main.pack()
task_frame = Frame()
canvas = Canvas(task_frame_main)
canvas.pack(side='left',expand=True,fill='both')
canvas.create_window((0,0),window=task_frame,tag='task_frame',anchor='nw')
scrollbar = Scrollbar(task_frame_main,orient='vertical',command=canvas.yview)
scrollbar.pack(side='right',fill='y')
canvas.config(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>',lambda e: canvas.config(scrollregion=canvas.bbox('task_frame')))
show_tasks()
root.mainloop()
try:
with open('saved_tasks.dat','wb') as file:
pickle.dump(task_list,file)
print('File saved.')
except Exception as e:
print(f'Exception was raised:\n{e}')
这里的主要部分是 Task
类,因为您可以看到它非常小,这就是重点,它不必太大。并且 task_list
可以使用 pickle
轻松序列化并且易于加载,并且它会保留那些具有给定属性的类。
如果您有任何其他问题,请提问。
解释一切(或至少解释大部分):
首先导入您需要的所有内容,我喜欢在使用 tkinter 时这样做。
然后我定义了 task_list
它将用于存储添加的任务,这可以并且可能应该由文件替换,因此您可以读取文件,然后将保存的任务附加到此列表中或仅使用 json或 pickle 将文件作为列表导入,这样更容易。无论如何,然后我刚刚创建了一个列表来存储所有类型的任务,它可以修改,这又不是必需的,但是可以从文件中加载列表,例如,如果有添加另一种类型的选项(这需要相当多的编码)将它们保存到文件中以便保存信息会很棒。
现在关于class Task
:
这个类没有很多属性,实际上只有三个来存储基本的东西,比如任务的name
、任务的type
以及它的重要性。
这里没有太多内容,但要提到的是,可以使用例如 pickle
模块并将其应用于 task_list
(将存储 Task
的实例),它将序列化这个对象,同时保留它的属性,所以当从 pickle
加载时,仍然可以以相同的方式访问该对象。
现在转到 show_tasks()
函数。
所以这是一个通用函数,用于显示附加到 task_list
也就是所有任务的所有内容。此函数将 Label
放在下面指定的框架上,但首先它会删除该框架外的所有内容,否则它每次都会附加所有项目,这意味着它将呈指数增长(您可以通过删除第一个来测试您是否想要循环并添加一些任务)。
接下来是 open_add_task()
函数,用于添加任务。
它首先创建另一个窗口 Toplevel
并将焦点放在它上面。 (有时我喜欢bind
这样的窗口,这样当用户点击窗口外并且这个窗口失去焦点时关闭它,这样就不会有多个这样的窗口,但这取决于你)。
然后我创建了一些标签来帮助用户指出他们的要求。
然后我放置了条目,以便用户可以输入任务名称,然后为了避免用户输入错误,我让他们选择他们想要的类别和重要性,以免他们输入错误。
然后我定义了一个函数 (add_task()
),用于从用户输入中收集数据、创建类实例并将其附加到 task_list
。并以创建一个调用此函数的 Button 结束。
进入sort_tasks
。
此功能与根上的小部件链接,因此有参考。所以首先获取用户输入的内容并存储在变量中以便于重用。同样,通过提供选择,用户输入变得更容易。再次清除所有小部件,然后是排序/逻辑部分,这可能可以改进,我没有添加按重要性数字排序的选项(所以它有多高)所以它按添加的时间排序(同样没有确切的时间但只是列表中的顺序是添加的时间)。逻辑可以改进,但它主要做它应该做的事情(已经晚了,我无法正确思考)但是是的,没有太多可以解释的,只需自己逐步完成即可。
下一位是主窗口,它不在任何函数内,不使用global
。首先我启动了 Tk()
这是基本的,最后使用了 .mainloop()
- 基本的东西。然后有很多框架用于帮助组织小部件,然后添加所有小部件在这种情况下我说的是有助于 sort_tasks()
功能的小部件。因此添加了所有选择菜单和执行 sort_tasks
的按钮。还有一个调用 open_add_task()
的按钮。
下一位是显示所有任务的主框架。画布很重要,因为 Frame
本身不能滚动,而画布可以滚动,所以本质上会发生什么,是一个框架被添加到画布并且 scrollregion
被设置为 { {1}} 大小。然后添加滚动条(将添加链接)。
仅此而已。
编辑:
添加了保存和读取文件的功能,以便可以保存和加载任务。出于某种原因,文件必须在 Frame
之后加载,因为显然否则它会抛出一个我不完全理解的错误,但我通过将类移到整个事情之上来处理它。我还发现了一个问题,当添加新任务并且它们超过可见帧限制时,滚动条不起作用,但是再次打开文件它可以正常工作,因此可以处理。同样如您所见,我在 Task
之后添加了保存功能,以便每当用户关闭窗口时,它都会将任务保存到文件中。 (添加到来源)
来源:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。