本文亮点:基于pyqt5+emoji实现多主题切换、动画效果、跨平台支持的桌面快捷方式管理器,3000字详解开发全流程!

项目概述
在windows/macos/linux系统中,我们经常需要快速访问常用程序和文件夹。传统方式是在桌面创建大量快捷方式,但会导致桌面杂乱无章。本项目使用pyqt5开发一个可视化快捷方式管理器,具有以下特点:
- 4种精美主题:深色/浅色/紫色/渐变风格
- 现代化ui:带动画效果的按钮、卡片式布局
- 跨平台支持:适配windows/macos/linux
- emoji集成:让界面更生动有趣
- 实用功能:添加/打开/删除/创建桌面快捷方式

图1:系统架构图
功能特色
多主题切换系统
class thememanager:
themes = {
"dark": {"name": "🌙 深色主题", "background": "#1e1e1e", ...},
"light": {"name": "☀️ 浅色主题", "background": "#f5f5f5", ...},
"purple": {"name": "🟣 紫色主题", "background": "#2a0a3e", ...},
"gradient": {"name": "🌈 渐变主题",
"background": "qlineargradient(...)", ...}
}
支持4种预设主题,一键切换不重启
动态交互效果
- 按钮按压动画(缩放效果)
- 悬停状态高亮提示
- 平滑的列表滚动
智能图标系统
def set_icon(self, path):
if os.path.isdir(path):
self.icon_label.settext(emoji.emojize("📁"))
elif ext in ('.exe', '.bat', '.cmd'):
self.icon_label.settext(emoji.emojize("🖥️"))
# 其他文件类型处理...
自动识别文件类型显示对应emoji图标
跨平台兼容性
# windows创建快捷方式
winshell.createshortcut(...)
# macos创建替身
os.symlink(...)
# linux创建.desktop文件
with open(shortcut_path, "w") as f:
f.write(desktop_file)
效果展示
浅色主题界面

渐变主题效果

