鱼C论坛

 找回密码
 立即注册
查看: 101|回复: 6

pyqt6 的日期教学

[复制链接]
发表于 2025-8-6 16:13:48 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
@FishC
  1. import sys
  2. from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
  3.                             QLabel, QCalendarWidget, QPushButton, QToolButton)
  4. from PyQt6.QtCore import Qt, QDate, QSize
  5. from PyQt6.QtGui import (QColor, QTextCharFormat, QFont, QPainter,
  6.                         QPalette, QPen, QBrush, QIcon, QPixmap)

  7. class RoundCellCalendar(QCalendarWidget):
  8.     def __init__(self, parent=None):
  9.         super().__init__(parent)
  10.         self.setStyleSheet("""
  11.             QCalendarWidget {
  12.                 border: 2px solid #e0e0e0;
  13.                 border-radius: 15px;
  14.                 padding: 5px;
  15.                 background: white;
  16.             }
  17.             /* 导航按钮容器 */
  18.             QCalendarWidget QWidget#qt_calendar_navigationbar {
  19.                 background: #f5f5f5;
  20.                 border-top-left-radius: 13px;
  21.                 border-top-right-radius: 13px;
  22.                 padding: 5px;
  23.             }
  24.             /* 月份年份标签 */
  25.             QCalendarWidget QToolButton#qt_calendar_monthbutton {
  26.                 font-size: 14px;
  27.                 font-weight: bold;
  28.                 color: #444444;
  29.                 padding: 5px 10px;
  30.                 border: none;
  31.             }
  32.             /* 年份选择框 */
  33.             QCalendarWidget QSpinBox {
  34.                 width: 80px;
  35.                 font-size: 14px;
  36.                 border-radius: 5px;
  37.                 padding: 2px;
  38.                 border: 1px solid #d0d0d0;
  39.             }
  40.             /* 月份选择菜单 */
  41.             QCalendarWidget QMenu {
  42.                 background: white;
  43.                 border-radius: 10px;
  44.                 padding: 5px;
  45.                 border: 1px solid #d0d0d0;
  46.             }
  47.             /* 选中日期的默认样式覆盖 */
  48.             QCalendarWidget QAbstractItemView:enabled {
  49.                 selection-background-color: transparent;
  50.                 selection-color: #333333;
  51.             }
  52.         """)
  53.         
  54.         # 自定义导航按钮样式
  55.         self.setup_navigation_buttons()
  56.         
  57.         # 初始化日期格式
  58.         self.init_date_formats()
  59.    
  60.     def setup_navigation_buttons(self):
  61.         # 获取导航栏中的按钮
  62.         prev_btn = self.findChild(QToolButton, "qt_calendar_prevmonth")
  63.         next_btn = self.findChild(QToolButton, "qt_calendar_nextmonth")
  64.         
  65.         if prev_btn and next_btn:
  66.             # 设置按钮样式
  67.             button_style = """
  68.                 QToolButton {
  69.                     background: #f0f0f0;
  70.                     border-radius: 12px;
  71.                     border: 1px solid #d0d0d0;
  72.                     width: 24px;
  73.                     height: 24px;
  74.                 }
  75.                 QToolButton:hover {
  76.                     background: #e0e0e0;
  77.                 }
  78.                 QToolButton:pressed {
  79.                     background: #d0d0d0;
  80.                 }
  81.             """
  82.             prev_btn.setStyleSheet(button_style)
  83.             next_btn.setStyleSheet(button_style)
  84.             
  85.             # 创建并设置自定义箭头图标
  86.             arrow_size = QSize(16, 16)
  87.             
  88.             # 左箭头图标
  89.             prev_icon = QIcon()
  90.             prev_pixmap = QPixmap(arrow_size)
  91.             prev_pixmap.fill(Qt.GlobalColor.transparent)
  92.             painter = QPainter(prev_pixmap)
  93.             painter.setRenderHint(QPainter.RenderHint.Antialiasing)
  94.             painter.setPen(QPen(QColor(80, 80, 80), 2))
  95.             painter.drawLine(12, 8, 4, 8)
  96.             painter.drawLine(5, 8, 9, 4)
  97.             painter.drawLine(5, 8, 9, 12)
  98.             painter.end()
  99.             prev_icon.addPixmap(prev_pixmap)
  100.             prev_btn.setIcon(prev_icon)
  101.             prev_btn.setIconSize(arrow_size)
  102.             
  103.             # 右箭头图标
  104.             next_icon = QIcon()
  105.             next_pixmap = QPixmap(arrow_size)
  106.             next_pixmap.fill(Qt.GlobalColor.transparent)
  107.             painter = QPainter(next_pixmap)
  108.             painter.setRenderHint(QPainter.RenderHint.Antialiasing)
  109.             painter.setPen(QPen(QColor(80, 80, 80), 2))
  110.             painter.drawLine(4, 8, 12, 8)
  111.             painter.drawLine(11, 8, 7, 4)
  112.             painter.drawLine(11, 8, 7, 12)
  113.             painter.end()
  114.             next_icon.addPixmap(next_pixmap)
  115.             next_btn.setIcon(next_icon)
  116.             next_btn.setIconSize(arrow_size)
  117.         
  118.     def init_date_formats(self):
  119.         # 今天的样式 (绿色圆角)
  120.         today_fmt = QTextCharFormat()
  121.         today_fmt.setBackground(QColor(230, 245, 230))  # 浅绿色背景
  122.         today_fmt.setForeground(QColor(0, 100, 0))      # 深绿色文字
  123.         today_fmt.setFont(QFont("Arial", 10, QFont.Weight.Bold))
  124.         self.setDateTextFormat(QDate.currentDate(), today_fmt)
  125.         
  126.         # 周末的样式 (柔和的红色)
  127.         weekend_fmt = QTextCharFormat()
  128.         weekend_fmt.setForeground(QColor(220, 50, 50))  # 柔和的红色
  129.         
  130.         # 工作日的样式 (深灰色)
  131.         weekday_fmt = QTextCharFormat()
  132.         weekday_fmt.setForeground(QColor(60, 60, 60))   # 深灰色文字
  133.         
  134.         # 设置周末和工作日样式
  135.         self.setWeekdayTextFormat(Qt.DayOfWeek.Saturday, weekend_fmt)
  136.         self.setWeekdayTextFormat(Qt.DayOfWeek.Sunday, weekend_fmt)
  137.         
  138.         for day in [Qt.DayOfWeek.Monday, Qt.DayOfWeek.Tuesday,
  139.                    Qt.DayOfWeek.Wednesday, Qt.DayOfWeek.Thursday,
  140.                    Qt.DayOfWeek.Friday]:
  141.             self.setWeekdayTextFormat(day, weekday_fmt)
  142.    
  143.     def paintCell(self, painter, rect, date):
  144.         painter.save()
  145.         painter.setRenderHint(QPainter.RenderHint.Antialiasing)
  146.         
  147.         # 绘制圆角背景
  148.         cell_rect = rect.adjusted(2, 2, -2, -2)
  149.         radius = 8
  150.         
  151.         # 设置背景颜色
  152.         if date == QDate.currentDate():
  153.             # 今天 - 浅绿色背景
  154.             bg_color = QColor(230, 245, 230)
  155.         elif date.dayOfWeek() > 5:  # 周末
  156.             bg_color = QColor(255, 240, 240)
  157.         else:  # 工作日
  158.             bg_color = QColor(255, 255, 255)
  159.         
  160.         # 如果是选中日期,使用特殊样式
  161.         if date == self.selectedDate():
  162.             painter.setPen(QPen(QColor(100, 150, 255), 2))  # 蓝色边框
  163.             painter.setBrush(QBrush(QColor(240, 245, 255)))  # 浅蓝色背景
  164.             painter.drawRoundedRect(cell_rect, radius, radius)
  165.         else:
  166.             # 普通日期背景
  167.             painter.setPen(QPen(QColor(220, 220, 220), 1))
  168.             painter.setBrush(QBrush(bg_color))
  169.             painter.drawRoundedRect(cell_rect, radius, radius)
  170.         
  171.         # 设置文字颜色
  172.         text_color = QColor(60, 60, 60)  # 默认深灰色
  173.         if date.dayOfWeek() > 5:  # 周末
  174.             text_color = QColor(220, 50, 50)
  175.         if date == QDate.currentDate():  # 今天
  176.             text_color = QColor(0, 100, 0)
  177.         if date == self.selectedDate():  # 选中日期
  178.             text_color = QColor(50, 100, 200)  # 蓝色文字
  179.         
  180.         painter.setPen(QPen(text_color))
  181.         
  182.         # 绘制日期文本
  183.         font = QFont("Arial", 9)
  184.         if date == QDate.currentDate() or date == self.selectedDate():
  185.             font.setBold(True)
  186.         painter.setFont(font)
  187.         
  188.         painter.drawText(cell_rect, Qt.AlignmentFlag.AlignCenter, str(date.day()))
  189.         
  190.         painter.restore()

  191. class CalendarApp(QMainWindow):
  192.     def __init__(self):
  193.         super().__init__()
  194.         self.setWindowTitle("精美日历")
  195.         self.resize(450, 450)
  196.         
  197.         # 主窗口样式
  198.         self.setStyleSheet("""
  199.             QMainWindow {
  200.                 background: #f8f8f8;
  201.                 border-radius: 15px;
  202.             }
  203.         """)
  204.         
  205.         # 创建中央部件
  206.         central_widget = QWidget()
  207.         central_widget.setStyleSheet("background: transparent;")
  208.         self.setCentralWidget(central_widget)
  209.         
  210.         # 布局
  211.         layout = QVBoxLayout(central_widget)
  212.         layout.setContentsMargins(20, 20, 20, 20)
  213.         layout.setSpacing(15)
  214.         
  215.         # 标题
  216.         title = QLabel("精美日历")
  217.         title.setStyleSheet("""
  218.             QLabel {
  219.                 font-size: 24px;
  220.                 font-weight: bold;
  221.                 color: #444444;
  222.                 padding: 5px;
  223.             }
  224.         """)
  225.         title.setAlignment(Qt.AlignmentFlag.AlignCenter)
  226.         layout.addWidget(title)
  227.         
  228.         # 日历部件
  229.         self.calendar = RoundCellCalendar()
  230.         layout.addWidget(self.calendar)
  231.         
  232.         # 底部按钮
  233.         btn_today = QPushButton("返回今天")
  234.         btn_today.setStyleSheet("""
  235.             QPushButton {
  236.                 background: #4CAF50;
  237.                 color: white;
  238.                 border: none;
  239.                 padding: 8px;
  240.                 border-radius: 10px;
  241.                 font-size: 14px;
  242.                 min-width: 100px;
  243.             }
  244.             QPushButton:hover {
  245.                 background: #45a049;
  246.             }
  247.         """)
  248.         btn_today.clicked.connect(self.go_to_today)
  249.         layout.addWidget(btn_today, 0, Qt.AlignmentFlag.AlignHCenter)

  250.     def go_to_today(self):
  251.         self.calendar.setSelectedDate(QDate.currentDate())

  252. if __name__ == "__main__":
  253.     app = QApplication(sys.argv)
  254.    
  255.     # 设置应用样式
  256.     app.setStyle("Fusion")
  257.     palette = app.palette()
  258.     palette.setColor(QPalette.ColorRole.Window, QColor(248, 248, 248))
  259.     app.setPalette(palette)
  260.    
  261.     window = CalendarApp()
  262.     window.show()
  263.     sys.exit(app.exec())
