【开发】利用AI · 纯小白也能编写精美的电脑日历📅组件

💠前言✨


  • 利用目前国内外主流的AI工具,可以编程小程序,比如打包为电脑时间日历小组件,完全不懂代码,也可以成功.
  • 电脑win11系统,安装编程软件:pycharm

💠正文✨


  • 去Github找一个你满意的软件,把网站扔给AI,让他根据你的需求和电脑环境进行代码提供。
  • Pycharm软件,左上角的文件,需要创建新项目,环境为自定义虚拟环境,python 3.14, 如图⬇️:
  • 新建项目
  • 左侧的菜单栏,选择根目录,鼠标右键,点击新建,名称根据项目自定义即可,如图⬇️:
  • 新建py
  • 代码,粘贴到右侧空白区域即可,右上角的绿色▶️按钮为实时展示成品
  • 作者写了一款HTC的翻页桌面大时钟+日历📅的组件,鼠标右键还支持查看每月的日期.
  • 效果如图:
  • clock
  • 先安装依赖包,代码如下:
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, 
    QFrame, QStackedLayout
)
from PyQt6.QtCore import QTimer, Qt, QPoint, QSettings, pyqtSignal
from PyQt6.QtGui import QFont, QIcon

import pystray
from PIL import Image

# --- 资源路径解析(打包 exe 时的核心函数) ---
def resource_path(relative_path):
    """ 获取资源的绝对路径,兼容开发环境和 PyInstaller 打包环境 """
    if hasattr(sys, '_MEIPASS'):
        # PyInstaller 会将资源解压到这个临时文件夹
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.abspath("."), relative_path)

# --- Borax 农历支持 ---
BORAX_AVAILABLE = False
try:
    from borax.calendars.lunardate import LunarDate
    BORAX_AVAILABLE = True
except:
    BORAX_AVAILABLE = False

