ToDoList

ToDoList

Intro

基于python的构建的简易ToDoList桌面应用,便于提醒和管理你的任务。

Show

在这里插入图片描述

在这里插入图片描述

Functions

  • Add Task
    可以直接在日期旁的输入框写入你想添加的任务和任务截止日期,任务信息会持久化在一个json文件中。

  • Remove Task
    点击你想删除的任务,再点击remove task即可删除。

  • Save Edit
    双击任务,可以修改内容或日期,再点击save edit即可保存修改。

  • Pending
    完成状态,目前来看好像没什么用,因为一般完成任务后直接remove了。

  • Search
    支持模糊搜索

  • Show All
    展示所有任务,用于配合搜索后,返回原来的任务列表。但是给搜索内容删除后,在点击search也可以直接返回。

  • Others

    • 点击Deadline可以按照截止时间排序

    • 支持开机自启,可能会有点慢,而且还会弹出命令行和记事本

Requirements

  • python3
  • Windows

Start

你需要把start_todo.bat文件放在下面目录中(文件代码在下面)

C:\Users\your_username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

修改start_todo.bat启动脚本

@echo off
cd D:\your_file  //MyToDo.py的文件位置 
pythonw "D:\your_file\MyToDo.py"

重启电脑或直接在命令行输入上面命令即可启动。

Extra

如果你有任何想法和修改建议可以联系我!

代码

MyToDo.py

import customtkinter as ctk
from tkcalendar import DateEntry
from tkinter import ttk, font
import json
import os
from datetime import datetime
from PIL import Image, ImageDraw
import pystray
import threading

# 初始化 CustomTkinter 应用
ctk.set_appearance_mode("System")
ctk.set_default_color_theme("blue")

# 使用绝对路径保存文件
DATA_FILE = os.path.join(os.path.expanduser("~"), "todo_data.json")

# 全部任务数据
all_tasks = []

# 添加任务
def add_task():
    task = entry_task.get()
    deadline = date_entry.get_date().strftime('%Y-%m-%d')
    status = status_var.get()
    if task and deadline:
        tree.insert("", "end", values=(task, deadline, status))
        entry_task.delete(0, "end")
        date_entry.set_date(datetime.today())
        status_var.set("Pending")
        save_tasks()

# 双击表格中的行进行编辑
def on_item_double_click(event):
    selected_item = tree.selection()[0]
    task_values = tree.item(selected_item, 'values')
    
    entry_task.delete(0, "end")
    entry_task.insert(0, task_values[0])
    
    date_entry.set_date(datetime.strptime(task_values[1], '%Y-%m-%d'))
    status_var.set(task_values[2])
    
    app.selected_item = selected_item

# 保存编辑后的任务
def save_edit():
    if hasattr(app, 'selected_item'):
        selected_item = app.selected_item
        task = entry_task.get()
        deadline = date_entry.get_date().strftime('%Y-%m-%d')
        status = status_var.get()
        if task and deadline:
            tree.item(selected_item, values=(task, deadline, status))
            entry_task.delete(0, "end")
            date_entry.set_date(datetime.today())
            status_var.set("Pending")
            save_tasks()
            del app.selected_item

# 删除任务
def remove_task():
    selected_items = tree.selection()
    if selected_items:
        for item in selected_items:
            tree.delete(item)
        save_tasks()

# 模糊搜索任务
def search_tasks():
    query = entry_search.get().lower()
    for row in tree.get_children():
        tree.delete(row)
    for task in all_tasks:
        if query in task[0].lower():
            tree.insert("", "end", values=task)

# 显示所有任务
def show_all_tasks():
    for row in tree.get_children():
        tree.delete(row)
    for task in all_tasks:
        tree.insert("", "end", values=task)

# 按截止日期排序
def sort_by_deadline():
    tasks = [(tree.item(item)['values'][0], tree.item(item)['values'][1], tree.item(item)['values'][2]) for item in tree.get_children()]
    sorted_tasks = sorted(tasks, key=lambda x: datetime.strptime(x[1], '%Y-%m-%d'))
    for row in tree.get_children():
        tree.delete(row)
    for task in sorted_tasks:
        tree.insert("", "end", values=task)

