'''
制作一个linux中运行的一个名叫快捷地址访问的python程序,实现点击按钮就能直达地址。用于改善统信的任务栏体验。使用tktinter,软件界面尺寸300*30不带标题栏以便尽量压缩高度以便放置在任务栏上,底色淡黄色,一键处理的按键是糖果绿色,字体:fangsong ti,字号12号。 程序开始运行时,自动置顶,优先级高于任务栏。十个空白按钮,用来打开文件夹地址,默认地址分别是 /home/huanghe/, smb://192.168.1.207/sbg, smb://192.168.1.207/, 可以修改。一个关闭,一个设置按键,点击设置按键后可以重新定义三个按钮的打开地址并保存。
'''
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import subprocess
import json
import tkinter as tk
from tkinter import messagebox
from pathlib import Path
import time
class QuickAccess:
def __init__(self, root):
self.root = root
self.root.title("快捷访问")
# 设置窗口初始大小
self.button_width = 3 # 每个按钮的基础宽度
self.control_button_width = 10
self.min_buttons = 3 # 最少按钮数
self.window_height = 30
# 配置文件路径
self.config_file = os.path.expanduser("~/.quick_access_config.json")
# 默认地址
self.default_paths = [
"/home/huanghe/",
"smb://192.168.1.207/sbg",
"smb://192.168.1.207/"
]
# 加载配置(先创建button_names和paths属性)
self.load_config()
# 现在再计算窗口大小
self.update_window_size()
self.root.overrideredirect(True) # 去掉标题栏
self.root.attributes('-type', 'normal') # 确保显示任务栏标签
self.root.configure(bg='#FFFACD') # 淡黄色背景
# 设置窗口置顶
self.root.attributes('-topmost', True)
# 创建UI
self.create_ui()
# 绑定快捷键
self.root.bind('<Control-q>', self.quit_app)
self.root.bind('<Control-Q>', self.quit_app)
# 允许自由调整大小
self.root.resizable(True, False) # 只允许水平调整
# 设置最小窗口尺寸
self.root.minsize(550, 30)
# 延迟一点点确保窗口已创建,然后定位到屏幕下沿居中偏右
self.root.after(100, self.position_window)
# 确保窗口在任务栏上方
self.root.lift()
def update_window_size(self):
"""根据按钮数量更新窗口宽度(修复强制预留宽度问题)"""
button_count = len(self.button_names)
self.window_width = max(350, button_count * self.button_width + 80) # 减少预留宽度
self.root.geometry(f"{self.window_width}x{self.window_height}")
def position_window(self):
"""启动时将窗口定位到屏幕下沿居中偏右"""
# 获取屏幕宽度和高度
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
# 获取当前窗口大小
current_width = self.root.winfo_width()
current_height = self.root.winfo_height()
# 计算任务栏高度(假设为40像素,可根据需要调整)
taskbar_height = 40
# 计算窗口位置:居中偏右(右侧留出一些空间)
x = screen_width - current_width - 350 # 距离右边10像素
y = screen_height - current_height - 1 # 任务栏上方5像素。去掉: - taskbar_height
# 设置窗口位置
self.root.geometry(f"+{x}+{y}")
def create_ui(self):
# 清除现有组件
for widget in self.root.winfo_children():
widget.destroy()
# 主框架
main_frame = tk.Frame(self.root, bg='#FFFACD')
main_frame.pack(fill=tk.BOTH, expand=True, padx=1, pady=1)
# 拆分框架:快捷按钮(拉伸) + 控制按钮(不拉伸)
btn_frame = tk.Frame(main_frame, bg='#FFFACD')
btn_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
ctrl_frame = tk.Frame(main_frame, bg='#FFFACD')
ctrl_frame.pack(side=tk.LEFT, fill=tk.BOTH)
# 按钮样式配置
button_style = {
'font': ('fangsong ti', 12),
'bg': '#F5FFF5', # 糖果绿色
'fg': 'black',
'relief': tk.RAISED,
'bd': 1,
'width': 1 # 限制宽度
}
# 创建所有快捷按钮(放在拉伸框架)
self.buttons = []
for i in range(len(self.button_names)):
btn = tk.Button(
btn_frame,
text=self.button_names[i],
command=lambda x=i: self.open_path(x),
**button_style
)
btn.pack(side=tk.LEFT, padx=1, fill=tk.BOTH, expand=True)
self.buttons.append(btn)
# 设置按钮(放在不拉伸框架)
settings_btn = tk.Button(
ctrl_frame,
text="设置",
font=('fangsong ti', 11),
bg='#FFB6C1',
fg='black',
relief=tk.RAISED,
bd=1,
width=3,
padx=0,
command=self.show_settings
)
settings_btn.pack(side=tk.LEFT, padx=0, fill=tk.BOTH)
# 开机启动按钮(放在不拉伸框架)
self.startup_btn = tk.Button(
ctrl_frame,
text="开",
font=('fangsong ti', 11),
bg='#98FB98',
fg='black',
relief=tk.RAISED,
bd=1,
width=2,
padx=0,
command=self.toggle_startup
)
self.startup_btn.pack(side=tk.LEFT, padx=0, fill=tk.BOTH)
# 关闭按钮(完全自定义宽度,无拉伸)
close_btn = tk.Button(
ctrl_frame,
text="✕",
font=('fangsong ti', 11),
bg='#F5fff4',
fg='black',
relief=tk.RAISED,
bd=1,
width=1, # 独立控制宽度,不会被覆盖
padx=2,
pady=0,
command=self.quit_app
)
close_btn.pack(side=tk.LEFT, padx=0, fill=tk.BOTH)
# 更新开机启动按钮状态
self.update_startup_button()
def load_config(self):
"""加载配置文件"""
try:
if os.path.exists(self.config_file):
with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
self.button_names = config.get('names', ["键1", "键2", "键3"])
self.paths = config.get('paths', self.default_paths.copy())
else:
self.button_names = ["键1", "键2", "键3"]
self.paths = self.default_paths.copy()
except Exception as e:
print(f"加载配置失败: {e}")
self.button_names = ["键1", "键2", "键3"]
self.paths = self.default_paths.copy()
def save_config(self):
"""保存配置"""
try:
config = {
'paths': self.paths,
'names': self.button_names
}
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
except Exception as e:
messagebox.showerror("错误", f"保存配置失败: {e}")
def open_path(self, index):
"""打开指定路径(最大化窗口)"""
if index >= len(self.paths):
return
path = self.paths[index]
try:
# 方法1: 使用dbus发送最大化命令(统信专用)
if path.startswith("smb://"):
# 对于SMB路径,直接打开
subprocess.Popen(["dde-file-manager", path])
else:
# 对于本地路径,先检查/创建目录
if not os.path.exists(path):
try:
os.makedirs(path, exist_ok=True)
except:
pass
# 使用dde-file-manager打开
subprocess.Popen(["dde-file-manager", path])
# 等待一下让文件管理器启动
time.sleep(0.5)
# 方法2: 使用wmctrl最大化窗口(如果安装了wmctrl)
try:
# 获取最近打开的文件管理器窗口并最大化
result = subprocess.run(["wmctrl", "-l"], capture_output=True, text=True)
if "dde-file-manager" in result.stdout.lower() or "文件管理器" in result.stdout:
# 找到最新的文件管理器窗口
lines = result.stdout.strip().split('\n')
for line in reversed(lines):
if "dde-file-manager" in line.lower() or "文件管理器" in line:
window_id = line.split()[0]
subprocess.run(["wmctrl", "-i", "-r", window_id, "-b", "add,maximized_vert,maximized_horz"])
break
except:
pass # 如果没有wmctrl,忽略最大化操作
except Exception as e:
# 如果都失败了,尝试最简单的打开方式
try:
if path.startswith("smb://"):
subprocess.Popen(["dde-file-manager", path])
else:
subprocess.Popen(["xdg-open", path]) # 使用xdg-open作为备选
except:
messagebox.showerror("错误", f"打开失败: {e}")
def show_settings(self):
"""显示设置对话框"""
settings_window = tk.Toplevel(self.root)
settings_window.title("设置")
settings_window.geometry("1000x500")
settings_window.configure(bg='#FFFACD')
settings_window.transient(self.root)
settings_window.grab_set()
# 设置窗口位置居中
settings_window.update_idletasks()
x = (settings_window.winfo_screenwidth() // 2) - (700 // 2)
y = (settings_window.winfo_screenheight() // 2) - (500 // 2)
settings_window.geometry(f"+{x}+{y}")
# 标题
title_label = tk.Label(
settings_window,
text="快捷访问设置",
font=('fangsong ti', 14, 'bold'),
bg='#FFFACD'
)
title_label.pack(pady=10)
# 创建可滚动的设置区域
canvas = tk.Canvas(settings_window, bg='#FFFACD', highlightthickness=0)
scrollbar = tk.Scrollbar(settings_window, orient="vertical", command=canvas.yview)
scrollable_frame = tk.Frame(canvas, bg='#FFFACD')
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
)
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
# 存储输入框的列表
entries = []
def add_button_row():
"""添加新的按钮行"""
i = len(entries)
# 创建一个框架来容纳整行
row_frame = tk.Frame(scrollable_frame, bg='#FFFACD')
row_frame.pack(fill=tk.X, padx=5, pady=1)
# 按钮编号
num_label = tk.Label(
row_frame,
text=f"{i + 1}.",
font=('fangsong ti', 12, 'bold'),
bg='#FFFACD',
width=1
)
num_label.pack(side=tk.LEFT, padx=1)
# 名称输入框
name_entry = tk.Entry(row_frame, font=('fangsong ti', 12), width=8)
name_entry.pack(side=tk.LEFT, padx=1)
if i < len(self.button_names):
name_entry.insert(0, self.button_names[i])
else:
name_entry.insert(0, f"键{i + 1}")
# 路径输入框
path_entry = tk.Entry(row_frame, font=('fangsong ti', 12), width=50)
path_entry.pack(side=tk.LEFT, padx=1, fill=tk.X, expand=True)
if i < len(self.paths):
path_entry.insert(0, self.paths[i])
# 删除按钮(只有超过3个的按钮才能删除)
if i >= 3:
delete_btn = tk.Button(
row_frame,
text="删除",
font=('fangsong ti', 10),
bg='#FF6B6B',
fg='white',
width=4,
command=lambda frame=row_frame, idx=i: delete_row(frame, idx)
)
delete_btn.pack(side=tk.RIGHT, padx=1)
entries.append((name_entry, path_entry, row_frame))
def delete_row(frame, index):
"""删除指定行"""
if len(entries) <= 3:
messagebox.showwarning("警告", "至少保留3个按钮")
return
# 从列表中移除
for i, (_, _, f) in enumerate(entries):
if f == frame:
entries.pop(i)
break
# 销毁框架
frame.destroy()
# 重新编号所有行的标签
for i, (name_entry, path_entry, row_frame) in enumerate(entries):
# 更新行的编号
for child in row_frame.winfo_children():
if isinstance(child, tk.Label) and child.cget('text').endswith('.'):
child.config(text=f"{i + 1}.")
break
# 创建现有的所有按钮行
max_count = max(len(self.button_names), len(self.paths), 3)
for i in range(max_count):
add_button_row()
canvas.pack(side="left", fill="both", expand=True, padx=(5, 0))
scrollbar.pack(side="right", fill="y")
# 按钮框架
button_frame = tk.Frame(settings_window, bg='#FFFACD')
button_frame.pack(fill=tk.X, pady=10)
# 添加按钮
add_btn = tk.Button(
button_frame,
text="添加",
font=('fangsong ti', 12),
bg='#98FB98',
command=lambda: [add_button_row(), settings_window.update_idletasks()]
)
add_btn.pack(side=tk.LEFT, padx=5)
# 保存按钮
def save_settings():
new_names = []
new_paths = []
for name_entry, path_entry, _ in entries:
name = name_entry.get().strip()
path = path_entry.get().strip()
if name:
new_names.append(name[:5]) # 限制长度为5
else:
new_names.append(f"键{len(new_names) + 1}")
new_paths.append(path if path else "")
self.button_names = new_names
self.paths = new_paths
self.save_config()
# 更新窗口大小
self.update_window_size()
# 重建UI
self.create_ui()
settings_window.destroy()
messagebox.showinfo("成功", f"已保存 {len(new_names)} 个按钮")
save_btn = tk.Button(
button_frame,
text="保存",
font=('fangsong ti', 12),
bg='#98FB98',
command=save_settings
)
save_btn.pack(side=tk.LEFT, padx=8)
# 取消按钮
cancel_btn = tk.Button(
button_frame,
text="取消",
font=('fangsong ti', 12),
bg='#FFB6C1',
command=settings_window.destroy
)
cancel_btn.pack(side=tk.LEFT, padx=8)
def toggle_startup(self):
"""切换开机启动状态"""
autostart_dir = os.path.expanduser("~/.config/autostart")
desktop_file = os.path.join(autostart_dir, "quick-access.desktop")
try:
if os.path.exists(desktop_file):
os.remove(desktop_file)
else:
os.makedirs(autostart_dir, exist_ok=True)
script_path = os.path.abspath(__file__)
desktop_content = f"""[Desktop Entry]
Type=Application
Name=快捷访问
Exec=python3 {script_path}
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Icon=system-file-manager
Comment=快捷访问文件夹工具
"""
with open(desktop_file, 'w', encoding='utf-8') as f:
f.write(desktop_content)
self.update_startup_button()
except Exception as e:
messagebox.showerror("错误", f"设置开机启动失败: {e}")
def update_startup_button(self):
"""更新开机启动按钮状态"""
autostart_file = os.path.expanduser("~/.config/autostart/quick-access.desktop")
if os.path.exists(autostart_file):
self.startup_btn.config(text="关", bg='#FF6B6B')
else:
self.startup_btn.config(text="开", bg='#98FB98')
def quit_app(self, event=None):
"""退出程序"""
self.root.quit()
self.root.destroy()
def main():
root = tk.Tk()
app = QuickAccess(root)
# 添加窗口拖动功能(点击背景拖动)
def start_move(event):
app.x = event.x
app.y = event.y
def stop_move(event):
app.x = None
app.y = None
def do_move(event):
if hasattr(app, 'x') and hasattr(app, 'y'):
deltax = event.x - app.x
deltay = event.y - app.y
x = root.winfo_x() + deltax
y = root.winfo_y() + deltay
root.geometry(f"+{x}+{y}")
# 绑定拖动事件到整个窗口背景
root.bind('<Button-1>', start_move)
root.bind('<ButtonRelease-1>', stop_move)
root.bind('<B1-Motion>', do_move)
# 防止按钮点击触发拖动
def on_button_press(event):
return
for widget in root.winfo_children():
widget.bind('<Button-1>', on_button_press, '+')
root.mainloop()
if __name__ == "__main__":
main()
统信小程序(十一)快捷地址栏
hnxaoli2026-03-25 15:38
相关推荐
weixin_421922692 小时前
机器学习模型部署:将模型转化为Web APItwc8292 小时前
Query 改写 大模型测试的数据倍增器Fortune792 小时前
Python迭代器(Iterator)揭秘:for循环背后的故事cm6543202 小时前
Python字典与集合:高效数据管理的艺术2401_846341652 小时前
Python单元测试(unittest)实战指南CQU_JIAKE2 小时前
3.23[Q]s黄昏晓x2 小时前
Linux----网络小比特_蓝光2 小时前
Linux开发工具大熊背2 小时前
ISP离线模式应用(二)-如何利用 ISP 离线模式 加速 3DNR 收敛