使用Python和wxPython创建动态HTML日历生成器

在这个数字化时代,日历仍然是我们日常生活中不可或缺的工具。今天,我们将探讨如何使用Python创建一个动态HTML日历生成器。这个项目不仅实用,还能帮助我们深入理解Python编程、GUI开发和网页生成的相关知识。

项目概述

我们的目标是创建一个应用程序,允许用户选择特定的年份和月份,然后生成并显示一个美观的HTML日历。这个日历不仅显示日期,还会包含中国的主要节假日信息。
C:\pythoncode\new\calendarHTML.py
C:\pythoncode\new\calendar_template.html

主要特性包括:

  1. 使用wxPython创建图形用户界面
  2. 动态生成HTML日历
  3. 从XML文件加载节假日信息
  4. 使用内嵌浏览器组件显示生成的HTML

技术栈

  • Python 3.x
  • wxPython: 用于创建图形用户界面
  • Jinja2: 用于HTML模板渲染
  • xml.etree.ElementTree: 用于解析XML文件
  • calendar和datetime模块: 用于日期处理

实现步骤

全部代码:

import wx
import wx.html2
import calendar
import datetime
import xml.etree.ElementTree as ET
from jinja2 import Template

class CalendarFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Calendar Generator')
        panel = wx.Panel(self)

        self.year_ctrl = wx.SpinCtrl(panel, min=1900, max=2100, initial=datetime.datetime.now().year)
        self.month_ctrl = wx.Choice(panel, choices=[calendar.month_name[i] for i in range(1, 13)])
        self.month_ctrl.SetSelection(datetime.datetime.now().month - 1)

        generate_btn = wx.Button(panel, label='Generate Calendar')
        generate_btn.Bind(wx.EVT_BUTTON, self.on_generate)

        self.browser = wx.html2.WebView.New(panel)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(wx.StaticText(panel, label="Select Year and Month:"))
        sizer.Add(self.year_ctrl, 0, wx.ALL | wx.EXPAND, 5)
        sizer.Add(self.month_ctrl, 0, wx.ALL | wx.EXPAND, 5)
        sizer.Add(generate_btn, 0, wx.ALL | wx.EXPAND, 5)
        sizer.Add(self.browser, 1, wx.ALL | wx.EXPAND, 5)

        panel.SetSizer(sizer)
        self.SetSize((800, 600))

    def on_generate(self, event):
        year = self.year_ctrl.GetValue()
        month = self.month_ctrl.GetSelection() + 1
        html_content = self.generate_calendar_html(year, month)
        self.browser.SetPage(html_content, "")

    def generate_calendar_html(self, year, month):
        # Load holidays from XML
        holidays = self.load_holidays_from_xml()

        # Generate calendar data
        cal = calendar.monthcalendar(year, month)
        month_name = calendar.month_name[month]

        # Prepare holiday data for the template
        holiday_data = {}
        for date, holiday in holidays.items():
            holiday_date = datetime.datetime.strptime(date, "%Y-%m-%d")
            if holiday_date.year == year and holiday_date.month == month:
                holiday_data[holiday_date.day] = holiday

        # Load and render the HTML template
        with open('calendar_template.html', 'r', encoding='utf-8') as file:
            template = Template(file.read())

        return template.render(
            year=year,
            month=month_name,
            calendar_data=cal,
            holidays=holiday_data
        )

    def load_holidays_from_xml(self):
        holidays = {}
        tree = ET.parse('holidays.xml')
        root = tree.getroot()
        for holiday in root.findall('holiday'):
            date = holiday.find('date').text
            name = holiday.find('name').text
            description = holiday.find('description').text
            holidays[date] = {'name': name, 'description': description}
        return holidays

if __name__ == '__main__':
    app = wx.App()
    frame = CalendarFrame()
    frame.Show()
    app.MainLoop()

1. 创建图形用户界面

首先,我们使用wxPython创建了一个简单的GUI,包含年份选择器、月份下拉列表、生成按钮和一个用于显示HTML的内嵌浏览器组件。

class CalendarFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Calendar Generator')
        panel = wx.Panel(self)

        self.year_ctrl = wx.SpinCtrl(panel, min=1900, max=2100, initial=datetime.datetime.now().year)
        self.month_ctrl = wx.Choice(panel, choices=[calendar.month_name[i] for i in range(1, 13)])
        self.month_ctrl.SetSelection(datetime.datetime.now().month - 1)

        generate_btn = wx.Button(panel, label='Generate Calendar')
        generate_btn.Bind(wx.EVT_BUTTON, self.on_generate)

        self.browser = wx.html2.WebView.New(panel)

        # 设置布局...

2. 生成HTML日历

核心功能是根据用户选择的年份和月份生成HTML日历。我们使用Python的calendar模块来获取日历数据,然后使用Jinja2模板引擎渲染HTML。

def generate_calendar_html(self, year, month):
    # 加载节假日信息
    holidays = self.load_holidays_from_xml()

    # 生成日历数据
    cal = calendar.monthcalendar(year, month)
    month_name = calendar.month_name[month]

    # 准备节假日数据
    holiday_data = {}
    for date, holiday in holidays.items():
        holiday_date = datetime.datetime.strptime(date, "%Y-%m-%d")
        if holiday_date.year == year and holiday_date.month == month:
            holiday_data[holiday_date.day] = holiday

    # 加载并渲染HTML模板
    with open('calendar_template.html', 'r', encoding='utf-8') as file:
        template = Template(file.read())

    return template.render(
        year=year,
        month=month_name,
        calendar_data=cal,
        holidays=holiday_data
    )