# 保存任务列表到文件
def save_tasks():
    global all_tasks
    all_tasks = []
    for item in tree.get_children():
        all_tasks.append(tree.item(item, 'values'))
    with open(DATA_FILE, "w") as f:
        json.dump(all_tasks, f)

# 加载任务列表
def load_tasks():
    global all_tasks
    all_tasks = []
    if os.path.exists(DATA_FILE):
        with open(DATA_FILE, "r") as f:
            all_tasks = json.load(f)
            for task in all_tasks:
                tree.insert("", "end", values=task)

# 最小化到托盘
def minimize_to_tray():
    app.withdraw()  # 隐藏窗口
    show_tray_icon()

def show_tray_icon():
    # 创建托盘图标
    def on_quit(icon, item):
        icon.stop()
        app.quit()

    def on_show_window(icon, item):
        app.deiconify()  # 显示窗口
        icon.stop()

    # 创建一个简单的图标
    image = Image.new('RGB', (64, 64), color=(73, 109, 137))
    draw = ImageDraw.Draw(image)
    draw.rectangle((10, 10, 54, 54), fill="white")

    # 创建托盘图标和菜单
    icon = pystray.Icon("ToDoApp", image, menu=pystray.Menu(
        pystray.MenuItem('Show', on_show_window),
        pystray.MenuItem('Quit', on_quit)
    ))
    icon.run()

# 创建主窗口
app = ctk.CTk()
app.title("CliPg ToDo List")

# 获取屏幕宽高
screen_width = app.winfo_screenwidth()
screen_height = app.winfo_screenheight()

# 窗口尺寸设置
window_width = 470
window_height = 400

# 计算窗口位置,使其出现在右下角
position_right = screen_width +130
position_bottom = screen_height - 175

app.geometry(f"{window_width}x{window_height}+{position_right}+{position_bottom}")

# 输入框和按钮区域
frame_input = ctk.CTkFrame(app)
frame_input.pack(pady=10, padx=10, fill="x")

entry_task = ctk.CTkEntry(frame_input, placeholder_text="Enter your task here", width=180)
entry_task.grid(row=0, column=0, padx=5)

date_entry = DateEntry(frame_input, width=12, background="darkblue", foreground="white", borderwidth=2)
date_entry.grid(row=0, column=1, padx=5)

status_var = ctk.StringVar(value="Pending")
status_menu = ctk.CTkOptionMenu(frame_input, values=["Pending", "Completed"], variable=status_var, width=80)
status_menu.grid(row=0, column=2, padx=5)

add_button = ctk.CTkButton(frame_input, text="Add Task", command=add_task, width=70)
add_button.grid(row=0, column=3, padx=5)

save_edit_button = ctk.CTkButton(frame_input, text="Save Edit", command=save_edit, width=70)
save_edit_button.grid(row=0, column=4, padx=5)



# 搜索框和按钮区域
frame_search = ctk.CTkFrame(app)
frame_search.pack(pady=10, padx=10, fill="x")

entry_search = ctk.CTkEntry(frame_search, placeholder_text="Search tasks...", width=180)
entry_search.grid(row=0, column=0, padx=5)

search_button = ctk.CTkButton(frame_search, text="Search", command=search_tasks, width=70)
search_button.grid(row=0, column=1, padx=5)

show_all_button = ctk.CTkButton(frame_search, text="Show All", command=show_all_tasks, width=70)
show_all_button.grid(row=0, column=2, padx=5)

remove_button = ctk.CTkButton(frame_search, text="Remove Task", command=remove_task, width=70)
remove_button.grid(row=0, column=3, padx=5)

# 创建任务表格
columns = ("Task", "Deadline", "Status")
tree = ttk.Treeview(app, columns=columns, show="headings", height=10)
tree.heading("Task", text="Task")
tree.heading("Deadline", text="Deadline", command=sort_by_deadline)
tree.heading("Status", text="Status")

