【开发】利用AI · 纯小白也能编写精美的电脑日历📅组件
💠前言✨
- 利用目前国内外主流的AI工具,可以编程小程序,比如打包为电脑时间日历小组件,完全不懂代码,也可以成功.
- 电脑win11系统,安装编程软件:pycharm
💠正文✨
- 去Github找一个你满意的软件,把网站扔给AI,让他根据你的需求和电脑环境进行代码提供。
- Pycharm软件,左上角的文件,需要创建新项目,环境为自定义虚拟环境,python 3.14, 如图⬇️:

- 左侧的菜单栏,选择根目录,鼠标右键,点击新建,名称根据项目自定义即可,如图⬇️:

- 代码,粘贴到右侧空白区域即可,右上角的绿色▶️按钮为实时展示成品
- 作者写了一款HTC的翻页桌面大时钟+日历📅的组件,鼠标右键还支持查看每月的日期.
- 效果如图:

- 先安装依赖包,代码如下:
pip install PyQt6 pystray Pillow borax
- 代码如下:
import sys
import os
import threading
import calendar
import winreg
from datetime import datetime
from PyQt6.QtWidgets import (
QApplication, QWidget, QLabel, QVBoxLayout, QHBoxLayout, QGridLayout,
QPushButton, QFrame, QStackedLayout
)
from PyQt6.QtCore import QTimer, Qt, QPoint, QSettings
from PyQt6.QtGui import QFont, QIcon # 确保导入 QIcon
import pystray
from PIL import Image, ImageDraw
# --- 0. 打包资源路径获取函数 (解决 EXE 运行图标丢失) ---
def resource_path(relative_path):
""" 获取程序运行时的绝对路径,兼容开发环境和 PyInstaller 打包环境 """
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
# --- 1. Borax 农历支持 ---
BORAX_AVAILABLE = False
try:
from borax.calendars.lunardate import LunarDate
BORAX_AVAILABLE = True
except:
BORAX_AVAILABLE = False
class HTCFlipClock(QWidget):
def __init__(self):
super().__init__()
self.old_pos = None
self.is_calendar_mode = False
self.is_refreshing = False
self.view_year = datetime.now().year
self.view_month = datetime.now().month
self.settings = QSettings("MyStudio", "HTC_Clock_Pro")
self.current_font_family = self.settings.value("font_family", "Arial")
self.init_ui()
self.load_settings()
self.set_auto_start()
self.timer = QTimer(self)
self.timer.timeout.connect(self.refresh_display)
self.timer.start(1000)
self.refresh_display()
def create_flip_card(self, parent):
container = QFrame(parent)
container.setFixedSize(110, 115)
back = QFrame(container); back.setGeometry(5, 8, 100, 100)
back.setStyleSheet("background: rgba(255, 255, 255, 15); border-radius: 6px;")
front = QFrame(container); front.setGeometry(0, 0, 110, 105)
front.setStyleSheet("background: rgba(255, 255, 255, 22); border-radius: 8px; border: 1px solid rgba(255,255,255,15);")
lbl = QLabel(front); lbl.setGeometry(0, 0, 110, 105); lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
lbl.setStyleSheet(f"color: white; font-family: '{self.current_font_family}'; font-size: 80px; font-weight: bold;")
line = QFrame(front); line.setGeometry(0, 52, 110, 2); line.setStyleSheet("background: rgba(0, 0, 0, 100);")
return container, lbl
def init_ui(self):
# --- 显式设置窗口图标 ---
icon_path = resource_path("clock.ico")
if os.path.exists(icon_path):
self.setWindowIcon(QIcon(icon_path))
# 移除 Tool 标记以确保在任务栏显示图标 (如果需要任务栏不显示图标,请保留 Tool)
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
self.main_container = QWidget(self)
self.main_container.setFixedWidth(280)
self.main_container.setStyleSheet("background-color: rgba(20, 20, 20, 245); border-radius: 15px;")
self.layout_total = QVBoxLayout(self.main_container)
self.layout_total.setContentsMargins(12, 12, 12, 12)
self.top_bar = QHBoxLayout()
lbl_s = "font-family: 'Microsoft YaHei'; font-size: 11px; color: #777;"
self.date_lbl = QLabel(); self.date_lbl.setStyleSheet(lbl_s)
self.week_lbl = QLabel(); self.week_lbl.setStyleSheet(f"{lbl_s} color: #FF3B30; font-weight: bold;")
self.lunar_lbl = QLabel(); self.lunar_lbl.setStyleSheet(lbl_s)
self.top_bar.addWidget(self.date_lbl); self.top_bar.addStretch(); self.top_bar.addWidget(self.week_lbl); self.top_bar.addStretch(); self.top_bar.addWidget(self.lunar_lbl)
self.layout_total.addLayout(self.top_bar)
self.view_stack = QStackedLayout()
# 时钟页
self.page_time = QWidget()
layout_time = QHBoxLayout(self.page_time)
layout_time.setContentsMargins(0, 10, 0, 0); layout_time.setSpacing(10)
self.h_card, self.h_lbl = self.create_flip_card(self.page_time)
self.m_card, self.m_lbl = self.create_flip_card(self.page_time)
layout_time.addWidget(self.h_card); layout_time.addWidget(self.m_card)
# 日历页
self.page_cal = QWidget()
layout_cal_root = QVBoxLayout(self.page_cal)
layout_cal_root.setContentsMargins(0, 5, 0, 0)
nav = QHBoxLayout()
btn_s = "color: #AAA; border: none; font-size: 14px; font-weight: bold; background: transparent;"
self.btn_year_prev = QPushButton("«", self); self.btn_year_prev.setStyleSheet(btn_s); self.btn_year_prev.setFixedWidth(25)
self.btn_year_next = QPushButton("»", self); self.btn_year_next.setStyleSheet(btn_s); self.btn_year_next.setFixedWidth(25)
self.btn_mon_prev = QPushButton("‹", self); self.btn_mon_prev.setStyleSheet(btn_s); self.btn_mon_prev.setFixedWidth(25)
self.btn_mon_next = QPushButton("›", self); self.btn_mon_next.setStyleSheet(btn_s); self.btn_mon_next.setFixedWidth(25)
self.cal_title = QLabel(); self.cal_title.setStyleSheet("color: white; font-weight: bold; font-size: 13px;")
nav.addWidget(self.btn_year_prev); nav.addWidget(self.btn_mon_prev); nav.addStretch()
nav.addWidget(self.cal_title); nav.addStretch(); nav.addWidget(self.btn_mon_next); nav.addWidget(self.btn_year_next)
layout_cal_root.addLayout(nav)
self.grid_layout = QGridLayout()
self.grid_layout.setSpacing(1)
layout_cal_root.addLayout(self.grid_layout)
self.view_stack.addWidget(self.page_time)
self.view_stack.addWidget(self.page_cal)
self.layout_total.addLayout(self.view_stack)
self.btn_year_prev.clicked.connect(lambda: self.safe_change_view(-1, 0))
self.btn_year_next.clicked.connect(lambda: self.safe_change_view(1, 0))
self.btn_mon_prev.clicked.connect(lambda: self.safe_change_view(0, -1))
self.btn_mon_next.clicked.connect(lambda: self.safe_change_view(0, 1))
main_vbox = QVBoxLayout(self)
main_vbox.setContentsMargins(0, 0, 0, 0)
main_vbox.addWidget(self.main_container)
# ... [保持之前的 safe_change_view, refresh_calendar_ui, refresh_display 逻辑不变] ...
def safe_change_view(self, y_delta, m_delta):
if self.is_refreshing: return
self.is_refreshing = True
self.view_year += y_delta
self.view_month += m_delta
if self.view_month > 12: self.view_month = 1; self.view_year += 1
elif self.view_month < 1: self.view_month = 12; self.view_year -= 1
QTimer.singleShot(5, self.refresh_calendar_ui)
def refresh_calendar_ui(self):
try:
while self.grid_layout.count():
child = self.grid_layout.takeAt(0)
if child.widget(): child.widget().deleteLater()
self.cal_title.setText(f"{self.view_year}年 {self.view_month}月")
for i, h in enumerate(["一", "二", "三", "四", "五", "六", "日"]):
lbl = QLabel(h); lbl.setStyleSheet("color: #666; font-size: 10px;"); self.grid_layout.addWidget(lbl, 0, i, Qt.AlignmentFlag.AlignCenter)
month_days = calendar.monthcalendar(self.view_year, self.view_month)
now = datetime.now()
for r, week in enumerate(month_days):
for c, day in enumerate(week):
if day != 0:
d_lbl = QLabel(str(day))
is_today = (day == now.day and self.view_year == now.year and self.view_month == now.month)
d_lbl.setStyleSheet(f"color: {'#FF3B30' if is_today else 'white'}; font-size: 12px; font-weight: {'bold' if is_today else 'normal'};")
self.grid_layout.addWidget(d_lbl, r + 1, c, Qt.AlignmentFlag.AlignCenter)
finally:
self.is_refreshing = False
def refresh_display(self):
now = datetime.now()
self.date_lbl.setText(now.strftime("%m-%d"))
self.week_lbl.setText(["周一", "周二", "周三", "周四", "周五", "周六", "周日"][now.weekday()])
self.lunar_lbl.setText(self.get_lunar_text() if BORAX_AVAILABLE else "未加载Borax")
self.h_lbl.setText(now.strftime("%H"))
self.m_lbl.setText(now.strftime("%M"))
def get_lunar_text(self):
try:
today = datetime.now()
lunar = LunarDate.from_solar_date(today.year, today.month, today.day)
return lunar.term if lunar.term else f"{['','正月','二月','三月','四月','五月','六月','七月','八月','九月','十月','冬月','腊月'][lunar.month]}{lunar.strftime('%D')}"
except: return "日期错误"
def mousePressEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
self.old_pos = event.globalPosition().toPoint()
elif event.button() == Qt.MouseButton.RightButton:
self.is_calendar_mode = not self.is_calendar_mode
if self.is_calendar_mode:
self.refresh_calendar_ui()
self.view_stack.setCurrentIndex(1)
else:
self.view_stack.setCurrentIndex(0)
def mouseMoveEvent(self, event):
if self.old_pos:
delta = QPoint(event.globalPosition().toPoint() - self.old_pos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.old_pos = event.globalPosition().toPoint()
def mouseReleaseEvent(self, event):
if event.button() == Qt.MouseButton.LeftButton:
self.settings.setValue("window_pos", self.pos())
def toggle_on_top(self):
is_top = bool(self.windowFlags() & Qt.WindowType.WindowStaysOnTopHint)
if is_top: self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowStaysOnTopHint)
else: self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowStaysOnTopHint)
self.show()
self.settings.setValue("is_top", not is_top)
def set_auto_start(self):
try:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run", 0, winreg.KEY_SET_VALUE)
winreg.SetValueEx(key, "HTC_FlipClock_Ultimate", 0, winreg.REG_SZ, f'"{os.path.realpath(sys.argv[0])}"')
winreg.CloseKey(key)
except: pass
def load_settings(self):
pos = self.settings.value("window_pos", QPoint(200, 200))
self.move(pos)
if self.settings.value("is_top", False, type=bool):
self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowStaysOnTopHint)
def setup_tray(win):
img = Image.new('RGBA', (64, 64), (0, 0, 0, 0))
d = ImageDraw.Draw(img)
d.rounded_rectangle([10, 10, 54, 54], radius=12, fill=(255, 255, 255, 240))
# 获取图标路径用于托盘(如果托盘库支持设置图标)
menu = pystray.Menu(
pystray.MenuItem("窗口置顶", lambda: win.toggle_on_top(), checked=lambda item: bool(win.windowFlags() & Qt.WindowType.WindowStaysOnTopHint)),
pystray.MenuItem("退出程序", lambda: os._exit(0))
)
pystray.Icon("Clock", img, "HTC Flip Pro", menu).run()
if __name__ == "__main__":
app = QApplication(sys.argv)
# --- 重要:在 APP 层也设置一下图标 ---
app.setWindowIcon(QIcon(resource_path("clock.ico")))
window = HTCFlipClock()
window.show()
threading.Thread(target=setup_tray, args=(window,), daemon=True).start()
sys.exit(app.exec())
- 由于需要图标,所以需要将.ico格式的图标命名为clock,放在clock.py的相同目录,进行打包为exe程序.
- 打包,需要利用PyInstaller依赖包,在下方的终端中,输入命令行:
pip install pyinstaller
- 开始全部打包📦,引号名称自定义,右侧的英文是你当前项目的名字,命令如下:
python -m PyInstaller --noconsole --onefile --icon=clock.ico --add-data "clock.ico;." --collect-all borax --name "HTC桌面时钟" clock.py
- 打包📦成功后,软件包exe就在dist电脑目录里面了.
💠折腾不止,热爱不停~✨
© 版权声明
文章版权归作者所有,未经允许请勿转载。