开发步骤详解
环境准备
pip install pyqt5 emoji winshell # windows额外安装
项目结构
shortcut_manager/
├── main.py # 主程序入口
├── themes/ # 主题配置文件
├── icons/ # 图标资源
└── shortcuts.json # 快捷方式存储文件
核心实现流程
- 初始化主窗口:设置基本属性和布局
- 加载主题系统:读取thememanager配置
- 构建ui组件:
- 标题栏(带主题切换)
- 快捷方式列表(自定义itemwidget)
- 操作按钮区域
- 实现业务逻辑:
- 添加快捷方式
- 打开/删除条目
- 创建桌面快捷方式
- 持久化存储:json格式保存配置
核心代码解析
自定义动画按钮
class animatedbutton(qpushbutton):
def mousepressevent(self, event):
self._animation.setendvalue(self.geometry().adjusted(2, 2, -2, -2))
self._animation.start()
按压时产生缩小效果,释放时恢复
主题切换机制
def change_theme(self, theme_key):
self.current_theme = theme_key
# 动态更新所有组件样式
self.update_ui_style()
跨平台快捷方式创建
def create_desktop_shortcut(self):
if platform.system() == "windows":
# windows使用winshell
elif platform.system() == "darwin":
# macos使用符号链接
else:
# linux使用.desktop文件
列表项自定义widget
class shortcutitemwidget(qwidget):
def __init__(self, name, path, theme):
super().__init__()
# 构建包含图标、名称、路径的自定义布局
源码下载
import sys
import os
import json
import platform
import emoji
import subprocess
from pyqt5.qtwidgets import (qapplication, qmainwindow, qwidget, qvboxlayout, qhboxlayout,
qlabel, qlineedit, qpushbutton, qlistwidget, qlistwidgetitem,
qframe, qscrollarea, qfiledialog, qmessagebox, qmenu, qaction,
qsizepolicy, qspaceritem, qstatusbar)
from pyqt5.qtcore import qt, qsize, qpoint, qpropertyanimation, qeasingcurve, qtimer
from pyqt5.qtgui import (qcolor, qlineargradient, qpainter, qfont, qfontdatabase, qpalette,
qicon, qpixmap, qmovie)
class emojilabel(qlabel):
"""支持emoji的标签"""
def __init__(self, text="", parent=none):
super().__init__(parent)
self.settext(emoji.emojize(text))
class thememanager:
"""管理不同的ui主题"""
themes = {
"dark": {
"name": "🌙 深色主题",
"background": "#1e1e1e",
"foreground": "#ffffff",
"primary": "#6a5acd", # 紫罗兰色
"secondary": "#303030",
"tertiary": "#404040",
"highlight": "#9370db", # 中等紫罗兰色
"error": "#ff5252",
"success": "#4caf50",
"warning": "#ffa500",
"title_font": ("segoe ui", 14, qfont.bold),
"heading_font": ("segoe ui", 12, qfont.bold),
"normal_font": ("segoe ui", 10, qfont.normal),
"small_font": ("segoe ui", 9, qfont.normal),
"button_radius": "12px",
"card_radius": "15px",
"shadow": "0 4px 8px rgba(0, 0, 0, 0.3)"
},
"light": {
"name": "☀️ 浅色主题",
"background": "#f5f5f5",
"foreground": "#000000",
"primary": "#4169e1", # 皇家蓝
"secondary": "#e0e0e0",
"tertiary": "#bdbdbd",
"highlight": "#6495ed", # 矢车菊蓝
"error": "#d32f2f",
"success": "#388e3c",
"warning": "#f57c00",
"title_font": ("segoe ui", 14, qfont.bold),
"heading_font": ("segoe ui", 12, qfont.bold),
"normal_font": ("segoe ui", 10, qfont.normal),
"small_font": ("segoe ui", 9, qfont.normal),
"button_radius": "12px",
"card_radius": "15px",
"shadow": "0 4px 8px rgba(0, 0, 0, 0.1)"
},
"purple": {
"name": "🟣 紫色主题",
"background": "#2a0a3e",
"foreground": "#ffffff",
"primary": "#9c27b0",
"secondary": "#4a148c",
"tertiary": "#7b1fa2",
"highlight": "#ba68c8",
"error": "#ff5252",
"success": "#4caf50",
"warning": "#ffa500",
"title_font": ("segoe ui", 14, qfont.bold),
"heading_font": ("segoe ui", 12, qfont.bold),
"normal_font": ("segoe ui", 10, qfont.normal),
"small_font": ("segoe ui", 9, qfont.normal),
"button_radius": "12px",
"card_radius": "15px",
"shadow": "0 4px 8px rgba(0, 0, 0, 0.3)"
},
"gradient": {
"name": "🌈 渐变主题",
"background": "qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #1e1e1e, stop:1 #2a0a3e)",
"foreground": "#ffffff",
"primary": "qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #6a5acd, stop:1 #9c27b0)",
"secondary": "rgba(48, 48, 48, 0.7)",
"tertiary": "rgba(64, 64, 64, 0.7)",
"highlight": "qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #9370db, stop:1 #ba68c8)",
"error": "#ff5252",
"success": "#4caf50",
"warning": "#ffa500",
"title_font": ("segoe ui", 14, qfont.bold),
"heading_font": ("segoe ui", 12, qfont.bold),
"normal_font": ("segoe ui", 10, qfont.normal),
"small_font": ("segoe ui", 9, qfont.normal),
"button_radius": "12px",
"card_radius": "15px",
"shadow": "0 4px 8px rgba(0, 0, 0, 0.3)"
}
}
@staticmethod
def get_theme(theme_name):
"""获取指定主题的配置"""
return thememanager.themes.get(theme_name, thememanager.themes["dark"])
@staticmethod
def get_theme_names():
"""获取所有主题的名称"""
return [thememanager.themes[key]["name"] for key in thememanager.themes]
@staticmethod
def get_theme_keys():
"""获取所有主题的键"""
return list(thememanager.themes.keys())
class animatedbutton(qpushbutton):
"""带有动画效果的按钮"""
def __init__(self, text="", parent=none):
super().__init__(text, parent)
self.setcursor(qt.pointinghandcursor)
self._animation = qpropertyanimation(self, b"geometry")
self._animation.setduration(200)
self._animation.seteasingcurve(qeasingcurve.outquad)
def mousepressevent(self, event):
self._animation.stop()
self._animation.setstartvalue(self.geometry())
self._animation.setendvalue(self.geometry().adjusted(2, 2, -2, -2))
self._animation.start()
super().mousepressevent(event)
def mousereleaseevent(self, event):
self._animation.stop()
self._animation.setstartvalue(self.geometry())
self._animation.setendvalue(self.geometry().adjusted(-2, -2, 2, 2))
self._animation.start()
super().mousereleaseevent(event)
class shortcutitemwidget(qwidget):
"""自定义快捷方式列表项"""
def __init__(self, name, path, theme, parent=none):
super().__init__(parent)
self.theme = theme
self.setup_ui(name, path)
def setup_ui(self, name, path):
layout = qhboxlayout(self)
layout.setcontentsmargins(15, 10, 15, 10)
layout.setspacing(15)
# 图标
self.icon_label = qlabel()
self.icon_label.setfixedsize(64, 64)
self.set_icon(path)
layout.addwidget(self.icon_label)
# 文本信息
text_layout = qvboxlayout()
text_layout.setspacing(30)
text_layout.setcontentsmargins(5,0, 0, 0)# 调整文本边距
self.name_label = qlabel(name)
self.name_label.setfont(qfont(self.theme["normal_font"][0], self.theme["normal_font"][1], self.theme["normal_font"][2]))
self.name_label.setstylesheet(f"color: {self.theme['foreground']};")
self.name_label.setwordwrap(true) # 允许文本换行
self.path_label = qlabel(path)
self.path_label.setfont(qfont(self.theme["small_font"][0], self.theme["small_font"][1], self.theme["small_font"][2]))
self.path_label.setstylesheet(f"color: {self.theme['tertiary']};")
self.path_label.setwordwrap(true) # 允许文本换行
self.path_label.setmaximumwidth(400) # 限制路径显示宽度
text_layout.addwidget(self.name_label)
text_layout.addwidget(self.path_label)
layout.addlayout(text_layout, stretch=1) # 添加拉伸因子
# 添加弹性空间
layout.addspaceritem(qspaceritem(0, 0, qsizepolicy.expanding, qsizepolicy.minimum))
# 悬停效果
self.setautofillbackground(true)
palette = self.palette()
palette.setcolor(qpalette.background, qcolor(self.theme["secondary"]))
self.setpalette(palette)
def set_icon(self, path):
"""根据路径类型设置不同图标"""
if os.path.isdir(path):
# 文件夹图标
icon = qicon.fromtheme("folder")
if icon.isnull():
self.icon_label.settext(emoji.emojize("📁"))
self.icon_label.setstylesheet(f"""
font-size: 20px;
color: {self.theme['primary']};
""")
else:
pixmap = icon.pixmap(32, 32)
self.icon_label.setpixmap(pixmap)
else:
# 文件图标
icon = qicon.fromtheme("application-x-executable")
if icon.isnull():
# 根据文件扩展名显示不同emoji
ext = os.path.splitext(path)[1].lower()
if ext in ('.exe', '.bat', '.cmd'):
self.icon_label.settext(emoji.emojize("🖥️"))
elif ext in ('.py', '.sh'):
self.icon_label.settext(emoji.emojize("📜"))
else:
self.icon_label.settext(emoji.emojize("📄"))
self.icon_label.setstylesheet(f"""
font-size: 20px;
color: {self.theme['primary']};
""")
else:
# 使用系统文件图标
icon = qicon.fromtheme(qicon.fromtheme("application-x-executable"))
if os.path.exists(path):
icon = qicon(path)
pixmap = icon.pixmap(32, 32)
self.icon_label.setpixmap(pixmap)
self.icon_label.setalignment(qt.aligncenter)
class desktopshortcutmanager(qmainwindow):
def __init__(self):
super().__init__()
# 窗口设置
self.setwindowtitle("🚀 桌面快捷方式管理器")
self.setgeometry(100, 100, 1000, 700) # 增大窗口尺寸
# 初始化数据
self.current_theme = "dark"
self.shortcuts = {}
self.config_file = "shortcut_manager_config.json"
self.shortcuts_file = "desktop_shortcuts.json"
# 加载配置
self.load_config()
# 创建ui
self.init_ui()
# 加载快捷方式
self.load_shortcuts()
def get_current_theme(self):
"""获取当前主题配置"""
return thememanager.get_theme(self.current_theme)
def load_config(self):
"""加载配置文件"""
if os.path.exists(self.config_file):
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
if "theme" in config and config["theme"] in thememanager.get_theme_keys():
self.current_theme = config["theme"]
except exception as e:
print(f"加载配置失败: {str(e)}")
def save_config(self):
"""保存配置文件"""
try:
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump({"theme": self.current_theme}, f)
except exception as e:
print(f"保存配置失败: {str(e)}")
def init_ui(self):
"""初始化用户界面"""
theme = self.get_current_theme()
# 设置主窗口背景
if theme["background"].startswith("qlineargradient"):
self.setstylesheet(f"""
qmainwindow {{
background: {theme['background']};
}}
""")
else:
palette = self.palette()
palette.setcolor(qpalette.background, qcolor(theme["background"]))
self.setpalette(palette)
# 创建中央部件
central_widget = qwidget()
self.setcentralwidget(central_widget)
# 主布局
main_layout = qvboxlayout(central_widget)
main_layout.setcontentsmargins(15, 15, 15, 15) # 调整边距
main_layout.setspacing(15)
# 标题栏
self.create_title_bar(main_layout)
# 内容区域
content_widget = qwidget()
content_layout = qhboxlayout(content_widget)
content_layout.setcontentsmargins(0, 0, 0, 0)
content_layout.setspacing(15)
# 快捷方式列表
self.create_shortcut_list(content_layout)
# 操作按钮区域
self.create_action_buttons(content_layout)
main_layout.addwidget(content_widget)
# 状态栏
self.create_status_bar()
# 创建菜单(只创建一次)
if not hasattr(self, 'menu_created'):
self.create_menu()
self.menu_created = true
def create_title_bar(self, parent_layout):
"""创建标题栏"""
theme = self.get_current_theme()
title_bar = qwidget()
title_bar_layout = qhboxlayout(title_bar)
title_bar_layout.setcontentsmargins(0, 0, 0, 0)
# 标题
self.title_label = emojilabel("🚀 桌面快捷方式管理器")
self.title_label.setfont(qfont(theme["title_font"][0], theme["title_font"][1], theme["title_font"][2]))
self.title_label.setstylesheet(f"color: {theme['primary']};")
# 主题选择器
self.theme_selector = qpushbutton(emoji.emojize(theme["name"] + " ▼"))
self.theme_selector.setfont(qfont(theme["normal_font"][0], theme["normal_font"][1], theme["normal_font"][2]))
self.theme_selector.setstylesheet(f"""
qpushbutton {{
background-color: {theme['secondary']};
color: {theme['foreground']};
border-radius: {theme['button_radius']};
padding: 8px 12px;
border: none;
}}
qpushbutton:hover {{
background-color: {theme['tertiary']};
}}
""")
# 创建主题菜单
self.theme_menu = qmenu(self)
for theme_key in thememanager.get_theme_keys():
theme_data = thememanager.get_theme(theme_key)
action = qaction(emoji.emojize(theme_data["name"]), self)
action.triggered.connect(lambda _, key=theme_key: self.change_theme(key))
self.theme_menu.addaction(action)
self.theme_selector.setmenu(self.theme_menu)
# 添加弹性空间
spacer = qspaceritem(0, 0, qsizepolicy.expanding, qsizepolicy.minimum)
title_bar_layout.addwidget(self.title_label)
title_bar_layout.addspaceritem(spacer)
title_bar_layout.addwidget(self.theme_selector)
parent_layout.addwidget(title_bar)
def create_shortcut_list(self, parent_layout):
"""创建快捷方式列表"""
theme = self.get_current_theme()
# 创建卡片容器
self.list_card = qwidget()
self.list_card.setstylesheet(f"""
background-color: {theme['secondary']};
border-radius: {theme['card_radius']};
padding: 15px;
""")
card_layout = qvboxlayout(self.list_card)
card_layout.setcontentsmargins(0, 0, 0, 0)
card_layout.setspacing(15)
# 标题
self.list_title = qlabel("📋 快捷方式列表")
self.list_title.setfont(qfont(theme["heading_font"][0], theme["heading_font"][1], theme["heading_font"][2]))
self.list_title.setstylesheet(f"color: {theme['foreground']};")
card_layout.addwidget(self.list_title)
# 列表部件
self.shortcut_list = qlistwidget()
self.shortcut_list.setstylesheet(f"""
qlistwidget {{
background-color: transparent;
border: none;
outline: none;
}}
qlistwidget::item {{
border-bottom: 1px solid {theme['tertiary']};
}}
qlistwidget::item:selected {{
background-color: {theme['primary']};
border-radius: 5px;
}}
""")
self.shortcut_list.setverticalscrollmode(qlistwidget.scrollperpixel)
self.shortcut_list.sethorizontalscrollmode(qlistwidget.scrollperpixel)
# 添加到卡片
card_layout.addwidget(self.shortcut_list)
# 添加到主布局
parent_layout.addwidget(self.list_card, stretch=3)
def create_action_buttons(self, parent_layout):
"""创建操作按钮区域"""
theme = self.get_current_theme()
# 创建卡片容器
self.action_card = qwidget()
self.action_card.setstylesheet(f"""
background-color: {theme['secondary']};
border-radius: {theme['card_radius']};
padding: 15px;
""")
card_layout = qvboxlayout(self.action_card)
card_layout.setcontentsmargins(0, 0, 0, 0)
card_layout.setspacing(15)
# 标题
self.actions_title = qlabel("⚡ 快捷操作")
self.actions_title.setfont(qfont(theme["heading_font"][0], theme["heading_font"][1], theme["heading_font"][2]))
self.actions_title.setstylesheet(f"color: {theme['foreground']};")
card_layout.addwidget(self.actions_title)
# 添加按钮
self.add_btn = animatedbutton(emoji.emojize("➕ 添加快捷方式"))
self.add_btn.setstylesheet(self.get_button_style())
self.add_btn.clicked.connect(self.add_shortcut)
# 打开按钮
self.open_btn = animatedbutton(emoji.emojize("📂 打开快捷方式"))
self.open_btn.setstylesheet(self.get_button_style())
self.open_btn.clicked.connect(self.open_selected_shortcut)
# 删除按钮
self.delete_btn = animatedbutton(emoji.emojize("🗑️ 删除快捷方式"))
self.delete_btn.setstylesheet(self.get_button_style(true))
self.delete_btn.clicked.connect(self.delete_shortcut)
# 创建到桌面按钮
self.create_btn = animatedbutton(emoji.emojize("🖥️ 创建到桌面"))
self.create_btn.setstylesheet(self.get_button_style())
self.create_btn.clicked.connect(self.create_desktop_shortcut)
# 添加到布局
card_layout.addwidget(self.add_btn)
card_layout.addwidget(self.open_btn)
card_layout.addwidget(self.delete_btn)
card_layout.addwidget(self.create_btn)
# 添加弹性空间
card_layout.addspaceritem(qspaceritem(0, 0, qsizepolicy.minimum, qsizepolicy.expanding))
# 添加到主布局
parent_layout.addwidget(self.action_card, stretch=1)
def get_button_style(self, is_destructive=false):
"""获取按钮样式"""
theme = self.get_current_theme()
color = theme["error"] if is_destructive else theme["primary"]
return f"""
qpushbutton {{
background-color: {color};
color: {theme['foreground']};
border-radius: {theme['button_radius']};
padding: 12px;
font-weight: bold;
border: none;
}}
qpushbutton:hover {{
background-color: {theme['highlight']};
}}
qpushbutton:pressed {{
background-color: {theme['primary']};
}}
"""
def create_status_bar(self):
"""创建状态栏"""
theme = self.get_current_theme()
self.status_bar = qstatusbar()
self.setstatusbar(self.status_bar)
# 状态消息
self.status_message = qlabel("🟢 就绪")
self.status_message.setfont(qfont(theme["small_font"][0], theme["small_font"][1], theme["small_font"][2]))
self.status_message.setstylesheet(f"color: {theme['foreground']};")
self.status_bar.addwidget(self.status_message, stretch=1)
def create_menu(self):
"""创建菜单栏(只创建一次)"""
menubar = self.menubar()
theme = self.get_current_theme()
# 设置菜单栏样式
menubar.setstylesheet(f"""
qmenubar {{
background-color: {theme['secondary']};
color: {theme['foreground']};
padding: 5px;
border-bottom: 1px solid {theme['tertiary']};
}}
qmenubar::item {{
padding: 5px 10px;
background-color: transparent;
}}
qmenubar::item:selected {{
background-color: {theme['primary']};
border-radius: 5px;
}}
qmenu {{
background-color: {theme['secondary']};
color: {theme['foreground']};
border: 1px solid {theme['tertiary']};
}}
qmenu::item:selected {{
background-color: {theme['primary']};
}}
""")
# 文件菜单
file_menu = menubar.addmenu("📁 文件")
save_action = qaction("💾 保存所有快捷方式", self)
save_action.triggered.connect(self.save_shortcuts)
file_menu.addaction(save_action)
file_menu.addseparator()
exit_action = qaction("🚪 退出", self)
exit_action.triggered.connect(self.close)
file_menu.addaction(exit_action)
# 帮助菜单
help_menu = menubar.addmenu("❓ 帮助")
about_action = qaction("ℹ️ 关于", self)
about_action.triggered.connect(self.show_about)
help_menu.addaction(about_action)
def change_theme(self, theme_key):
"""更改ui主题"""
if theme_key not in thememanager.get_theme_keys():
return
self.current_theme = theme_key
self.save_config()
# 更新ui样式而不重新创建整个ui
theme = self.get_current_theme()
# 更新主窗口背景
if theme["background"].startswith("qlineargradient"):
self.setstylesheet(f"""
qmainwindow {{
background: {theme['background']};
}}
""")
else:
palette = self.palette()
palette.setcolor(qpalette.background, qcolor(theme["background"]))
self.setpalette(palette)
# 更新标题栏
self.title_label.setfont(qfont(theme["title_font"][0], theme["title_font"][1], theme["title_font"][2]))
self.title_label.setstylesheet(f"color: {theme['primary']};")
# 更新主题选择器
self.theme_selector.settext(emoji.emojize(theme["name"] + " ▼"))
self.theme_selector.setfont(qfont(theme["normal_font"][0], theme["normal_font"][1], theme["normal_font"][2]))
self.theme_selector.setstylesheet(f"""
qpushbutton {{
background-color: {theme['secondary']};
color: {theme['foreground']};
border-radius: {theme['button_radius']};
padding: 8px 12px;
border: none;
}}
qpushbutton:hover {{
background-color: {theme['tertiary']};
}}
""")
# 更新快捷方式列表卡片
self.list_card.setstylesheet(f"""
background-color: {theme['secondary']};
border-radius: {theme['card_radius']};
padding: 15px;
""")
self.list_title.setfont(qfont(theme["heading_font"][0], theme["heading_font"][1], theme["heading_font"][2]))
self.list_title.setstylesheet(f"color: {theme['foreground']};")
self.shortcut_list.setstylesheet(f"""
qlistwidget {{
background-color: transparent;
border: none;
outline: none;
}}
qlistwidget::item {{
border-bottom: 1px solid {theme['tertiary']};
}}
qlistwidget::item:selected {{
background-color: {theme['primary']};
border-radius: 5px;
}}
""")
# 更新操作按钮卡片
self.action_card.setstylesheet(f"""
background-color: {theme['secondary']};
border-radius: {theme['card_radius']};
padding: 15px;
""")
self.actions_title.setfont(qfont(theme["heading_font"][0], theme["heading_font"][1], theme["heading_font"][2]))
self.actions_title.setstylesheet(f"color: {theme['foreground']};")
# 更新按钮样式
self.add_btn.setstylesheet(self.get_button_style())
self.open_btn.setstylesheet(self.get_button_style())
self.delete_btn.setstylesheet(self.get_button_style(true))
self.create_btn.setstylesheet(self.get_button_style())
# 更新状态栏
self.status_message.setfont(qfont(theme["small_font"][0], theme["small_font"][1], theme["small_font"][2]))
self.status_message.setstylesheet(f"color: {theme['foreground']};")
# 更新菜单栏样式
menubar = self.menubar()
menubar.setstylesheet(f"""
qmenubar {{
background-color: {theme['secondary']};
color: {theme['foreground']};
padding: 5px;
border-bottom: 1px solid {theme['tertiary']};
}}
qmenubar::item {{
padding: 5px 10px;
background-color: transparent;
}}
qmenubar::item:selected {{
background-color: {theme['primary']};
border-radius: 5px;
}}
qmenu {{
background-color: {theme['secondary']};
color: {theme['foreground']};
border: 1px solid {theme['tertiary']};
}}
qmenu::item:selected {{
background-color: {theme['primary']};
}}
""")
# 刷新快捷方式列表项样式
self.refresh_shortcut_list()
# 显示主题更改成功消息
theme_name = thememanager.get_theme(theme_key)["name"]
self.show_status_message(f"已切换到 {theme_name}", "success")
def show_status_message(self, message, type="info"):
"""显示状态栏消息"""
theme = self.get_current_theme()
if type == "info":
icon = "🔵"
color = theme["primary"]
elif type == "success":
icon = "🟢"
color = theme["success"]
elif type == "error":
icon = "🔴"
color = theme["error"]
elif type == "warning":
icon = "🟡"
color = theme["warning"]
else:
icon = "🔵"
color = theme["primary"]
self.status_message.settext(f"{icon} {message}")
self.status_message.setstylesheet(f"color: {color};")
# 3秒后自动清除消息
qtimer.singleshot(3000, lambda: self.status_message.settext("🟢 就绪"))
def load_shortcuts(self):
"""从文件加载已保存的快捷方式"""
if os.path.exists(self.shortcuts_file):
try:
with open(self.shortcuts_file, 'r', encoding='utf-8') as f:
self.shortcuts = json.load(f)
self.refresh_shortcut_list()
self.show_status_message(f"已加载 {len(self.shortcuts)} 个快捷方式", "success")
except exception as e:
self.show_status_message(f"加载快捷方式失败: {str(e)}", "error")
self.shortcuts = {}
else:
self.shortcuts = {}
self.show_status_message("没有找到快捷方式文件,已创建新列表", "info")
def save_shortcuts(self):
"""保存快捷方式到文件"""
try:
with open(self.shortcuts_file, 'w', encoding='utf-8') as f:
json.dump(self.shortcuts, f, ensure_ascii=false, indent=4)
self.show_status_message("快捷方式保存成功", "success")
return true
except exception as e:
self.show_status_message(f"保存快捷方式失败: {str(e)}", "error")
return false
def refresh_shortcut_list(self):
"""刷新快捷方式列表"""
self.shortcut_list.clear()
for name, path in self.shortcuts.items():
item = qlistwidgetitem()
item.setsizehint(qsize(0, 80)) # 增加项高度以适应多行文本
widget = shortcutitemwidget(name, path, self.get_current_theme())
self.shortcut_list.additem(item)
self.shortcut_list.setitemwidget(item, widget)
def add_shortcut(self):
"""添加新的快捷方式(支持文件和文件夹)"""
path, _ = qfiledialog.getopenfilename(
self,
"选择文件或文件夹",
"",
"所有文件 (*);;可执行文件 (*.exe *.bat *.cmd);;脚本文件 (*.py *.sh);;文件夹"
)
if not path:
return
# 获取名称
name = os.path.basename(path)
# 如果已存在同名快捷方式,添加数字后缀
base_name = os.path.splitext(name)[0]
ext = os.path.splitext(name)[1]
counter = 1
while name in self.shortcuts:
name = f"{base_name} ({counter}){ext}"
counter += 1
# 添加到快捷方式字典
self.shortcuts[name] = path
# 保存并刷新列表
if self.save_shortcuts():
self.refresh_shortcut_list()
self.show_status_message(f"已添加快捷方式: {name}", "success")
def get_selected_shortcut(self):
"""获取选中的快捷方式"""
selected_items = self.shortcut_list.selecteditems()
if not selected_items:
return none, none
item = selected_items[0]
widget = self.shortcut_list.itemwidget(item)
return widget.name_label.text(), widget.path_label.text()
def open_selected_shortcut(self):
"""打开选中的快捷方式"""
name, path = self.get_selected_shortcut()
if not name:
self.show_status_message("请先选择一个快捷方式", "warning")
return
if not os.path.exists(path):
self.show_status_message(f"路径不存在: {path}", "error")
return
try:
if platform.system() == "windows":
if os.path.isdir(path):
os.startfile(path)
else:
os.startfile(path)
elif platform.system() == "darwin":
if os.path.isdir(path):
subprocess.run(["open", path])
else:
subprocess.run(["open", path])
else:
if os.path.isdir(path):
subprocess.run(["xdg-open", path])
else:
subprocess.run(["xdg-open", path])
self.show_status_message(f"已打开: {name}", "success")
except exception as e:
self.show_status_message(f"打开失败: {str(e)}", "error")
def delete_shortcut(self):
"""删除选中的快捷方式"""
name, path = self.get_selected_shortcut()
if not name:
self.show_status_message("请先选择一个快捷方式", "warning")
return
# 确认对话框
reply = qmessagebox.question(
self, "确认删除",
f"确定要删除快捷方式 '{name}' 吗?",
qmessagebox.yes | qmessagebox.no,
qmessagebox.no
)
if reply == qmessagebox.yes:
del self.shortcuts[name]
if self.save_shortcuts():
self.refresh_shortcut_list()
self.show_status_message(f"已删除快捷方式: {name}", "success")
def create_desktop_shortcut(self):
"""创建选中的快捷方式到桌面"""
name, path = self.get_selected_shortcut()
if not name:
self.show_status_message("请先选择一个快捷方式", "warning")
return
if not os.path.exists(path):
self.show_status_message(f"路径不存在: {path}", "error")
return
desktop_path = os.path.join(os.path.expanduser("~"), "desktop")
try:
if platform.system() == "windows":
try:
import winshell
shortcut_path = os.path.join(desktop_path, f"{name}.lnk")
winshell.createshortcut(
path=shortcut_path,
target=path,
description=f"快捷方式到 {name}",
icon=(path, 0)
)
except importerror:
self.show_status_message("需要安装winshell库: pip install winshell", "error")
return
elif platform.system() == "darwin":
# macos 创建替身
shortcut_path = os.path.join(desktop_path, name)
os.symlink(path, shortcut_path)
else:
# linux 创建.desktop文件
shortcut_path = os.path.join(desktop_path, f"{name}.desktop")
icon_path = path if os.path.isfile(path) else "system-file-manager"
desktop_file = f"""[desktop entry]
version=1.0
type=application
name={name}
exec={path}
icon={icon_path}
terminal=false
"""
with open(shortcut_path, "w") as f:
f.write(desktop_file)
os.chmod(shortcut_path, 0o755)
self.show_status_message(f"已在桌面创建快捷方式: {name}", "success")
except exception as e:
self.show_status_message(f"创建快捷方式失败: {str(e)}", "error")
def show_about(self):
"""显示关于对话框"""
theme = self.get_current_theme()
about_box = qmessagebox(self)
about_box.setwindowtitle("ℹ️ 关于")
about_box.settext("""
<h2>🚀 桌面快捷方式管理器</h2>
<p>版本 2.0</p>
<p>一个美观实用的快捷方式管理工具</p>
<p>使用 pyqt5 和 emoji 构建</p>
<p>© 2025 版权所有 创客白泽</p>
""")
# 设置样式
about_box.setstylesheet(f"""
qmessagebox {{
background-color: {theme['secondary']};
color: {theme['foreground']};
}}
qlabel {{
color: {theme['foreground']};
}}
qpushbutton {{
background-color: {theme['primary']};
color: {theme['foreground']};
border-radius: {theme['button_radius']};
padding: 8px;
min-width: 80px;
}}
qpushbutton:hover {{
background-color: {theme['highlight']};
}}
""")
about_box.exec_()
if __name__ == "__main__":
app = qapplication(sys.argv)
# 设置应用程序图标
if platform.system() == "windows":
import ctypes
myappid = "desktop.shortcut.manager.2.0"
ctypes.windll.shell32.setcurrentprocessexplicitappusermodelid(myappid)
# 创建并显示主窗口
window = desktopshortcutmanager()
window.show()
sys.exit(app.exec_())
总结
本项目通过pyqt5实现了:
- 现代化ui设计:卡片布局+动画+多主题
- 完整功能闭环:增删改查快捷方式
- 跨平台兼容:适配三大操作系统
- 用户体验优化:状态提示、emoji图标
扩展建议:
- 增加云同步功能
- 支持快捷键操作
- 添加分类标签系统
到此这篇关于python+pyqt5打造炫酷的桌面快捷方式管理器的文章就介绍到这了,更多相关python快捷方式管理器内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论