class HTCFlipClock(QWidget):
    # 信号:由托盘触发,主线程执行 UI 更新
    sig_apply_font = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.old_pos = None
        self.is_calendar_mode = False
        
        # 配置系统
        self.settings = QSettings("MyStudio", "HTC_Clock_Stable_Final")
        self.is_locked = self.settings.value("is_locked", False, type=bool)
        self.current_font = self.settings.value("font_family", "Impact")
        self.auto_start_active = False

        self.init_ui()
        self.load_settings()
        self.check_auto_start_status()

        # 绑定信号
        self.sig_apply_font.connect(self.handle_font_change)

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.refresh_display)
        self.timer.start(1000)
        self.refresh_display()

    def init_ui(self):
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Tool)
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        
        # 加载内部图标
        icon_path = resource_path("clock.ico")
        if os.path.exists(icon_path):
            self.setWindowIcon(QIcon(icon_path))

        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.view_stack.addWidget(self.page_time)

        # 日历页
        self.page_cal = QWidget()
        layout_cal_root = QVBoxLayout(self.page_cal)
        layout_cal_root.setContentsMargins(0, 5, 0, 0)
        self.cal_title = QLabel(); self.cal_title.setStyleSheet("color: white; font-weight: bold; font-size: 13px;")
        layout_cal_root.addWidget(self.cal_title, alignment=Qt.AlignmentFlag.AlignCenter)
        self.grid_layout = QGridLayout(); self.grid_layout.setSpacing(1)
        layout_cal_root.addLayout(self.grid_layout)
        self.view_stack.addWidget(self.page_cal)

        self.layout_total.addLayout(self.view_stack)
        
        main_vbox = QVBoxLayout(self)
        main_vbox.setContentsMargins(0, 0, 0, 0)
        main_vbox.addWidget(self.main_container)

    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)
        return container, lbl

    def refresh_display(self):
        now = datetime.now()
        self.date_lbl.setText(now.strftime("%m-%d"))
        self.week_lbl.setText(["周一", "周二", "周三", "周四", "周五", "周六", "周日"][now.weekday()])
        if BORAX_AVAILABLE:
            try:
                lunar = LunarDate.from_solar_date(now.year, now.month, now.day)
                self.lunar_lbl.setText(lunar.term if lunar.term else f"{lunar.strftime('%M%D')}")
            except: pass
        self.h_lbl.setText(now.strftime("%H"))
        self.m_lbl.setText(now.strftime("%M"))

    def handle_font_change(self, font_name):
        self.current_font = font_name
        is_bold = any(x in font_name for x in ["Bold", "Impact", "Black"])
        weight = "bold" if is_bold else "normal"
        clean_name = font_name.split(",")[0].replace(" Bold", "")
        qss = f"color: white; font-family: '{clean_name}'; font-size: 80px; font-weight: {weight};"
        self.h_lbl.setStyleSheet(qss)
        self.m_lbl.setStyleSheet(qss)
        self.settings.setValue("font_family", font_name)

    # --- 基础功能 ---
    def toggle_lock(self):
        self.is_locked = not self.is_locked
        self.settings.setValue("is_locked", self.is_locked)

    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()

    def check_auto_start_status(self):
        try:
            key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run", 0, winreg.KEY_READ)
            winreg.QueryValueEx(key, "HTC_FlipClock_Ultimate")
            winreg.CloseKey(key)
            self.auto_start_active = True
        except: self.auto_start_active = False

    def toggle_auto_start(self):
        try:
            key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run", 0, winreg.KEY_SET_VALUE)
            if not self.auto_start_active:
                winreg.SetValueEx(key, "HTC_FlipClock_Ultimate", 0, winreg.REG_SZ, f'"{os.path.realpath(sys.argv[0])}"')
                self.auto_start_active = True
            else:
                winreg.DeleteValue(key, "HTC_FlipClock_Ultimate")
                self.auto_start_active = False
            winreg.CloseKey(key)
        except: pass

    def mousePressEvent(self, event):
        if not self.is_locked and 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
            self.view_stack.setCurrentIndex(1 if self.is_calendar_mode else 0)
            if self.is_calendar_mode: self.refresh_calendar_ui()

    def mouseMoveEvent(self, event):
        if not self.is_locked and 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 refresh_calendar_ui(self):
        while self.grid_layout.count():
            child = self.grid_layout.takeAt(0)
            if child.widget(): child.widget().deleteLater()
        now = datetime.now()
        self.cal_title.setText(f"{now.year}年 {now.month}月")
        days = calendar.monthcalendar(now.year, now.month)
        for r, week in enumerate(days):
            for c, day in enumerate(week):
                if day != 0:
                    d_lbl = QLabel(str(day))
                    is_today = (day == now.day)
                    d_lbl.setStyleSheet(f"color: {'#FF3B30' if is_today else 'white'}; font-size: 12px;")
                    self.grid_layout.addWidget(d_lbl, r, c, Qt.AlignmentFlag.AlignCenter)

    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.toggle_on_top()
        self.handle_font_change(self.current_font)

# --- 托盘管理 ---
def setup_tray(win):
    icon_path = resource_path("clock.ico")
    tray_img = Image.open(icon_path) if os.path.exists(icon_path) else Image.new('RGB', (64, 64), color='white')

    def create_menu():
        return pystray.Menu(
            pystray.MenuItem("窗口锁定", lambda: win.toggle_lock(), checked=lambda item: win.is_locked),
            pystray.MenuItem("窗口置顶", lambda: win.toggle_on_top(), checked=lambda item: bool(win.windowFlags() & Qt.WindowType.WindowStaysOnTopHint)),
            pystray.MenuItem("开机自启", lambda: win.toggle_auto_start(), checked=lambda item: win.auto_start_active),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("字体切换", pystray.Menu(
                pystray.MenuItem("Impact", lambda: win.sig_apply_font.emit("Impact"), checked=lambda item: win.current_font == "Impact"),
                pystray.MenuItem("Consolas", lambda: win.sig_apply_font.emit("Consolas"), checked=lambda item: win.current_font == "Consolas"),
                pystray.MenuItem("Segoe UI Bold", lambda: win.sig_apply_font.emit("Segoe UI Bold"), checked=lambda item: win.current_font == "Segoe UI Bold"),
                pystray.MenuItem("微软雅黑", lambda: win.sig_apply_font.emit("Microsoft YaHei"), checked=lambda item: win.current_font == "Microsoft YaHei"),
            )),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("退出程序", lambda: os._exit(0))
        )

    icon = pystray.Icon("HTCClock", tray_img, "HTC Flip Clock Stable")
    icon.menu = create_menu()
    icon.run()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)
    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电脑目录里面了.

💠折腾不止,热爱不停~✨


© 版权声明
文章版权归作者所有,未经允许请勿转载。

消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息