复制代码


分步骤教我上面的内容
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2025-8-6 16:14:29 | 显示全部楼层
@FishC
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-8-6 16:15:45 | 显示全部楼层
下面我将分步骤详细解释这段 PyQt6 日历应用的实现原理和关键代码:

### 第一步:创建自定义日历控件
  1. class RoundCellCalendar(QCalendarWidget):
  2.     def __init__(self, parent=None):
  3.         super().__init__(parent)
  4.         # 设置整体样式表
  5.         self.setStyleSheet("""...""")
  6.         
  7.         # 自定义导航按钮
  8.         self.setup_navigation_buttons()
  9.         
  10.         # 初始化日期格式
  11.         self.init_date_formats()
复制代码


**关键点:**
1. 继承自 QCalendarWidget
2. 使用 CSS 样式表设置圆角边框和背景
3. 自定义导航按钮样式
4. 初始化不同日期类型(今天/周末)的显示格式

### 第二步:自定义导航按钮
  1. def setup_navigation_buttons(self):
  2.     # 获取前后月按钮
  3.     prev_btn = self.findChild(QToolButton, "qt_calendar_prevmonth")
  4.     next_btn = self.findChild(QToolButton, "qt_calendar_nextmonth")
  5.    
  6.     # 设置按钮样式
  7.     button_style = """..."""
  8.     prev_btn.setStyleSheet(button_style)
  9.     next_btn.setStyleSheet(button_style)
  10.    
  11.     # 使用QPainter绘制自定义箭头图标
  12.     # 创建左箭头
  13.     painter = QPainter(prev_pixmap)
  14.     painter.drawLine(...)
  15.     # 创建右箭头
  16.     painter = QPainter(next_pixmap)
  17.     painter.drawLine(...)
