import os
import sys
import json
import shutil
import threading
import winreg
import ctypes
from PIL import Image, ImageTk
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from ctypes import wintypes
# 启用Windows 10/11的亚克力效果
if sys.platform == 'win32':
try:
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
DWMWA_WINDOW_CORNER_PREFERENCE = 33
DWMWA_SYSTEMBACKDROP_TYPE = 38
# Windows 11的背景效果类型
class BackdropType:
DWMSBT_DISABLE = 1 # 无特效
DWMSBT_MAINWINDOW = 2 # 云母效果
DWMSBT_TRANSIENTWINDOW = 3 # 亚克力效果
DWMSBT_TABBEDWINDOW = 4 # 标签页效果
# 设置窗口特效
def set_window_effect(hwnd, effect_type):
if not hasattr(ctypes, "windll"):
return
try:
dwm = ctypes.windll.dwmapi
value = ctypes.c_int(effect_type)
dwm.DwmSetWindowAttribute(
wintypes.HWND(hwnd),
DWMWA_SYSTEMBACKDROP_TYPE,
ctypes.byref(value),
ctypes.sizeof(value)
)
except Exception as e:
print(f"设置窗口特效失败: {e}")
# 设置深色模式
def set_dark_mode(hwnd):
if not hasattr(ctypes, "windll"):
return
try:
dwm = ctypes.windll.dwmapi
value = ctypes.c_int(1) # 深色模式
dwm.DwmSetWindowAttribute(
wintypes.HWND(hwnd),
DWMWA_USE_IMMERSIVE_DARK_MODE,
ctypes.byref(value),
ctypes.sizeof(value)
)
except Exception as e:
print(f"设置深色模式失败: {e}")
except Exception as e:
print(f"初始化Windows特效失败: {e}")
class DesktopGrid:
"""表示桌面上的一个整理格子"""
def __init__(self, canvas, x, y, size, color, index, target_dir):
self.canvas = canvas
self.x = x
self.y = y
self.size = size
self.color = color
self.index = index
self.target_dir = target_dir
self.files = []
self.selected = False
self.drag_start = None
self.hovered = False
# 创建圆角矩形
self.rect = self.create_rounded_rectangle(
x, y, x+size, y+size, radius=15,
fill=color, outline="#FFFFFF", width=1,
alpha=180 # 70% 透明度
)
# 创建标签
self.label = canvas.create_text(
x + size/2, y + size/2,
text=f"格子 {index}",
fill="white",
font=("Segoe UI", 11, "bold"),
anchor=tk.CENTER
)
# 绑定事件
self.canvas.tag_bind(self.rect, "<ButtonPress-1>", self.on_press)
self.canvas.tag_bind(self.rect, "<B1-Motion>", self.on_drag)
self.canvas.tag_bind(self.rect, "<ButtonRelease-1>", self.on_release)
self.canvas.tag_bind(self.rect, "<Enter>", self.on_enter)
self.canvas.tag_bind(self.rect, "<Leave>", self.on_leave)
# 确保目标目录存在
os.makedirs(target_dir, exist_ok=True)
def create_rounded_rectangle(self, x1, y1, x2, y2, radius=25, **kwargs):
"""创建圆角矩形(支持半透明)"""
# 创建透明图像作为纹理
alpha = kwargs.pop('alpha', 255)
fill = kwargs.pop('fill', '#FFFFFF')
# 创建圆角矩形图像
image = Image.new('RGBA', (self.size, self.size), (0, 0, 0, 0))
pixels = image.load()
# 计算圆角
for y in range(self.size):
for x in range(self.size):
# 检查是否在圆角范围内
dist_x = min(x, self.size - x - 1)
dist_y = min(y, self.size - y - 1)
# 计算到最近角的距离
if dist_x < radius and dist_y < radius:
dist = ((radius - dist_x) ** 2 + (radius - dist_y) ** 2) ** 0.5
if dist > radius:
continue
# 设置像素颜色(带透明度)
r, g, b = int(fill[1:3], 16), int(fill[3:5], 16), int(fill[5:7], 16)
pixels[x, y] = (r, g, b, alpha)
# 转换为Tkinter图像
self.tk_image = ImageTk.PhotoImage(image)
return self.canvas.create_image(
x1 + self.size/2, y1 + self.size/2,
image=self.tk_image,
tags="grid"
)
def on_press(self, event):
"""鼠标按下事件"""
self.drag_start = (event.x, event.y)
self.selected = True
self.canvas.tag_raise(self.rect)
self.canvas.tag_raise(self.label)
self.update_appearance()
def on_drag(self, event):
"""拖动事件"""
if self.drag_start:
dx = event.x - self.drag_start[0]
dy = event.y - self.drag_start[1]
self.canvas.move(self.rect, dx, dy)
self.canvas.move(self.label, dx, dy)
self.x += dx
self.y += dy
self.drag_start = (event.x, event.y)
# 检查是否需要吸附到其他格子
self.check_snap()
def check_snap(self):
"""检查并执行吸附到其他格子"""
snap_threshold = 20 # 吸附阈值
for grid in self.canvas.grids:
if grid != self:
# 水平吸附
if abs(self.x - grid.x) < snap_threshold:
self.x = grid.x
# 垂直吸附
if abs(self.y - grid.y) < snap_threshold:
self.y = grid.y
# 更新位置
self.canvas.coords(self.rect, self.x, self.y)
self.canvas.coords(self.label, self.x + self.size/2, self.y + self.size/2)
def on_release(self, event):
"""鼠标释放事件"""
self.drag_start = None
self.update_appearance()
def on_enter(self, event):
"""鼠标进入事件"""
self.hovered = True
self.update_appearance()
def on_leave(self, event):
"""鼠标离开事件"""
self.hovered = False
self.update_appearance()
def update_appearance(self):
"""更新格子的外观(悬停/选中状态)"""
if self.selected:
# 选中状态 - 更亮的颜色
self.canvas.itemconfig(
self.rect,
image=self.create_highlighted_image(self.color, 220)
)
elif self.hovered:
# 悬停状态 - 稍亮的颜色
self.canvas.itemconfig(
self.rect,
image=self.create_highlighted_image(self.color, 200)
)
else:
# 正常状态
self.canvas.itemconfig(
self.rect,
image=self.create_normal_image(self.color)
)
def create_normal_image(self, color):
"""创建正常状态的图像"""
return self.create_rounded_rectangle(
self.x, self.y, self.x+self.size, self.y+self.size,
radius=15, fill=color, alpha=180
)
def create_highlighted_image(self, color, alpha):
"""创建高亮状态的图像"""
# 计算高亮颜色(增加亮度)
r = min(255, int(int(color[1:3], 16) * 1.2))
g = min(255, int(int(color[3:5], 16) * 1.2))
b = min(255, int(int(color[5:7], 16) * 1.2))
new_color = f"#{r:02x}{g:02x}{b:02x}"
return self.create_rounded_rectangle(
self.x, self.y, self.x+self.size, self.y+self.size,
radius=15, fill=new_color, alpha=alpha
)
def add_file(self, file_path):
"""添加文件到格子"""
try:
# 移动文件到目标目录
filename = os.path.basename(file_path)
dest_path = os.path.join(self.target_dir, filename)
# 避免覆盖同名文件
counter = 1
base_name, ext = os.path.splitext(filename)
while os.path.exists(dest_path):
new_filename = f"{base_name}_{counter}{ext}"
dest_path = os.path.join(self.target_dir, new_filename)
counter += 1
shutil.move(file_path, dest_path)
self.files.append(dest_path)
# 更新标签显示文件名
display_name = filename if len(filename) < 15 else filename[:12] + "..."
self.canvas.itemconfig(
self.label,
text=f"格子 {self.index}\n{display_name}"
)
return True
except Exception as e:
messagebox.showerror("错误", f"添加文件失败: {str(e)}")
return False
class DesktopOrganizerApp:
def __init__(self, root):
self.root = root
self.root.title("高级桌面整理工具")
self.root.geometry("1000x700+200+100")
# 设置深色背景作为基础
self.root.configure(bg='#2B2B2B')
# 设置Windows特效
if sys.platform == 'win32':
try:
# 获取窗口句柄
hwnd = ctypes.windll.user32.GetParent(root.winfo_id())
# 设置深色模式
set_dark_mode(hwnd)
# 设置云母效果
set_window_effect(hwnd, BackdropType.DWMSBT_MAINWINDOW)
except Exception as e:
print(f"设置Windows特效失败: {e}")
# 回退方案:设置半透明背景
self.root.attributes('-alpha', 0.95)
# 修复:使用有效的背景色
self.canvas = tk.Canvas(
root,
bg='#2B2B2B', # 使用深灰色背景
highlightthickness=0
)
self.canvas.pack(fill=tk.BOTH, expand=True)
self.canvas.grids = [] # 存储所有格子
# 初始格子布局
self.grid_colors = [
'#FF6B6B', '#4ECDC4', '#FFE66D', '#1A535C', '#FF9F1C'
]
# 创建初始格子
self.create_initial_grids()
# 右键菜单
self.context_menu = tk.Menu(root, tearoff=0, bg='#3C3C3C', fg='white')
self.context_menu.add_command(
label="添加新格子",
command=self.add_new_grid,
background='#3C3C3C',
foreground='white'
)
self.context_menu.add_command(
label="删除选中格子",
command=self.delete_selected_grid,
background='#3C3C3C',
foreground='white'
)
self.context_menu.add_command(
label="添加文件",
command=self.add_files_to_grid,
background='#3C3C3C',
foreground='white'
)
self.context_menu.add_separator()
self.context_menu.add_command(
label="保存布局",
command=self.save_layout,
background='#3C3C3C',
foreground='white'
)
self.context_menu.add_command(
label="加载布局",
command=self.load_layout,
background='#3C3C3C',
foreground='white'
)
self.context_menu.add_separator()
self.context_menu.add_command(
label="退出",
command=root.destroy,
background='#3C3C3C',
foreground='white'
)
# 绑定事件
self.root.bind("<Button-3>", self.show_context_menu)
self.root.bind("<Control-n>", lambda e: self.add_new_grid())
self.root.bind("<Delete>", lambda e: self.delete_selected_grid())
self.root.bind("<Control-s>", lambda e: self.save_layout())
self.root.bind("<Control-o>", lambda e: self.load_layout())
# 状态栏
self.status_var = tk.StringVar()
self.status_var.set("就绪 | 右键菜单添加文件或格子")
status_bar = ttk.Label(
root,
textvariable=self.status_var,
relief=tk.SUNKEN,
anchor=tk.W,
background='#333333',
foreground='white'
)
status_bar.pack(side=tk.BOTTOM, fill=tk.X)
# 文件监视器
self.start_file_monitor()
def create_initial_grids(self):
"""创建初始格子布局"""
grid_size = 220
positions = [
(50, 50), # 左上
(300, 50), # 右上
(50, 300), # 左下
(300, 300), # 右下
(550, 180) # 中间
]
for i, (x, y) in enumerate(positions):
color = self.grid_colors[i % len(self.grid_colors)]
target_dir = os.path.expanduser(f"~/Desktop/整理格子_{i+1}")
grid = DesktopGrid(
self.canvas, x, y, grid_size, color, i+1, target_dir
)
self.canvas.grids.append(grid)
def add_new_grid(self):
"""添加新格子"""
color = self.grid_colors[len(self.canvas.grids) % len(self.grid_colors)]
target_dir = os.path.expanduser(f"~/Desktop/整理格子_{len(self.canvas.grids)+1}")
grid = DesktopGrid(
self.canvas, 400, 300, 220, color, len(self.canvas.grids)+1, target_dir
)
self.canvas.grids.append(grid)
self.status_var.set(f"已添加新格子: {len(self.canvas.grids)}")
def delete_selected_grid(self):
"""删除选中的格子"""
for grid in self.canvas.grids[:]:
if grid.selected:
self.canvas.delete(grid.rect)
self.canvas.delete(grid.label)
self.canvas.grids.remove(grid)
self.status_var.set("已删除选中的格子")
return
self.status_var.set("没有选中的格子")
def save_layout(self):
"""保存布局到文件"""
try:
layout_data = []
for grid in self.canvas.grids:
layout_data.append({
"x": grid.x,
"y": grid.y,
"size": grid.size,
"color": grid.color,
"index": grid.index,
"target_dir": grid.target_dir
})
# 保存到用户文档目录
save_path = os.path.expanduser("~/Documents/desktop_grid_layout.json")
with open(save_path, "w") as f:
json.dump(layout_data, f, indent=4)
self.status_var.set(f"布局已保存到: {save_path}")
messagebox.showinfo("成功", f"布局已保存到: {save_path}")
except Exception as e:
messagebox.showerror("错误", f"保存失败: {str(e)}")
def load_layout(self):
"""从文件加载布局"""
try:
load_path = os.path.expanduser("~/Documents/desktop_grid_layout.json")
if not os.path.exists(load_path):
messagebox.showerror("错误", f"找不到布局文件: {load_path}")
return
with open(load_path, "r") as f:
layout_data = json.load(f)
# 清除现有格子
for grid in self.canvas.grids[:]:
self.canvas.delete(grid.rect)
self.canvas.delete(grid.label)
self.canvas.grids = []
# 创建新格子
for data in layout_data:
grid = DesktopGrid(
self.canvas,
data["x"],
data["y"],
data["size"],
data["color"],
data["index"],
data["target_dir"]
)
self.canvas.grids.append(grid)
self.status_var.set(f"已加载布局: {load_path}")
messagebox.showinfo("成功", f"已从 {load_path} 加载布局")
except Exception as e:
messagebox.showerror("错误", f"加载布局失败: {str(e)}")
def add_files_to_grid(self):
"""添加文件到选中的格子"""
selected_grid = None
for grid in self.canvas.grids:
if grid.selected:
selected_grid = grid
break
if not selected_grid:
messagebox.showwarning("警告", "请先选择一个格子")
return
file_paths = filedialog.askopenfilenames(
title="选择要添加的文件",
filetypes=[("所有文件", "*.*")]
)
if not file_paths:
return
for file_path in file_paths:
if selected_grid.add_file(file_path):
self.status_var.set(f"已添加: {os.path.basename(file_path)} -> 格子 {selected_grid.index}")
def show_context_menu(self, event):
"""显示右键菜单"""
self.context_menu.post(event.x_root, event.y_root)
def start_file_monitor(self):
"""启动文件监视器(监视桌面文件夹)"""
# 获取桌面路径
desktop_path = os.path.expanduser("~/Desktop")
# 使用线程监视桌面文件夹
threading.Thread(
target=self.monitor_desktop,
args=(desktop_path,),
daemon=True
).start()
self.status_var.set("已启动桌面文件监视器...")
def monitor_desktop(self, path):
"""监视桌面文件夹并自动整理新文件"""
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class DesktopHandler(FileSystemEventHandler):
def __init__(self, app):
self.app = app
self.last_handled = set()
self.last_event_time = 0
def on_created(self, event):
# 只处理文件(跳过目录)
if not event.is_directory:
current_time = time.time()
# 防止短时间内重复触发
if current_time - self.last_event_time < 0.5:
return
self.last_event_time = current_time
file_path = event.src_path
# 延迟处理,确保文件已完全写入
time.sleep(0.5)
# 避免重复处理
if file_path not in self.last_handled:
self.last_handled.add(file_path)
# 在新线程中整理文件
threading.Thread(
target=self.app.auto_organize_file,
args=(file_path,),
daemon=True
).start()
event_handler = DesktopHandler(self)
observer = Observer()
observer.schedule(event_handler, path, recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
def auto_organize_file(self, file_path):
"""自动整理文件到合适的格子"""
# 确保文件存在
if not os.path.exists(file_path) or os.path.isdir(file_path):
return
# 获取文件扩展名
_, ext = os.path.splitext(file_path)
ext = ext.lower()
# 根据文件类型选择格子
category = self.classify_file(ext)
# 查找对应类别的格子
target_grid = None
for grid in self.canvas.grids:
grid_category = self.classify_grid(grid)
if grid_category == category:
target_grid = grid
break
# 如果没有找到匹配的格子,使用第一个格子
if not target_grid and self.canvas.grids:
target_grid = self.canvas.grids[0]
# 添加文件
if target_grid:
if target_grid.add_file(file_path):
self.status_var.set(f"自动整理: {os.path.basename(file_path)} -> {target_grid.target_dir}")
def classify_file(self, ext):
"""根据文件扩展名分类文件"""
categories = {
'documents': ['.pdf', '.doc', '.docx', '.txt', '.xls', '.xlsx', '.ppt', '.pptx', '.rtf'],
'images': ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp', '.tiff'],
'videos': ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.mpeg'],
'music': ['.mp3', '.wav', '.flac', '.aac', '.ogg', '.m4a'],
'archives': ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2'],
'executables': ['.exe', '.msi', '.bat', '.sh'],
'code': ['.py', '.js', '.html', '.css', '.java', '.cpp', '.cs', '.php']
}
for cat, exts in categories.items():
if ext in exts:
return cat
return 'others'
def classify_grid(self, grid):
"""根据格子中的文件类型确定格子类别"""
if not grid.files:
return 'others'
# 统计格子中文件类型的分布
type_count = {}
for file_path in grid.files:
_, ext = os.path.splitext(file_path)
ext = ext.lower()
cat = self.classify_file(ext)
type_count[cat] = type_count.get(cat, 0) + 1
# 返回最常见的类型
return max(type_count, key=type_count.get)
# 创建主窗口
if __name__ == "__main__":
root = tk.Tk()
app = DesktopOrganizerApp(root)
# 设置任务栏图标
if sys.platform == 'win32':
try:
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
icon_path = os.path.join(base_path, "app_icon.ico")
root.iconbitmap(icon_path)
except:
try:
# 尝试从当前目录加载
root.iconbitmap("app_icon.ico")
except:
print("图标文件加载失败,使用默认图标")
# 启动主循环
root.mainloop()
[Running] python -u "e:\system\Desktop\项目所需文件\工具\桌面整理工具\Desktop Grid Organizer.py"
Traceback (most recent call last):
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u684c�ʐ����H��\Desktop Grid Organizer.py", line 639, in <module>
root.iconbitmap(icon_path)
File "C:\Users\cheny9210\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 2156, in wm_iconbitmap
return self.tk.call('wm', 'iconbitmap', self._w, bitmap)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_tkinter.TclError: bitmap "e:\system\Desktop\\u9879�ڏ�������\�H��\\u684c�ʐ����H��\app_icon.ico" not defined
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u684c�ʐ����H��\Desktop Grid Organizer.py", line 643, in <module>
root.iconbitmap("app_icon.ico")
File "C:\Users\cheny9210\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 2156, in wm_iconbitmap
return self.tk.call('wm', 'iconbitmap', self._w, bitmap)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_tkinter.TclError: bitmap "app_icon.ico" not defined
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "e:\system\Desktop\\u9879�ڏ�������\�H��\\u684c�ʐ����H��\Desktop Grid Organizer.py", line 645, in <module>
print("\u56fe\u6807������\u8f7d��\u8d25�C�g�p��\u8ba4\u56fe\u6807")
UnicodeEncodeError: 'cp932' codec can't encode character '\u56fe' in position 0: illegal multibyte sequence
[Done] exited with code=1 in 0.766 seconds
最新发布