项目简介
本文将详细讲解如何使用Python的wxPython GUI框架开发一个功能完整的日历记事本应用。该应用支持选择年月、记录每日待办事项、美观预览、背景自定义以及PDF导出等功能。
特别说明:本教程使用自绘日历方式,完全不依赖 wx.calendar 模块,避免了安装问题,更加灵活可控。
技术栈
- wxPython: 跨平台GUI框架,用于构建用户界面
- ReportLab: PDF生成库
- PIL (Pillow): 图像处理库
- Python标准库: calendar、json、datetime等
一、项目架构设计
1.1 核心类结构
项目包含两个主要类:
CalendarDiary (主窗口类)
├── 数据管理 (JSON读写)
├── UI界面构建
├── 自绘日历实现
├── 事件处理
└── PDF导出功能
PreviewFrame (预览窗口类)
├── 日历图像生成
└── 可视化展示
1.2 数据存储设计
使用JSON格式存储数据,结构如下:
{
"2025-10-01": {
"morning": "晨跑 30分钟",
"noon": "团队会议",
"evening": "学习Python"
},
"2025-10-02": {
"morning": "",
"noon": "午餐约会",
"evening": "看电影"
}
}
二、主窗口类详解
2.1 初始化方法
def __init__(self):
super().__init__(None, title="美观日历记事本", size=(1200, 800))
self.data_file = "diary_data.json"
self.diary_data = self.load_data()
self.background_image = None
# 初始化日期
today = datetime.now()
self.current_year = today.year
self.current_month = today.month
self.selected_date = None
self.init_ui()
self.Centre()
关键点:
- 调用父类构造函数创建窗口框架
- 定义数据文件路径
- 加载历史数据
- 初始化当前年月和选中日期
- 构建UI并居中显示
2.2 UI界面构建
2.2.1 布局管理器
wxPython使用Sizer进行布局管理,主要类型:
- BoxSizer: 水平或垂直排列控件
- GridSizer: 网格布局
- FlexGridSizer: 灵活网格布局
本项目使用BoxSizer的嵌套结构:
main_sizer = wx.BoxSizer(wx.VERTICAL) # 主垂直布局
├── toolbar_sizer (wx.HORIZONTAL) # 顶部工具栏
├── content_sizer (wx.HORIZONTAL) # 主内容区
├── left_panel (自绘日历)
└── right_panel (记事区域)
2.2.2 工具栏设计
toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL)
# 年份选择
self.year_choice = wx.Choice(panel, choices=[str(y) for y in range(2020, 2031)])
self.year_choice.SetSelection(self.current_year - 2020)
self.year_choice.Bind(wx.EVT_CHOICE, self.on_year_month_change)
# 月份选择
self.month_choice = wx.Choice(panel, choices=[f"{m}月" for m in range(1, 13)])
self.month_choice.SetSelection(self.current_month - 1)
self.month_choice.Bind(wx.EVT_CHOICE, self.on_year_month_change)
wx.Choice控件特点:
- 下拉选择框,占用空间小
SetSelection()设置默认选中项(索引从0开始)GetStringSelection()获取当前选中的文本Bind(wx.EVT_CHOICE, handler)绑定选择变化事件
三、自绘日历实现(核心技术)
3.1 创建日历面板
# 创建自定义日历
self.calendar_panel = wx.Panel(left_panel, size=(400, 400))
self.calendar_panel.SetBackgroundColour(wx.Colour(255, 255, 255))
self.calendar_panel.Bind(wx.EVT_PAINT, self.on_paint_calendar)
self.calendar_panel.Bind(wx.EVT_LEFT_DOWN, self.on_calendar_click)
关键点:
- 使用
wx.Panel作为画布 - 绑定
wx.EVT_PAINT事件进行绘制 - 绑定
wx.EVT_LEFT_DOWN处理点击事件 - 设置白色背景色
3.2 绘制日历(核心算法)
def on_paint_calendar(self, event):
dc = wx.PaintDC(self.calendar_panel)
dc.Clear()
width, height = self.calendar_panel.GetSize()
# 1. 绘制标题
dc.SetFont(wx.Font(16, wx.FONTFAMILY_DEFAULT,
wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))
title = f"{self.current_year}年{self.current_month}月"
tw, th = dc.GetTextExtent

最低0.47元/天 解锁文章
638

被折叠的 条评论
为什么被折叠?