复制代码


**关键点:**
1. 使用 findChild 获取内置按钮
2. 使用 CSS 设置按钮圆角样式
3. 通过 QPainter 绘制自定义箭头图标
4. 设置按钮的悬停和按下状态样式

### 第三步:设置日期显示格式
  1. def init_date_formats(self):
  2.     # 今天样式(绿色)
  3.     today_fmt = QTextCharFormat()
  4.     today_fmt.setBackground(QColor(230, 245, 230))
  5.     today_fmt.setForeground(QColor(0, 100, 0))
  6.    
  7.     # 周末样式(红色)
  8.     weekend_fmt = QTextCharFormat()
  9.     weekend_fmt.setForeground(QColor(220, 50, 50))
  10.    
  11.     # 应用格式
  12.     self.setDateTextFormat(QDate.currentDate(), today_fmt)
  13.     self.setWeekdayTextFormat(Qt.DayOfWeek.Saturday, weekend_fmt)
  14.     self.setWeekdayTextFormat(Qt.DayOfWeek.Sunday, weekend_fmt)
复制代码


**关键点:**
1. 使用 QTextCharFormat 设置文本格式
2. 区分今天、周末和工作日样式
3. 通过 setDateTextFormat 设置特定日期样式
4. 通过 setWeekdayTextFormat 设置每周固定日样式

