在日常工作和生活中,我们经常需要记录和管理待办事项,以确保工作和生活的顺利进行。根据最新调查显示,使用专业任务管理工具的用户比不使用者的工作效率平均提升42%。本节教程将介绍如何通过Python编写一个简单而实用的待办事项管理程序,通过Python标准库中的Tkinter创建简单的GUI图形界面,并通过JSON进行数据存储,允许用户添加、编辑和删除待办事项。
1、待办事项管理器介绍
程序启动时,如果在当前脚本工作目录下存在“data.json”文件,则程序默认会从JSON文件中读取已保存的任务数据,如果不存在“data.json”文件,则会在当前脚本工作目录下自动创建“data.json”文件,用于保存任务数据。
主要功能介绍:
日期处理与日历选择:通过datetime库处理日期,通过tkcalendar库处理日历选择,tkcalendar库是Python的第三方库,用于创建和管理日期和时间的日历控件。
添加待办事项:点击“添加新任务”按钮后,在输入窗口中输入待办事项的详细信息,程序会将待办事项内容保存到本地的“data.json”文件中,下次打开程序时,会默认读取本地JSON文件中的数据。
编辑待办事项:在任务列表中可以通过左键双击鼠标,直接打开编辑待办事项的窗口,也可以点击界面中的“编辑任务”按钮,修改指定的任务。
删除待办事项:在任务列表中右击鼠标可以删除单条任务信息,也可以点击界面中的“删除任务”按钮,删除指定的任务。
优先级排序:优先级分为高/中/低三级,实现优先级顺序。
智能搜索功能: 支持多条件组合搜索 ,包括关键词搜索、任务状态、优先级。
任务列表颜色管理:在任务列表中,根据优先级、任务日期、完成状态突出显示不同的颜色。
2、待办事项管理器界面演示
3、代码实现
(1)安装tkcalendar库
首先,确保你已经安装了tkcalendar库。如果还没有安装,可以通过pip安装:
pip install tkcalendar
(2)待办事项管理器,完整代码如下所示:
动手练一练:
import tkinter as tk
from tkinter import ttk, messagebox
import os, json, locale, webbrowser
from datetime import datetime
from tkcalendar import DateEntry
# 获取当前脚本文件所在的目录
default_directory = os.path.dirname(os.path.abspath(__file__))
# 将当前脚本文件所在的目录设置为工作目录
os.chdir(default_directory)
# 定义空列表,用于从JSON文件导入全局任务列表
tasks = []
# 定义JSON文件名为“data.json”
JSON_FILE = "data.json"
# 设置系统的语言环境为中文
locale.setlocale(locale.LC_ALL, 'zh_CN.utf8')
# 定义成功提示框
def show_sucess(window, txt):
add = tk.Toplevel(window)
add.title("成功")
screen_width, screen_height = add.maxsize()
# 窗口的宽和高
width = 300
height = 100
centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
(screen_height - height) / 2)
add.geometry(centre)
tk.Label(add, text=f'{txt}', font=('黑体', 14)).pack(pady=10)
def confirmm():
add.destroy()
# 确定按钮
tk.Button(add, text='确定', font=('黑体', 12), width=10, command=confirmm).pack(pady=10)
# 定义错误提示框
def show_error(window, txt):
add = tk.Toplevel(window)
add.title("错误")
screen_width, screen_height = add.maxsize()
# 窗口的宽和高
width = 300
height = 100
centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
(screen_height - height) / 2)
add.geometry(centre)
tk.Label(add, text=f'{txt}', font=('黑体', 14)).pack(pady=10)
def confirmm():
add.destroy()
# 确定按钮
tk.Button(add, text='确定', font=('黑体', 12), width=10, command=confirmm).pack(pady=10)
# 创建主窗口界面
class TaskApp:
def __init__(self, root):
self.root = root
self.root.title("待办事项管理器")
# 设置窗口居中
window_width = 950
window_height = 710
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.root.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.root.resizable(width=False, height=False)
self.root.grid_columnconfigure(0, weight=1)
self.root.grid_rowconfigure(0, weight=1)
self.tasks_by_date = {}
self.group_states = {}
# 窗口样式配置
self.style = ttk.Style()
self.set_styles()
# 创建主界面控件
self.create_widgets()
# 启动时间更新
self.update_time()
# 点击关闭窗口触发函数
def window_close(self):
# 弹出确认对话框
if messagebox.askokcancel("退出", "你确定要退出吗?"):
# 点击确定后关闭窗口
self.root.destroy()
# 定义样式函数
def set_styles(self):
self.style.configure("TButton", padding=6)
self.style.configure("TLabel", padding=3)
self.style.configure("TEntry", padding=3)
self.style.configure("Blue.TLabel", foreground="blue", font=("宋体", 20))
self.style.configure("Treeview", rowheight=25) # 定义行高
self.style.configure("Treeview.Heading", font=("宋体", 10, "bold"))
# 创建“待办事项”界面控件
def create_widgets(self):
# 加载任务
self.tasks_load()
# 定义标题标签
title_label = ttk.Label(self.root, text="待办事项管理器", font=('宋体', 20, 'bold'))
title_label.pack(pady=10, padx=10)
# 添加新任务区域
add_frame = ttk.LabelFrame(self.root, text="添加新任务", padding="10")
add_frame.pack(fill=tk.X, pady=10, padx=10)
# 当前时间显示
self.time_label = ttk.Label(add_frame, text="", style="Blue.TLabel")
self.time_label.pack(pady=(0, 5))
# 添加新任务按钮
add_button = ttk.Button(add_frame, text="添加新任务", command=self.add_task)
add_button.pack(padx=10, pady=10)
# 任务列表区域
list_frame = ttk.LabelFrame(self.root, text="任务列表", padding=5)
list_frame.pack(fill=tk.X, padx=5, pady=5)
# 任务搜索区域
search_frame = ttk.Frame(list_frame)
search_frame.pack(fill=tk.X, pady=5)
# 关键词搜索
ttk.Label(search_frame, text="搜索关键词:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
self.search_entry = ttk.Entry(search_frame, width=25)
self.search_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
# 状态筛选
ttk.Label(search_frame, text="任务状态:").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
self.status_var = tk.StringVar(value="全部")
self.status_combobox = ttk.Combobox(search_frame, textvariable=self.status_var, values=["全部", "已完成", "未完成"], state="readonly")
self.status_combobox.grid(row=0, column=3, padx=5, pady=5, sticky=tk.W)
# 优先级筛选
ttk.Label(search_frame, text="优先级:").grid(row=0, column=4, padx=5, pady=5, sticky=tk.W)
self.priority_filter_var = tk.StringVar(value="全部")
self.priority_combobox = ttk.Combobox(search_frame, textvariable=self.priority_filter_var, values=["全部", "高", "中", "低"],
state="readonly")
self.priority_combobox.grid(row=0, column=5, padx=5, pady=5, sticky=tk.W)
self.search_button = ttk.Button(search_frame, text="搜索", command=self.update_list)
self.search_button.grid(row=0, column=6, padx=8, pady=5, sticky=tk.W)
# 排序区域
sort_frame = ttk.Frame(list_frame)
sort_frame.pack(fill=tk.X, pady=5)
ttk.Label(sort_frame, text="排序字段:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
self.sort_var = tk.StringVar(value="创建时间")
self.sort_combobox = ttk.Combobox(sort_frame, textvariable=self.sort_var,
values=["任务名称", "优先级", "状态", "截止日期", "创建时间"],
state="readonly")
self.sort_combobox.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
ttk.Label(sort_frame, text="排序方向:").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
self.order_var = tk.StringVar(value="升序")
self.order_combobox = ttk.Combobox(sort_frame, textvariable=self.order_var, values=["升序", "降序"], state="readonly")
self.order_combobox.grid(row=0, column=3, padx=5, pady=5, sticky=tk.W)
ttk.Button(sort_frame, text="任务排序", command=self.update_list).grid(row=0, column=4, padx=10, pady=5, sticky=tk.E)
# 任务统计
self.task_count = ttk.Label(sort_frame, text=f"共 {len(tasks)} 个任务")
self.task_count.grid(row=0, column=5, padx=5, pady=5, sticky=tk.E)
# 利用Treeview控件显示任务列表
columns = ("ID", "任务名称", "创建时间", "截止日期", "状态", "提醒设置", "描述")
self.tree = ttk.Treeview(list_frame, columns=columns, show="headings", selectmode="browse")
# 设置表头
for col in columns:
self.tree.heading(col, text=col)
# 设置列的宽度
self.tree.column(col, width=130, anchor="center")
# 初始化列表
self.update_list()
# 为列表添加标签样式
def fixed_map(option):
return [elm for elm in style.map("Treeview", query_opt=option)
if elm[:2] != ("!disabled", "!selected")]
style = ttk.Style()
style.map("Treeview",
foreground=fixed_map("foreground"),
background=fixed_map("background"))
self.tree.tag_configure("high", foreground="red")
self.tree.tag_configure("medium", foreground="orange")
self.tree.tag_configure("low", foreground="green")
self.tree.tag_configure("overdue", background="#ffe6e6") # 粉红色为过期任务
self.tree.tag_configure("today", background="#fff6cc") # 淡黄色为今日到期任务
self.tree.tag_configure("soon", background="#e6f2ff") # 淡蓝色为即将到期任务
self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 设置滚动条
scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.tree.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.tree.configure(yscrollcommand=scrollbar.set)
# 鼠标双击任务列表任意一行,可以触发修改任务页面
def double_click(event):
# 获取被双击的项的IID
iid = self.tree.focus()
if iid == '':
return # 如果没有选中任何一行,则直接返回
# 选中指定的行
self.tree.selection_set((iid,))
self.edit_task()
# 绑定鼠标双击事件
self.tree.bind("<Double-1>", double_click)
# 鼠标右键点击任务列表任意一行,就会显示“删除任务”按钮
def right_click(event):
# 获取当前焦点项的iid
iid = self.tree.focus()
# 选中指定的行
self.tree.selection_set((iid,))
if iid:
# 弹出菜单选项
menu = tk.Menu(self.tree, tearoff=0)
menu.add_command(label="删除任务", command=self.delete_task)
menu.tk_popup(event.x_root, event.y_root)
# 绑定鼠标右键点击事件
self.tree.bind("<Button-3>", right_click)
# 功能按钮
button_frame = ttk.Frame(self.root)
button_frame.pack(fill=tk.X, pady=5)
refresh_button = ttk.Button(button_frame, text="刷新列表", command=self.update_list)
refresh_button.pack(side=tk.LEFT, padx=10)
add_button = ttk.Button(button_frame, text="添加新任务", command=self.add_task)
add_button.pack(side=tk.LEFT, padx=10)
edit_button = ttk.Button(button_frame, text="编辑任务", command=self.edit_task)
edit_button.pack(side=tk.LEFT, padx=10)
delete_button = ttk.Button(button_frame, text="删除任务", command=self.delete_task)
delete_button.pack(side=tk.LEFT, padx=10)
quit_button = ttk.Button(button_frame, text="退出", command=self.window_close)
quit_button.pack(side=tk.LEFT, padx=10)
about_button = ttk.Button(button_frame, text="关于程序", command=self.app_about)
about_button.pack(side=tk.RIGHT, padx=10)
help_button = ttk.Button(button_frame, text="程序讲解", command=self.help_window)
help_button.pack(side=tk.RIGHT, padx=10)
# 添加任务
def add_task(self):
self.add_window = tk.Toplevel(self.root)
self.add_window.title("添加任务")
# 设置窗口居中
window_width = 500
window_height = 440
screen_width = self.add_window.winfo_screenwidth()
screen_height = self.add_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.add_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.add_window.resizable(width=False, height=False)
# 创建标题标签控件
show_title = tk.Label(self.add_window, text=">>>添加任务<<<", bg = "white", fg = "black", font = ("宋体", 18), bd = '0', anchor = 'center')
show_title.place(x = 50, y = 30, width = 400, height = 50)
# 任务名称
ttk.Label(self.add_window, text="任务名称:", width=10, anchor=tk.E).place(x = 75, y = 120, anchor = 'nw')
self.name_entry = ttk.Entry(self.add_window, width=40)
self.name_entry.place(x = 150, y = 120, anchor = 'nw')
# 优先级
ttk.Label(self.add_window, text="优先级:", width=10, anchor=tk.E).place(x = 75, y = 170, anchor = 'nw')
self.priority_input_var = tk.StringVar(value="中")
self.priority_combobox = ttk.Combobox(self.add_window, textvariable=self.priority_input_var, values=["高", "中", "低"], state="readonly")
self.priority_combobox.place(x = 150, y = 170, anchor = 'nw')
# 任务描述
ttk.Label(self.add_window, text="任务描述:", width=10, anchor=tk.E).place(x = 75, y = 220, anchor = 'nw')
self.description_entry = ttk.Entry(self.add_window, width=40)
self.description_entry.place(x = 150, y = 220, anchor = 'nw')
# 截止日期(日历)
ttk.Label(self.add_window, text="截止日期:", width=10, anchor=tk.E).place(x = 75, y = 270, anchor = 'nw')
self.deaddate_calendar = DateEntry(self.add_window, date_pattern="yyyy-mm-dd", locale='zh_CN')
self.deaddate_calendar.set_date(datetime.now())
self.deaddate_calendar.place(x = 150, y = 270, anchor = 'nw')
# 提醒设置
ttk.Label(self.add_window, text="提醒设置:", width=10, anchor=tk.E).place(x = 75, y = 320, anchor = 'nw')
self.reminder_var = tk.StringVar(value="不提醒")
reminder_comb = ttk.Combobox(self.add_window, textvariable=self.reminder_var,
values=["不提醒", "提前5分钟", "提前15分钟", "提前30分钟", "提前1小时", "提前1天"],
state="readonly")
reminder_comb.place(x = 150, y = 320, anchor = 'nw')
# 确认添加按钮
add_button = ttk.Button(self.add_window, text="确认添加任务", command=self.add_command)
add_button.place(x = 200, y = 370, anchor = 'nw')
# 更新当前时间显示
def update_time(self):
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.time_label.config(text=f"当前时间: {current_time}")
self.root.after(1000, self.update_time) # 每秒更新一次
# 通过JSON文件加载任务
def tasks_load(self):
global tasks
if os.path.exists(JSON_FILE):
try:
with open(JSON_FILE, "r", encoding="utf-8") as file:
tasks = json.load(file)
except Exception as e:
show_error(self.root, f"加载任务失败: {e}")
tasks = []
else:
tasks = []
# 通过JSON文件保存任务内容
def tasks_save(self):
try:
with open(JSON_FILE, "w", encoding="utf-8") as file:
json.dump(tasks, file, ensure_ascii=False, indent=4)
except Exception as e:
show_error(self.root, f"保存任务失败: {e}")
# 更新任务列表显示,包括筛选或排序方式
def update_list(self):
# 清空表格
for item in self.tree.get_children():
self.tree.delete(item)
# 任务列表筛选
tasks_filtered = self.apply_filter()
# 任务列表排序
tasks_sorted = self.apply_sort(tasks_filtered)
# 遍历任务列表重新插入数据
for index, task in enumerate(tasks_sorted, start=1):
# 根据优先级显示不同颜色
tag = ""
if task["priority"] == "高":
tag = "high"
elif task["priority"] == "中":
tag = "medium"
else:
tag = "low"
# 通过截止日期设置特殊样式
if task["deaddate"] and not task["status"]:
deaddate_date = datetime.strptime(task["deaddate"], "%Y-%m-%d").date()
today = datetime.now().date()
if deaddate_date < today:
tag = "overdue"
elif deaddate_date == today:
tag = "today"
elif (deaddate_date - today).days <= 3:
tag = "soon"
# 添加数据
self.tree.insert(
"",
tk.END,
values=(
index,
task["name"],
task["created"],
task["deaddate"],
"√" if task["status"] else "×",
task["reminder"],
task["description"]
),
tags=(tag,)
)
# 更新任务统计
self.task_count.config(text=f"共 {len(tasks_filtered)} 个任务")
# 设置列表宽度
for col in self.tree["columns"]:
self.tree.column(col, width=130, anchor="center")
# 定义筛选条件,包括多字段模糊匹配+状态+优先级
def apply_filter(self):
filter_text = self.search_entry.get().lower()
filter_status = self.status_var.get()
filter_priority = self.priority_filter_var.get()
filtered = []
for task in tasks:
# 名称/描述/提醒模糊匹配
name_match = filter_text in task["name"].lower()
describe_match = filter_text in task["description"].lower()
reminder_match = filter_text in task["reminder"].lower()
# 状态筛选(全部/已完成/未完成)
status_match = (filter_status == "全部") or (task["status"] == (filter_status == "已完成"))
# 优先级筛选(全部/高/中/低)
priority_match = (filter_priority == "全部") or (task["priority"] == filter_priority)
if (name_match or describe_match or reminder_match) and status_match and priority_match:
filtered.append(task)
return filtered
# 定义列表排序,包括按选择的字段和顺序
def apply_sort(self, tasks_list):
sort_by = self.sort_var.get()
sort_order = self.order_var.get()
# 自定义排序键
def sort_key(task):
if sort_by == "任务名称":
return task["name"]
elif sort_by == "优先级":
return {"高": 1, "中": 2, "低": 3}[task["priority"]]
elif sort_by == "状态":
return task["status"] # 已完成(True)排在后面
elif sort_by == "截止日期":
return datetime.strptime(task["deaddate"], "%Y-%m-%d") if task["deaddate"] else datetime.max
elif sort_by == "创建时间":
return datetime.strptime(task["created"], "%Y-%m-%d %H:%M:%S")
return 0 # 默认按ID排序
# 排序
tasks_sorted = sorted(tasks_list, key=sort_key, reverse=(sort_order == "降序"))
return tasks_sorted
# 添加新任务
def add_command(self):
task_name = self.name_entry.get().strip()
priority = self.priority_input_var.get()
description = self.description_entry.get().strip()
deaddate = self.deaddate_calendar.get_date().strftime("%Y-%m-%d")
reminder = self.reminder_var.get()
if not task_name:
show_error(self.root, "任务名称不能为空!")
return
new_task = {
"name": task_name,
"priority": priority,
"status": False,
"description": description,
"deaddate": deaddate,
"reminder": reminder,
"created": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
# 添加任务到列表
tasks.append(new_task)
self.tasks_save()
# 刷新列表并清空输入框
self.update_list()
self.clear_inputs()
# 显示成功提示
messagebox.showinfo("成功", f"任务 '{task_name}' 已添加")
# 清空输入框
def clear_inputs(self):
self.name_entry.delete(0, tk.END)
self.description_entry.delete(0, tk.END)
self.deaddate_calendar.set_date(datetime.now())
self.reminder_var.set("不提醒")
self.priority_input_var.set("中") # 优先级选择重置
# 删除选中任务
def delete_task(self):
selected_items = self.tree.selection()
if not selected_items:
show_error(self.root, "请选择要删除的任务!")
return
if len(selected_items) == 1:
task_id = self.tree.item(selected_items[0], "values")[0]
task_name = self.tree.item(selected_items[0], "values")[1]
confirm_msg = f"确定要删除任务 '{task_name}' (ID: {task_id}) 吗?"
else:
confirm_msg = f"确定要删除选中的 {len(selected_items)} 个任务吗?"
if messagebox.askyesno("确认删除", confirm_msg):
# 为了避免索引混乱,按表格索引反向删除
for item in reversed(selected_items):
task_index = self.tree.index(item)
tasks.pop(task_index)
self.tasks_save()
self.update_list()
# 编辑选中任务
def edit_task(self):
selected_items = self.tree.selection()
if len(selected_items) != 1:
show_error(self.root, "请选择一条任务进行编辑!")
return
selected_item = selected_items[0]
task_index = self.tree.index(selected_item)
task = tasks[task_index]
self.edit_window = tk.Toplevel(self.root)
self.edit_window.title("编辑任务")
# 设置窗口居中
window_width = 450
window_height = 500
screen_width = self.edit_window.winfo_screenwidth()
screen_height = self.edit_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.edit_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.edit_window.resizable(width=False, height=False)
# 创建标题标签控件
show_title = tk.Label(self.edit_window, text=">>>编辑任务<<<", bg = "white", fg = "black", font = ("宋体", 18), bd = '0', anchor = 'center')
show_title.place(x = 50, y = 30, width = 350, height = 50)
# 任务名称
ttk.Label(self.edit_window, text="任务名称:").place(x = 75, y = 120, anchor = 'nw')
name_edit = ttk.Entry(self.edit_window, width=30)
name_edit.insert(0, task["name"])
name_edit.place(x = 150, y = 120, anchor = 'nw')
# 优先级
ttk.Label(self.edit_window, text="优先级:").place(x = 75, y = 170, anchor = 'nw')
priority_edit = ttk.Combobox(self.edit_window, values=["高", "中", "低"], state="readonly")
priority_edit.set(task["priority"])
priority_edit.place(x = 150, y = 170, anchor = 'nw')
# 状态
ttk.Label(self.edit_window, text="状态:").place(x = 75, y = 220, anchor = 'nw')
status_edit = ttk.Combobox(self.edit_window, values=["已完成", "未完成"], state="readonly")
status_edit.set("已完成" if task["status"] else "未完成")
status_edit.place(x = 150, y = 220, anchor = 'nw')
# 描述
ttk.Label(self.edit_window, text="描述:").place(x = 75, y = 270, anchor = 'nw')
describe_edit = ttk.Entry(self.edit_window, width=30)
describe_edit.insert(0, task["description"])
describe_edit.place(x = 150, y = 270, anchor = 'nw')
# 截止日期(日历选择)
ttk.Label(self.edit_window, text="截止日期:").place(x = 75, y = 320, anchor = 'nw')
deaddate_edit = DateEntry(self.edit_window, date_pattern="yyyy-mm-dd", locale='zh_CN')
deaddate_edit.set_date(datetime.strptime(task["deaddate"], "%Y-%m-%d"))
deaddate_edit.place(x = 150, y = 320, anchor = 'nw')
# 提醒设置
ttk.Label(self.edit_window, text="提醒设置:").place(x = 75, y = 370, anchor = 'nw')
reminder_edit = ttk.Combobox(self.edit_window,
values=["不提醒", "提前5分钟", "提前15分钟", "提前30分钟", "提前1小时", "提前1天"],
state="readonly")
reminder_edit.set(task["reminder"])
reminder_edit.place(x = 150, y = 370, anchor = 'nw')
# 保存编辑
def save_edit():
name = name_edit.get().strip()
if not name:
show_error(self.root, "任务名称不能为空!")
return
task["name"] = name
task["priority"] = priority_edit.get()
task["status"] = (status_edit.get() == "已完成")
task["description"] = describe_edit.get().strip()
task["deaddate"] = deaddate_edit.get_date().strftime("%Y-%m-%d")
task["reminder"] = reminder_edit.get()
self.tasks_save()
self.update_list()
self.edit_window.destroy()
ttk.Button(self.edit_window, text="保存", command=save_edit).place(x = 90, y = 430, anchor = 'nw')
ttk.Button(self.edit_window, text="取消", command=self.edit_window.destroy).place(x = 260, y = 430, anchor = 'nw')
# 关于程序页面
def app_about(self):
about = tk.Tk()
about.title('关于程序')
# 设置窗口居中
window_width = 400
window_height = 380
screen_width = about.winfo_screenwidth()
screen_height = about.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
about.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
about.resizable(width=False, height=False)
about_frame = tk.Frame(about, width=490, height=520)
about_frame.pack()
tk.Label(about_frame, text='待办事项管理器', font=("宋体", 16)).place(x=120, y=20)
tk.Label(about_frame, text='使用编程语言:Python', font=("宋体", 14)).place(x=50, y=70)
tk.Label(about_frame, text='保存数据方式:保存为JSON文件', font=("宋体", 14)).place(x=50, y=120)
tk.Label(about_frame, text='JSON文件名:data.json', font=("宋体", 14)).place(x=50, y=170)
tk.Label(about_frame, text='修改任务:在任务列表直接双击鼠标', font=("宋体", 14)).place(x=50, y=220)
tk.Label(about_frame, text='删除任务:在任务列表右击鼠标', font=("宋体", 14)).place(x=50, y=270)
tk.Label(about_frame, text='创作者:www.pyhint.com', font=("宋体", 14)).place(x=50, y=320)
about.mainloop()
# 程序讲解页面
def help_window(self):
webbrowser.open("https://www.pyhint.com/article/159.html")
def run(self):
self.root.mainloop()
# 当前模块直接被执行
if __name__ == "__main__":
root = tk.Tk()
app = TaskApp(root)
app.run()