3. HTML模板设计

我们设计了一个美观的HTML模板,使用CSS来样式化日历。模板包含一个标题区域显示年份和月份,以及一个表格来显示日期和节假日信息。

DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ month }} {{ year }} 日历title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f0f0f0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
        }
        .calendar {
            background-color: white;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
            overflow: hidden;
            width: 90%;
            max-width: 800px;
        }
        .header {
            background-color: #4CAF50;
            color: white;
            text-align: center;
            padding: 20px;
        }
        .month-year {
            font-size: 24px;
            font-weight: bold;
        }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            border: 1px solid #ddd;
            text-align: center;
            padding: 10px;
        }
        th {
            background-color: #f2f2f2;
        }
        .holiday {
            background-color: #ffebee;
            cursor: pointer;
        }
        .holiday-name {
            font-weight: bold;
            color: #d32f2f;
        }
        .holiday-description {
            font-size: 12px;
            color: #757575;
        }
    style>
head>
<body>
    <div class="calendar">
        <div class="header">
            <div class="month-year">{{ month }} {{ year }}div>
            <img src="https://via.placeholder.com/800x200" alt="月份图片" style="width: 100%; margin-top: 10px;">
        div>
        <table>
            <tr>
                <th>周日th>
                <th>周一th>
                <th>周二th>
                <th>周三th>
                <th>周四th>
                <th>周五th>
                <th>周六th>
            tr>
            {% for week in calendar_data %}
                <tr>
                    {% for day in week %}
                        {% if day != 0 %}
                            {% set date_string = '%d-%02d-%02d'|format(year, loop.index, day) %}
                            {% if date_string in holidays %}
                                <td class="holiday" title="{{ holidays[date_string]['description'] }}">
                                    {{ day }}
                                    <div class="holiday-name">{{ holidays[date_string]['name'] }}div>
                                    <div class="holiday-description">{{ holidays[date_string]['description'] }}div>
                                td>
                            {% else %}
                                <td>{{ day }}td>
                            {% endif %}
                        {% else %}
                            <td>td>
                        {% endif %}
                    {% endfor %}
                tr>
            {% endfor %}
        table>
    div>
body>
html>

4. 加载节假日信息

我们使用XML文件来存储节假日信息,并使用Python的xml.etree.ElementTree模块来解析它。
C:\pythoncode\new\holidays.xml


<holidays>
    <holiday>
        <date>2024-01-01date>
        <name>元旦name>
        <description>新年的第一天,象征着新的开始description>
    holiday>
    <holiday>
        <date>2024-02-10date>
        <name>春节name>
        <description>中国最重要的传统节日,家人团聚的日子description>
    holiday>
    <holiday>
        <date>2024-04-04date>
        <name>清明节name>
        <description>缅怀先人,踏青郊游的节日description>
    holiday>
    <holiday>
        <date>2024-05-01date>
        <name>劳动节name>
        <description>庆祝劳动者的节日description>
    holiday>
    <holiday>
        <date>2024-06-10date>
        <name>端午节name>
        <description>赛龙舟,吃粽子的传统节日description>
    holiday>
    <holiday>
        <date>2024-09-17date>
        <name>中秋节name>
        <description>家人团聚,赏月吃月饼的节日description>
    holiday>
    <holiday>
        <date>2024-10-01date>
        <name>国庆节name>
        <description>庆祝中华人民共和国成立description>
    holiday>
holidays>

def load_holidays_from_xml(self):
    holidays = {}
    tree = ET.parse('holidays.xml')
    root = tree.getroot()
    for holiday in root.findall('holiday'):
        date = holiday.find('date').text
        name = holiday.find('name').text
        description = holiday.find('description').text
        holidays[date] = {'name': name, 'description': description}
    return holidays

遇到的挑战和解决方案

在开发过程中,我们遇到了一个与Jinja2模板渲染相关的错误。错误信息表明在模板中使用了loop.parent,但在某些情况下它可能不存在。

解决方案是修改HTML模板中的日期处理逻辑:

{% set date_string = '%d-%02d-%02d'|format(year, loop.index, day) %}

我们移除了loop.parent.loop.index,改为直接使用loop.index。这是因为在这个上下文中,loop.index已经给出了正确的月份数字。

同时,我们也优化了Python脚本中的generate_calendar_html方法,预处理节假日数据,只传递当前月份的节假日信息给模板,简化了模板中的日期处理逻辑。

结果:

使用Python和wxPython创建动态HTML日历生成器_第1张图片

结论

通过这个项目,我们不仅创建了一个实用的日历生成器,还学习了如何结合使用多个Python库来创建复杂的应用程序。我们探索了GUI编程、HTML生成、模板渲染和XML解析等多个方面的知识。

这个项目还有很多可以扩展的地方。例如,我们可以添加更多的自定义选项,允许用户选择不同的主题或颜色方案。我们也可以增加导出功能,让用户可以将生成的日历保存为PDF或图片文件。

编程是一个不断学习和改进的过程。通过解决实际问题和克服挑战,我们不仅提高了编程技能,还培养了解决问题的能力。希望这个项目能够激发你的创意,鼓励你尝试开发自己的有趣应用程序!

你可能感兴趣的:(python,html,xml,带照片和节假日信息的日历)