### 第四步:重写单元格绘制方法(核心)
  1. def paintCell(self, painter, rect, date):
  2.     # 保存painter状态
  3.     painter.save()
  4.    
  5.     # 创建圆角矩形区域
  6.     cell_rect = rect.adjusted(2, 2, -2, -2)
  7.     radius = 8
  8.    
  9.     # 根据日期类型设置背景色
  10.     if date == QDate.currentDate():
  11.         bg_color = QColor(230, 245, 230)  # 今天-绿色
  12.     elif date.dayOfWeek() > 5:
  13.         bg_color = QColor(255, 240, 240)  # 周末-粉色
  14.     else:
  15.         bg_color = Qt.GlobalColor.white   # 工作日-白色
  16.    
  17.     # 绘制圆角矩形背景
  18.     painter.setPen(QPen(QColor(220, 220, 220), 1))
  19.     painter.setBrush(QBrush(bg_color))
  20.     painter.drawRoundedRect(cell_rect, radius, radius)
  21.    
  22.     # 绘制日期文本
  23.     painter.drawText(cell_rect, Qt.AlignmentFlag.AlignCenter, str(date.day()))
  24.    
  25.     # 恢复painter状态
  26.     painter.restore()
复制代码


**关键点:**
1. 重写 paintCell 方法实现自定义绘制
2. 使用 drawRoundedRect 绘制圆角单元格
3. 根据日期类型动态设置背景色
4. 居中绘制日期文本

### 第五步:创建主窗口
  1. class CalendarApp(QMainWindow):
  2.     def __init__(self):
  3.         super().__init__()
  4.         # 设置窗口样式
  5.         self.setStyleSheet("QMainWindow { border-radius: 15px; }")
  6.         
  7.         # 创建布局和控件
  8.         layout = QVBoxLayout()
  9.         title = QLabel("精美日历")
  10.         self.calendar = RoundCellCalendar()
  11.         btn_today = QPushButton("返回今天")
  12.         
  13.         # 按钮点击事件
  14.         btn_today.clicked.connect(self.go_to_today)
  15.         
  16.     def go_to_today(self):
  17.         self.calendar.setSelectedDate(QDate.currentDate())
复制代码


**关键点:**
1. 主窗口使用圆角样式
2. 垂直布局管理控件
3. "返回今天"按钮绑定点击事件
4. 使用 QDate.currentDate() 获取当前日期

### 第六步:运行应用
  1. if __name__ == "__main__":
  2.     app = QApplication(sys.argv)
  3.     # 设置应用整体样式
  4.     app.setStyle("Fusion")
  5.     window = CalendarApp()
  6.     window.show()
  7.     sys.exit(app.exec())
复制代码


**关键点:**
1. 创建 QApplication 实例
2. 使用 Fusion 样式提升视觉效果
3. 显示主窗口并启动事件循环