tree.column("Task", anchor="w", width=250)
tree.column("Deadline", anchor="center", width=100)
tree.column("Status", anchor="center", width=80)

style = ttk.Style()
style.configure("Treeview", font=("Helvetica", 14))
style.configure("Treeview.Heading", font=("Helvetica", 14, "bold"))

tree.pack(pady=10, padx=10, fill="both", expand=True)

# 双击事件绑定
tree.bind("<Double-1>", on_item_double_click)

# 加载保存的任务
load_tasks()

# 窗口关闭时最小化到托盘
app.protocol("WM_DELETE_WINDOW", minimize_to_tray)

# 启动应用
app.mainloop()

start_todo.bat

@echo off
cd D:\cs_study\AI\projects\
pythonw "D:\cs_study\AI\projects\MyToDo.py"
### 实现 Todolist 功能的核心概念 要实现一个前端 Todolist 应用程序,通常会涉及以下几个核心部分: #### 1. **HTML 结构** 定义页面的基本结构,包括输入框、提交按钮以及用于显示待办事项的容器。 ```html <div id="app"> <input type="text" id="taskInput" placeholder="请输入任务..." /> <button onclick="addTask()">添加</button> <ul id="todoList"></ul> </div> ``` 此 HTML 部分提供了用户界面的基础框架[^1]。 --- #### 2. **CSS 样式** 为了提升用户体验,可以通过 CSS 对页面进行美化。例如设置字体大小、颜色和布局等属性。 ```css body { font-family: Arial, sans-serif; } #app { width: 300px; margin: auto; text-align: center; } #taskInput { padding: 8px; width: 70%; } ``` 上述样式使得应用更加美观易用[^2]。 --- #### 3. **JavaScript 或其他库/框架逻辑** ##### 使用纯 JavaScript 实现基础功能 以下是基于原生 JavaScript 的代码片段,展示了如何动态更新 DOM 并保存数据至浏览器本地存储中。 ```javascript function addTask() { const taskText = document.getElementById('taskInput').value.trim(); if (taskText === '') return; const todoList = JSON.parse(localStorage.getItem('todolist')) || []; todoList.push(taskText); localStorage.setItem('todolist', JSON.stringify(todoList)); renderTasks(); } function renderTasks() { const tasks = JSON.parse(localStorage.getItem('todolist')) || []; const ulElement = document.getElementById('todoList'); ulElement.innerHTML = ''; tasks.forEach((task) => { const li = document.createElement('li'); li.textContent = task; ulElement.appendChild(li); }); } window.onload = () => renderTasks(); // 页面加载时渲染已有任务 ``` 这段脚本实现了简单的增删操作并利用 `localStorage` 存储数据以便刷新后仍能保留[^3]。 --- ##### 利用 jQuery 提升开发效率 如果倾向于更简洁的方式,则可考虑引入 jQuery 来简化 DOM 操作流程。 ```javascript $(document).ready(() => { $('#submitBtn').click(() => { let inputValue = $('#taskInput').val().trim(); if (!inputValue.length) return; $.ajax({ url: '/save-task', method: 'POST', data: { content: inputValue }, success: function(response) { loadTodosFromStorage(); } }); $('#taskInput').val(''); }); function loadTodosFromStorage() { try { const storedData = JSON.parse(localStorage.getItem('todos')); if (Array.isArray(storedData)) { $('#todoList').empty(); $(storedData).each((index, item) => { $('#todoList').append(`<li>${item}</li>`); }); } } catch(e){ console.error("Error loading todos:", e.message); } } loadTodosFromStorage(); }); ``` 这里不仅演示了事件绑定方法的不同之处,同时也加入了 AJAX 请求模拟后台交互过程[^4]。 --- #### 4. **高级特性扩展** 随着需求复杂度增加,还可以加入更多实用的功能模块,比如时间戳标记、状态切换(已完成 / 待完成)、拖拽排序等功能支持。 --- ### 总结 无论是采用 React 这类现代框架还是传统方式构建 Todo List ,都需要围绕着 UI 渲染机制展开设计思考 。 同时也要注意性能优化方面的问题,在大规模项目里尤其重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值