这个实现通过自定义绘制创建了圆角单元格的日历,使用样式表美化界面,并实现了日期分类显示和"返回今天"功能。关键点是重写 paintCell 方法和合理使用 QTextCharFormat 设置日期样式。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-8-6 16:18:21 | 显示全部楼层
下面我将分步解释这个PyQt6精美日历应用的实现过程,帮助你理解每个部分的功能:

### 步骤1:导入必要的模块
  1. import sys
  2. from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
  3.                             QLabel, QCalendarWidget, QPushButton, QToolButton)
  4. from PyQt6.QtCore import Qt, QDate, QSize
  5. from PyQt6.QtGui import (QColor, QTextCharFormat, QFont, QPainter,
  6.                         QPalette, QPen, QBrush, QIcon, QPixmap)
复制代码


### 步骤2:创建自定义日历组件(核心)
  1. class RoundCellCalendar(QCalendarWidget):
  2.     def __init__(self, parent=None):
  3.         super().__init__(parent)
  4.         # 1. 设置整体样式表
  5.         self.setStyleSheet("""
  6.             QCalendarWidget { /* 主日历样式 */ }
  7.             QCalendarWidget QWidget#qt_calendar_navigationbar { /* 导航栏样式 */ }
  8.             QCalendarWidget QToolButton#qt_calendar_monthbutton { /* 月份按钮 */ }
  9.             QCalendarWidget QSpinBox { /* 年份选择框 */ }
  10.             QCalendarWidget QMenu { /* 月份选择菜单 */ }
  11.             QCalendarWidget QAbstractItemView:enabled { /* 选中日期样式 */ }
  12.         """)
  13.         
  14.         # 2. 自定义导航按钮
  15.         self.setup_navigation_buttons()
  16.         
  17.         # 3. 初始化日期格式
  18.         self.init_date_formats()
  19.    
  20.     def setup_navigation_buttons(self):
  21.         # 获取前后月份按钮
  22.         prev_btn = self.findChild(QToolButton, "qt_calendar_prevmonth")
  23.         next_btn = self.findChild(QToolButton, "qt_calendar_nextmonth")
  24.         
  25.         # 设置按钮样式并绘制自定义箭头图标
  26.         # ... [图标绘制代码] ...
  27.    
  28.     def init_date_formats(self):
  29.         # 设置今天、周末、工作日的不同样式
  30.         today_fmt = QTextCharFormat()  # 今天的格式
  31.         weekend_fmt = QTextCharFormat()  # 周末格式
  32.         weekday_fmt = QTextCharFormat()  # 工作日格式
  33.         
  34.         # 应用格式到具体日期
  35.         self.setDateTextFormat(QDate.currentDate(), today_fmt)
  36.         self.setWeekdayTextFormat(Qt.DayOfWeek.Saturday, weekend_fmt)
  37.         self.setWeekdayTextFormat(Qt.DayOfWeek.Sunday, weekend_fmt)
  38.    
  39.     def paintCell(self, painter, rect, date):
  40.         # 4. 自定义单元格绘制
  41.         # - 创建圆角矩形
  42.         # - 根据日期类型设置不同颜色
  43.         # - 绘制日期文本
  44.         # ... [绘制逻辑] ...
复制代码


### 步骤3:创建主窗口
  1. class CalendarApp(QMainWindow):
  2.     def __init__(self):
  3.         super().__init__()
  4.         self.setWindowTitle("精美日历")
  5.         self.resize(450, 450)
  6.         
  7.         # 1. 主窗口样式
  8.         self.setStyleSheet("QMainWindow { background: #f8f8f8; border-radius: 15px; }")
  9.         
  10.         # 2. 创建中央部件和布局
  11.         central_widget = QWidget()
  12.         layout = QVBoxLayout(central_widget)
  13.         
  14.         # 3. 添加标题
  15.         title = QLabel("精美日历")
  16.         layout.addWidget(title)
  17.         
  18.         # 4. 添加自定义日历
  19.         self.calendar = RoundCellCalendar()
  20.         layout.addWidget(self.calendar)
  21.         
  22.         # 5. 添加"返回今天"按钮
  23.         btn_today = QPushButton("返回今天")
  24.         btn_today.clicked.connect(self.go_to_today)
  25.         layout.addWidget(btn_today)
  26.    
  27.     def go_to_today(self):
  28.         self.calendar.setSelectedDate(QDate.currentDate())
复制代码


### 步骤4:运行应用
  1. if __name__ == "__main__":
  2.     app = QApplication(sys.argv)
  3.    
  4.     # 设置全局样式
  5.     app.setStyle("Fusion")
  6.     palette = app.palette()
  7.     palette.setColor(QPalette.ColorRole.Window, QColor(248, 248, 248))
  8.     app.setPalette(palette)
  9.    
  10.     window = CalendarApp()
  11.     window.show()
  12.     sys.exit(app.exec())
复制代码


### 关键功能说明:
1. **自定义日历组件**:
   - 重写paintCell()方法实现圆角日期格
   - 使用QSS样式表美化整体外观
   - 自定义导航按钮图标

2. **日期样式处理**:
   - 今天:绿色背景+深绿文字
   - 周末:红色文字
   - 工作日:深灰文字
   - 选中日期:蓝色边框+浅蓝背景

3. **主窗口结构**:
   - 标题标签
   - 自定义日历组件
   - "返回今天"功能按钮

4. **样式技巧**:
   - 使用setStyleSheet()设置QSS样式
   - 通过QTextCharFormat定制日期文本样式
   - 使用QPainter绘制自定义图标

### 运行效果:
- 圆角边框的日历组件
- 自定义箭头导航按钮
- 不同日期类型有不同颜色标识
- 点击"返回今天"按钮可快速定位当前日期

这个实现展示了PyQt6强大的自定义能力,你可以根据需要调整颜色、圆角大小等样式参数来改变视觉效果。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-8-6 16:20:51 | 显示全部楼层


我注意到您@了FishC但没有提出具体问题。请详细描述您遇到的编程问题或学习困惑,我会用通俗易懂的方式为您解答!

例如您可以这样提问:
  • Python中如何读取文件内容?
  • 为什么我的循环一直运行停不下来?
  • 请解释面向对象编程的基本概念。


期待您的问题!当您补充具体内容后,我会立即给出分步解答和示例代码。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-8-6 16:26:55 | 显示全部楼层
FishC 发表于 2025-8-6 16:15
下面我将分步骤详细解释这段 PyQt6 日历应用的实现原理和关键代码:

### 第一步:创建自定义日历控件

能不能更细致的讲解
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-8-6 16:30:52 | 显示全部楼层
cjjJasonchen 发表于 2025-08-06 16:26
FishC 发表于 2025-8-6 16:15
下面我将分步骤详细解 ...


# PyQt6 精美日历应用详细解析

我将为您详细讲解这个精美日历应用的实现原理和关键代码,帮助您深入理解每个部分的功能。

## 一、整体结构分析

这个应用包含两个主要类:
1. `RoundCellCalendar` - 自定义日历组件
2. `CalendarApp` - 主窗口类

应用运行流程:
  1. 创建应用 -> 设置全局样式 -> 创建主窗口 -> 显示窗口 -> 进入事件循环
复制代码


## 二、自定义日历组件详解

### 1. 组件初始化
  1. class RoundCellCalendar(QCalendarWidget):
  2.     def __init__(self, parent=None):
  3.         super().__init__(parent)
  4.         # 设置整体样式表
  5.         self.setStyleSheet("""...""")
  6.         
  7.         # 自定义导航按钮
  8.         self.setup_navigation_buttons()
  9.         
  10.         # 初始化日期格式
  11.         self.init_date_formats()
复制代码


### 2. 导航按钮定制
  1. def setup_navigation_buttons(self):
  2.     # 获取前后月份按钮
  3.     prev_btn = self.findChild(QToolButton, "qt_calendar_prevmonth")
  4.     next_btn = self.findChild(QToolButton, "qt_calendar_nextmonth")
  5.    
  6.     # 设置按钮样式
  7.     button_style = """
  8.         QToolButton {
  9.             background: #f0f0f0;
  10.             border-radius: 12px;
  11.             border: 1px solid #d0d0d0;
  12.             width: 24px;
  13.             height: 24px;
  14.         }
  15.         QToolButton:hover { background: #e0e0e0; }
  16.         QToolButton:pressed { background: #d0d0d0; }
  17.     """
  18.     prev_btn.setStyleSheet(button_style)
  19.     next_btn.setStyleSheet(button_style)
  20.    
  21.     # 使用QPainter绘制自定义箭头图标
  22.     # 左箭头绘制代码...
  23.     # 右箭头绘制代码...
复制代码


关键点:
- 使用 `findChild` 获取内置按钮对象
- 使用 CSS 样式表设置按钮外观
- 通过 QPainter 动态绘制箭头图标
- 设置按钮的悬停和按下状态效果

### 3. 日期格式初始化
  1. def init_date_formats(self):
  2.     # 今天的样式
  3.     today_fmt = QTextCharFormat()
  4.     today_fmt.setBackground(QColor(230, 245, 230))  # 浅绿背景
  5.     today_fmt.setForeground(QColor(0, 100, 0))      # 深绿文字
  6.     today_fmt.setFont(QFont("Arial", 10, QFont.Weight.Bold))
  7.    
  8.     # 周末的样式
  9.     weekend_fmt = QTextCharFormat()
  10.     weekend_fmt.setForeground(QColor(220, 50, 50))  # 柔和的红色
  11.    
  12.     # 应用格式
  13.     self.setDateTextFormat(QDate.currentDate(), today_fmt)
  14.     self.setWeekdayTextFormat(Qt.DayOfWeek.Saturday, weekend_fmt)
  15.     self.setWeekdayTextFormat(Qt.DayOfWeek.Sunday, weekend_fmt)
  16.    
  17.     # 工作日的样式
  18.     weekday_fmt = QTextCharFormat()
  19.     weekday_fmt.setForeground(QColor(60, 60, 60))   # 深灰色
  20.     for day in range(1, 6):  # 周一(1)到周五(5)
  21.         self.setWeekdayTextFormat(day, weekday_fmt)
复制代码


关键点:
- 使用 `QTextCharFormat` 定义文本格式
- 区分今天、周末和工作日的不同样式
- `setDateTextFormat` 设置特定日期格式
- `setWeekdayTextFormat` 设置每周固定日的格式

### 4. 单元格绘制(核心)
  1. def paintCell(self, painter, rect, date):
  2.     painter.save()  # 保存当前绘图状态
  3.     painter.setRenderHint(QPainter.RenderHint.Antialiasing)  # 开启抗锯齿
  4.    
  5.     # 创建圆角矩形区域(比原始单元格小2像素)
  6.     cell_rect = rect.adjusted(2, 2, -2, -2)
  7.     radius = 8  # 圆角半径
  8.    
  9.     # 确定背景颜色
  10.     if date == QDate.currentDate():   # 今天
  11.         bg_color = QColor(230, 245, 230)  # 浅绿色
  12.     elif date.dayOfWeek() > 5:        # 周末(周六=6,周日=7)
  13.         bg_color = QColor(255, 240, 240)  # 浅粉色
  14.     else:                             # 工作日
  15.         bg_color = QColor(255, 255, 255)  # 白色
  16.    
  17.     # 绘制选中日期的特殊样式
  18.     if date == self.selectedDate():
  19.         painter.setPen(QPen(QColor(100, 150, 255), 2))  # 蓝色边框
  20.         painter.setBrush(QBrush(QColor(240, 245, 255)))  # 浅蓝背景
  21.         painter.drawRoundedRect(cell_rect, radius, radius)
  22.     else:
  23.         painter.setPen(QPen(QColor(220, 220, 220), 1))  # 灰色边框
  24.         painter.setBrush(QBrush(bg_color))  # 背景色
  25.         painter.drawRoundedRect(cell_rect, radius, radius)
  26.    
  27.     # 设置文字颜色
  28.     text_color = QColor(60, 60, 60)  # 默认深灰色
  29.     if date.dayOfWeek() > 5:         # 周末
  30.         text_color = QColor(220, 50, 50)
  31.     if date == QDate.currentDate():  # 今天
  32.         text_color = QColor(0, 100, 0)
  33.     if date == self.selectedDate():  # 选中日期
  34.         text_color = QColor(50, 100, 200)  # 蓝色
  35.    
  36.     painter.setPen(QPen(text_color))
  37.    
  38.     # 设置字体
  39.     font = QFont("Arial", 9)
  40.     if date == QDate.currentDate() or date == self.selectedDate():
  41.         font.setBold(True)  # 今天和选中日期加粗
  42.    
  43.     # 绘制日期文本(居中)
  44.     painter.drawText(cell_rect, Qt.AlignmentFlag.AlignCenter, str(date.day()))
  45.    
  46.     painter.restore()  # 恢复绘图状态
复制代码


关键点:
- `paintCell` 是自定义绘制的核心方法
- 使用 `drawRoundedRect` 绘制圆角矩形
- 根据日期类型动态设置背景色和文字颜色
- 使用 `QPainter.save()` 和 `restore()` 管理绘图状态
- 开启抗锯齿使图形更平滑

## 三、主窗口实现详解

  1. class CalendarApp(QMainWindow):
  2.     def __init__(self):
  3.         super().__init__()
  4.         self.setWindowTitle("精美日历")
  5.         self.resize(450, 450)
  6.         
  7.         # 主窗口样式
  8.         self.setStyleSheet("""
  9.             QMainWindow {
  10.                 background: #f8f8f8;  /* 浅灰色背景 */
  11.                 border-radius: 15px;  /* 圆角窗口 */
  12.             }
  13.         """)
  14.         
  15.         # 创建中央部件
  16.         central_widget = QWidget()
  17.         central_widget.setStyleSheet("background: transparent;")  # 透明背景
  18.         self.setCentralWidget(central_widget)
  19.         
  20.         # 垂直布局
  21.         layout = QVBoxLayout(central_widget)
  22.         layout.setContentsMargins(20, 20, 20, 20)  # 设置边距
  23.         layout.setSpacing(15)  # 控件间距
  24.         
  25.         # 标题
  26.         title = QLabel("精美日历")
  27.         title.setStyleSheet("""
  28.             QLabel {
  29.                 font-size: 24px;
  30.                 font-weight: bold;
  31.                 color: #444444;
  32.                 padding: 5px;
  33.             }
  34.         """)
  35.         title.setAlignment(Qt.AlignmentFlag.AlignCenter)
  36.         layout.addWidget(title)
  37.         
  38.         # 添加自定义日历
  39.         self.calendar = RoundCellCalendar()
  40.         layout.addWidget(self.calendar)
  41.         
  42.         # "返回今天"按钮
  43.         btn_today = QPushButton("返回今天")
  44.         btn_today.setStyleSheet("""
  45.             QPushButton {
  46.                 background: #4CAF50;  /* 绿色背景 */
  47.                 color: white;
  48.                 border: none;
  49.                 padding: 8px;
  50.                 border-radius: 10px;  /* 圆角按钮 */
  51.                 font-size: 14px;
  52.                 min-width: 100px;    /* 最小宽度 */
  53.             }
  54.             QPushButton:hover {
  55.                 background: #45a049;  /* 悬停时深绿色 */
  56.             }
  57.         """)
  58.         btn_today.clicked.connect(self.go_to_today)  # 连接信号和槽
  59.         layout.addWidget(btn_today, 0, Qt.AlignmentFlag.AlignHCenter)  # 水平居中
  60.    
  61.     def go_to_today(self):
  62.         """跳转到今天的日期"""
  63.         self.calendar.setSelectedDate(QDate.currentDate())
复制代码


关键点:
- 使用 `QVBoxLayout` 垂直布局管理控件
- 设置窗口圆角效果
- 按钮的样式定制和悬停效果
- 信号与槽的连接:按钮点击事件

## 四、应用启动代码

  1. if __name__ == "__main__":
  2.     app = QApplication(sys.argv)
  3.    
  4.     # 设置应用整体样式
  5.     app.setStyle("Fusion")  # 使用Fusion样式,更现代
  6.    
  7.     # 设置调色板
  8.     palette = app.palette()
  9.     palette.setColor(QPalette.ColorRole.Window, QColor(248, 248, 248))  # 窗口背景色
  10.     app.setPalette(palette)
  11.    
  12.     window = CalendarApp()
  13.     window.show()
  14.     sys.exit(app.exec())
复制代码


关键点:
- `app.setStyle("Fusion")` 使用现代样式
- 设置全局调色板统一应用风格
- `app.exec()` 启动事件循环

## 五、关键知识点总结

1. **样式表(QSS)**:使用CSS-like语法定制控件外观
2. **自定义绘制**:通过重写`paintCell`实现个性化单元格
3. **日期处理**:使用`QDate`处理日期操作
4. **图形绘制**:使用`QPainter`绘制自定义图形
5. **布局管理**:`QVBoxLayout`垂直布局控件
6. **信号与槽**:连接按钮点击事件
7. **QTextCharFormat**:定制文本显示格式
8. **抗锯齿渲染**:提升图形显示质量

这个应用展示了PyQt6强大的自定义能力,您可以根据需要调整颜色、圆角大小、字体等参数来创建不同风格的日历组件。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-8-30 22:41

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表