基于Python編寫(xiě)一個(gè)win10桌面便簽工具
Python的GUI(圖形用戶界面)庫(kù)Tkinter是Python標(biāo)準(zhǔn)庫(kù)的一部分,用于創(chuàng)建桌面應(yīng)用程序。"Python GUI Win10 便貼"項(xiàng)目就是利用Tkinter來(lái)模仿Windows 10操作系統(tǒng)中的便簽功能,提供了類似的功能,讓用戶可以在桌面上創(chuàng)建、編輯和管理文本小記。
Tkinter庫(kù)提供了豐富的控件和布局管理器,使得開(kāi)發(fā)者可以輕松構(gòu)建具有窗口、按鈕、文本框等元素的應(yīng)用程序。在"Python tkinter GUI Windows10 sticky note"這個(gè)項(xiàng)目中,開(kāi)發(fā)者可能使用了Tkinter的`Tk`類來(lái)創(chuàng)建主窗口,`Label`控件來(lái)顯示文本,`Text`控件來(lái)實(shí)現(xiàn)可編輯的便簽內(nèi)容,并可能使用了`Button`控件來(lái)添加、保存或刪除便簽。
在設(shè)計(jì)這樣一個(gè)GUI應(yīng)用時(shí),開(kāi)發(fā)者可能考慮了以下幾點(diǎn):
1. 用戶交互:通過(guò)點(diǎn)擊按鈕或者使用快捷鍵來(lái)實(shí)現(xiàn)新建、編輯、保存、刪除等功能。
2. 數(shù)據(jù)持久化:為了保存用戶的便簽內(nèi)容,開(kāi)發(fā)者可能使用了文件存儲(chǔ)(如JSON或pickle格式)或數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)數(shù)據(jù),確保即使程序關(guān)閉后,便簽內(nèi)容也不會(huì)丟失。
3. 界面設(shè)計(jì):模仿Windows 10的風(fēng)格,包括顏色、字體、圖標(biāo)等,以提供一致的用戶體驗(yàn)。
4. 窗口管理:利用Tkinter的`geometry`方法調(diào)整窗口大小和位置,允許用戶自由拖動(dòng)和調(diào)整大小。
5. 事件綁定:使用`bind`函數(shù)監(jiān)聽(tīng)鍵盤(pán)和鼠標(biāo)事件,響應(yīng)用戶的操作。
6. 多個(gè)便簽管理:如果程序支持創(chuàng)建多個(gè)便簽,可能使用列表或其他容器結(jié)構(gòu)來(lái)存儲(chǔ)每個(gè)便簽對(duì)象。
在實(shí)際使用中,用戶可以通過(guò)這個(gè)Python實(shí)現(xiàn)的"Win10 便貼"輕松記錄日?,嵤隆⒋k事項(xiàng)或者靈感,享受與Windows 10系統(tǒng)一致的便利體驗(yàn),同時(shí)得益于Python和Tkinter的易用性,開(kāi)發(fā)者可以快速實(shí)現(xiàn)和定制自己的需求。
以下是完整代碼
可以拿去自己生成小程序
import tkinter as tk
from tkinter import colorchooser, font, messagebox, simpledialog
import json
import os
from pathlib import Path
from datetime import datetime
# 常量定義(便于維護(hù))
DEFAULT_PASSWORD = "123456"
MIN_WIDTH = 200
MIN_HEIGHT = 150
AUTO_SAVE_INTERVAL = 5000 # 5秒自動(dòng)保存
PURE_MODE_DELAY = 10000 # 10秒進(jìn)入純凈模式
CONFIG_FILE = Path.home() / "sticky_note_config.json" # 保存到用戶目錄
CONTENT_FILE = Path.home() / "sticky_note_content.txt"
PASSWORD_FILE = Path.home() / "sticky_note_pwd.json"
class BorderlessStickyNote:
def __init__(self, root):
self.root = root
self.root.title("極簡(jiǎn)便簽")
self.root.geometry("400x500+100+100")
# 核心狀態(tài)變量
self.root.overrideredirect(True) # 移除窗口裝飾
self.resizing = False
self.moving = False
self._drag_data = {"x": 0, "y": 0}
self.hide_timer = None
# 樣式配置
self.current_font_family = "Microsoft YaHei"
self.current_font_size = 14
self.current_font_color = "#2C3E50"
self.current_bg_color = "#FFFEF0"
self.current_alpha = 0.95
self.is_topmost = True
# 密碼配置
self.close_password = self.load_password()
# 初始化UI
self.root.attributes('-topmost', self.is_topmost)
self.root.attributes('-alpha', self.current_alpha)
self.load_config() # 加載配置(覆蓋默認(rèn)值)
self.create_ui()
self.create_context_menu()
self.bind_events()
self.load_content()
# 啟動(dòng)定時(shí)任務(wù)
self.schedule_pure_mode()
self.schedule_auto_save()
def create_ui(self):
"""創(chuàng)建界面(優(yōu)化布局和初始提示)"""
# 主容器(調(diào)整大小邊框)
self.main_container = tk.Frame(self.root, bg="#CCCCCC", cursor="arrow")
self.main_container.pack(fill=tk.BOTH, expand=True)
# 內(nèi)容區(qū)域
self.main_frame = tk.Frame(self.main_container, bg=self.current_bg_color, bd=0)
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=1, pady=1)
# 文本編輯區(qū)(增加初始提示)
self.text_area = tk.Text(
self.main_frame,
wrap=tk.WORD,
font=(self.current_font_family, self.current_font_size),
fg=self.current_font_color,
bg=self.current_bg_color,
padx=20,
pady=20,
undo=True,
maxundo=50, # 增加撤銷次數(shù)
relief=tk.FLAT,
highlightthickness=0,
insertbackground=self.current_font_color,
selectbackground="#3498DB",
selectforeground="white",
spacing1=3,
spacing3=3,
borderwidth=0
)
self.text_area.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
# 初始提示文字
if not os.path.exists(CONTENT_FILE) or os.path.getsize(CONTENT_FILE) == 0:
self.text_area.insert("1.0",
"? 歡迎使用極簡(jiǎn)便簽\n\n- 右鍵可打開(kāi)功能菜單\n- Alt+左鍵拖動(dòng)移動(dòng)窗口\n- 邊緣/角落拖動(dòng)調(diào)整大小\n- Ctrl+滾輪調(diào)整字號(hào)")
self.text_area.tag_add("hint", "1.0", "5.0")
self.text_area.tag_config("hint", foreground="#999999")
def create_context_menu(self):
"""創(chuàng)建優(yōu)化后的右鍵菜單(修復(fù)勾選狀態(tài)、新增功能)"""
# 置頂狀態(tài)變量(持久化)
self.topmost_var = tk.BooleanVar(value=self.is_topmost)
self.menu = tk.Menu(self.root, tearoff=0, bg="white", fg="#333",
activebackground="#E0E0E0", font=("Microsoft YaHei", 10))
# 窗口控制(優(yōu)化)
self.menu.add_command(label="??? 移動(dòng)窗口", command=self.start_move_mode)
self.menu.add_command(label="?? 最小化窗口", command=self.minimize_window)
self.menu.add_checkbutton(
label="?? 窗口置頂",
variable=self.topmost_var,
command=self.toggle_topmost
)
self.menu.add_separator()
# 字體設(shè)置(新增字體家族選擇)
font_menu = tk.Menu(self.menu, tearoff=0, bg="white")
# 字體家族子菜單
family_menu = tk.Menu(font_menu, tearoff=0, bg="white")
common_fonts = ["Microsoft YaHei", "SimSun", "SimHei", "KaiTi", "Arial", "Times New Roman"]
for f in common_fonts:
family_menu.add_command(
label=f" {f} {'?' if f == self.current_font_family else ''}",
command=lambda fm=f: self.set_font_family(fm)
)
font_menu.add_cascade(label="字體家族", menu=family_menu)
# 字體大小子菜單
size_menu = tk.Menu(font_menu, tearoff=0, bg="white")
for size in [10, 12, 14, 16, 18, 20, 24, 28, 32]:
size_menu.add_command(
label=f" {size}px {'?' if size == self.current_font_size else ''}",
command=lambda s=size: self.set_font_size(s)
)
font_menu.add_cascade(label="字體大小", menu=size_menu)
self.menu.add_cascade(label="?? 字體設(shè)置", menu=font_menu)
# 樣式設(shè)置
self.menu.add_command(label="?? 文字顏色", command=self.choose_color)
self.menu.add_command(label="??? 背景顏色", command=self.choose_bg_color)
# 透明度(優(yōu)化顯示)
alpha_menu = tk.Menu(self.menu, tearoff=0, bg="white")
alpha_levels = [
(0.3, "30% 透視"),
(0.5, "50% 半透明"),
(0.7, "70% 輕薄"),
(0.85, "85% 淡雅"),
(0.95, "95% 默認(rèn)"),
(1.0, "100% 不透明")
]
for alpha_val, label_text in alpha_levels:
alpha_menu.add_command(
label=f" {label_text} {'?' if abs(alpha_val - self.current_alpha) < 0.01 else ''}",
command=lambda a=alpha_val: self.set_alpha(a)
)
self.menu.add_cascade(label="??? 背景透明度", menu=alpha_menu)
self.menu.add_separator()
# 編輯功能(綁定快捷鍵)
self.menu.add_command(label="?? 加粗 (Ctrl+B)", command=self.toggle_bold)
self.menu.add_command(label="?? 撤銷 (Ctrl+Z)", command=lambda: self.text_area.edit_undo())
self.menu.add_command(label="?? 重做 (Ctrl+Y)", command=lambda: self.text_area.edit_redo())
self.menu.add_separator()
self.menu.add_command(label="全選 (Ctrl+A)", command=self.select_all)
self.menu.add_command(label="復(fù)制 (Ctrl+C)", command=self.copy_text)
self.menu.add_command(label="粘貼 (Ctrl+V)", command=self.paste_text)
self.menu.add_separator()
# 高級(jí)功能
self.menu.add_command(label="?? 清空內(nèi)容", command=self.clear_text, foreground="#E74C3C")
self.menu.add_command(label="?? 修改關(guān)閉密碼", command=self.change_password)
self.menu.add_command(label="?? 關(guān)于", command=self.show_about)
self.menu.add_separator()
# 退出(優(yōu)化提示)
self.menu.add_command(label="?? 退出程序 (Alt+F4/Ctrl+Q)", command=self.on_closing,
foreground="#C0392B")
# -------------------------- 核心功能:修復(fù)調(diào)整大小 --------------------------
def check_resize_cursor(self, event):
"""優(yōu)化:擴(kuò)大邊緣檢測(cè)區(qū)域(20px),覆蓋所有邊緣,光標(biāo)樣式更精準(zhǔn)"""
width = self.main_container.winfo_width()
height = self.main_container.winfo_height()
x, y = event.x, event.y
edge_size = 20 # 擴(kuò)大檢測(cè)區(qū)域,提升易用性
# 檢測(cè)各邊緣
is_left = x < edge_size
is_right = width - x < edge_size
is_top = y < edge_size
is_bottom = height - y < edge_size
# 按優(yōu)先級(jí)設(shè)置光標(biāo)
if is_left and is_top:
self.main_container.config(cursor="size_nw_se")
elif is_left and is_bottom:
self.main_container.config(cursor="size_ne_sw")
elif is_right and is_top:
self.main_container.config(cursor="size_ne_sw")
elif is_right and is_bottom:
self.main_container.config(cursor="size_nw_se")
elif is_left or is_right:
self.main_container.config(cursor="sb_h_double_arrow")
elif is_top or is_bottom:
self.main_container.config(cursor="sb_v_double_arrow")
else:
self.main_container.config(cursor="arrow")
def start_resize(self, event):
"""修復(fù):記錄完整初始狀態(tài),明確邊緣類型,避免計(jì)算偏差"""
width = self.main_container.winfo_width()
height = self.main_container.winfo_height()
x, y = event.x, event.y
edge_size = 20
# 僅在邊緣區(qū)域啟動(dòng)調(diào)整
if not (x < edge_size or width - x < edge_size or y < edge_size or height - y < edge_size):
return
self.resizing = True
self._resize_start = {
"start_x": event.x_root, # 記錄鼠標(biāo)絕對(duì)位置,避免容器偏移影響
"start_y": event.y_root,
"init_width": self.root.winfo_width(),
"init_height": self.root.winfo_height(),
"init_x": self.root.winfo_x(), # 記錄窗口初始位置,支持左上邊緣調(diào)整
"init_y": self.root.winfo_y(),
"edge": self._get_resize_edge(x, y, width, height, edge_size)
}
def _get_resize_edge(self, x, y, width, height, edge_size):
"""輔助函數(shù):判斷調(diào)整的邊緣類型"""
is_left = x < edge_size
is_right = width - x < edge_size
is_top = y < edge_size
is_bottom = height - y < edge_size
if is_left and is_top:
return "top_left"
elif is_left and is_bottom:
return "bottom_left"
elif is_right and is_top:
return "top_right"
elif is_right and is_bottom:
return "bottom_right"
elif is_left:
return "left"
elif is_right:
return "right"
elif is_top:
return "top"
elif is_bottom:
return "bottom"
return None
def do_resize(self, event):
"""修復(fù):基于初始狀態(tài)計(jì)算尺寸,支持所有邊緣調(diào)整,限制最小尺寸"""
if not self.resizing or not hasattr(self, "_resize_start"):
return
start = self._resize_start
delta_x = event.x_root - start["start_x"]
delta_y = event.y_root - start["start_y"]
min_w, min_h = MIN_WIDTH, MIN_HEIGHT # 最小尺寸
# 根據(jù)邊緣類型計(jì)算新尺寸和位置
if start["edge"] == "right":
new_w = max(min_w, start["init_width"] + delta_x)
self.root.geometry(f"{int(new_w)}x{self.root.winfo_height()}")
elif start["edge"] == "bottom":
new_h = max(min_h, start["init_height"] + delta_y)
self.root.geometry(f"{self.root.winfo_width()}x{int(new_h)}")
elif start["edge"] == "bottom_right":
new_w = max(min_w, start["init_width"] + delta_x)
new_h = max(min_h, start["init_height"] + delta_y)
self.root.geometry(f"{int(new_w)}x{int(new_h)}")
elif start["edge"] == "left":
new_w = max(min_w, start["init_width"] - delta_x)
new_x = start["init_x"] + delta_x
self.root.geometry(f"{int(new_w)}x{self.root.winfo_height()}+{int(new_x)}+{self.root.winfo_y()}")
elif start["edge"] == "top":
new_h = max(min_h, start["init_height"] - delta_y)
new_y = start["init_y"] + delta_y
self.root.geometry(f"{self.root.winfo_width()}x{int(new_h)}+{self.root.winfo_x()}+{int(new_y)}")
elif start["edge"] == "top_left":
new_w = max(min_w, start["init_width"] - delta_x)
new_h = max(min_h, start["init_height"] - delta_y)
new_x = start["init_x"] + delta_x
new_y = start["init_y"] + delta_y
self.root.geometry(f"{int(new_w)}x{int(new_h)}+{int(new_x)}+{int(new_y)}")
elif start["edge"] == "top_right":
new_w = max(min_w, start["init_width"] + delta_x)
new_h = max(min_h, start["init_height"] - delta_y)
new_y = start["init_y"] + delta_y
self.root.geometry(f"{int(new_w)}x{int(new_h)}+{self.root.winfo_x()}+{int(new_y)}")
elif start["edge"] == "bottom_left":
new_w = max(min_w, start["init_width"] - delta_x)
new_h = max(min_h, start["init_height"] + delta_y)
new_x = start["init_x"] + delta_x
self.root.geometry(f"{int(new_w)}x{int(new_h)}+{int(new_x)}+{self.root.winfo_y()}")
def _stop_resize(self, event):
"""新增:鼠標(biāo)釋放時(shí)重置調(diào)整狀態(tài),保存窗口配置"""
if self.resizing:
self.resizing = False
self.save_config() # 調(diào)整后保存尺寸和位置
# -------------------------- 移動(dòng)窗口功能 --------------------------
def start_move_mode(self):
"""修復(fù)移動(dòng)窗口邏輯:基于鼠標(biāo)指針位置計(jì)算"""
self.moving = True
self.root.config(cursor="fleur")
# 記錄初始偏移量
self._drag_data["x"] = self.root.winfo_pointerx() - self.root.winfo_x()
self._drag_data["y"] = self.root.winfo_pointery() - self.root.winfo_y()
# 綁定移動(dòng)和停止事件
self.root.bind('<Motion>', self.do_move)
self.root.bind('<ButtonRelease-1>', self.stop_move_mode)
def do_move(self, event):
"""正確的窗口移動(dòng)邏輯"""
if self.moving:
x = self.root.winfo_pointerx() - self._drag_data["x"]
y = self.root.winfo_pointery() - self._drag_data["y"]
self.root.geometry(f"+{x}+{y}")
def stop_move_mode(self, event):
"""停止移動(dòng)模式(優(yōu)化恢復(fù)邏輯)"""
self.moving = False
self.root.config(cursor="arrow")
self.root.unbind('<Motion>')
self.root.unbind('<ButtonRelease-1>')
self.save_config() # 移動(dòng)后保存位置
def start_alt_move(self, event):
self._drag_data = {"x": event.x, "y": event.y, "moving": True}
def do_alt_move(self, event):
if hasattr(self, '_drag_data') and self._drag_data.get("moving"):
x = self.root.winfo_x() + (event.x - self._drag_data["x"])
y = self.root.winfo_y() + (event.y - self._drag_data["y"])
self.root.geometry(f"+{x}+{y}")
def stop_alt_move(self, event):
if hasattr(self, '_drag_data'):
self._drag_data["moving"] = False
# -------------------------- 新增功能 --------------------------
def minimize_window(self):
"""最小化窗口(無(wú)邊框窗口專用)"""
self.root.overrideredirect(False) # 臨時(shí)恢復(fù)窗口裝飾
self.root.iconify() # 最小化
# 恢復(fù)無(wú)邊框(最小化還原后)
self.root.bind('<Map>', lambda e: self.root.overrideredirect(True) if e.widget == self.root else None)
def set_font_family(self, family):
"""新增:設(shè)置字體家族"""
self.current_font_family = family
self.update_font()
self.save_config()
self.create_context_menu() # 更新菜單勾選狀態(tài)
def change_password(self):
"""新增:修改關(guān)閉密碼"""
old_pwd = simpledialog.askstring("驗(yàn)證舊密碼", "請(qǐng)輸入當(dāng)前關(guān)閉密碼:", show="*", parent=self.root)
if old_pwd != self.close_password:
messagebox.showerror("錯(cuò)誤", "舊密碼不正確!", parent=self.root)
return
new_pwd = simpledialog.askstring("設(shè)置新密碼", "請(qǐng)輸入新的關(guān)閉密碼(至少4位):", show="*", parent=self.root)
if not new_pwd or len(new_pwd) < 4:
messagebox.warning("提示", "密碼長(zhǎng)度不能少于4位!", parent=self.root)
return
confirm_pwd = simpledialog.askstring("確認(rèn)新密碼", "請(qǐng)?jiān)俅屋斎胄旅艽a:", show="*", parent=self.root)
if new_pwd == confirm_pwd:
self.close_password = new_pwd
self.save_password()
messagebox.showinfo("成功", "密碼修改成功!", parent=self.root)
else:
messagebox.showerror("錯(cuò)誤", "兩次輸入的密碼不一致!", parent=self.root)
def load_password(self):
"""加載自定義密碼"""
try:
if os.path.exists(PASSWORD_FILE):
with open(PASSWORD_FILE, 'r', encoding='utf-8') as f:
return json.load(f).get("password", DEFAULT_PASSWORD)
return DEFAULT_PASSWORD
except:
return DEFAULT_PASSWORD
def save_password(self):
"""保存密碼到文件"""
try:
with open(PASSWORD_FILE, 'w', encoding='utf-8') as f:
json.dump({"password": self.close_password}, f)
except Exception as e:
messagebox.showerror("錯(cuò)誤", f"保存密碼失?。簕str(e)}", parent=self.root)
def show_about(self):
"""新增:關(guān)于窗口"""
about_window = tk.Toplevel(self.root)
about_window.title("關(guān)于極簡(jiǎn)便簽")
about_window.geometry("300x200+%d+%d" % (self.root.winfo_x() + 50, self.root.winfo_y() + 50))
about_window.resizable(False, False)
about_window.attributes('-topmost', True)
tk.Label(about_window, text="極簡(jiǎn)便簽 v1.0", font=("Microsoft YaHei", 16)).pack(pady=20)
tk.Label(about_window, text="基于Python Tkinter開(kāi)發(fā)").pack()
tk.Label(about_window, text="? 輕量 · 簡(jiǎn)潔 · 易用").pack(pady=5)
tk.Button(about_window, text="確定", command=about_window.destroy, width=10).pack(pady=20)
# -------------------------- 原有功能優(yōu)化 --------------------------
def toggle_topmost(self):
"""優(yōu)化:保存置頂狀態(tài)到配置"""
self.is_topmost = self.topmost_var.get()
self.root.attributes('-topmost', self.is_topmost)
self.save_config()
def enter_pure_mode(self):
"""優(yōu)化純凈模式:鼠標(biāo)移動(dòng)也退出"""
self.main_container.config(bg=self.current_bg_color)
self.text_area.config(padx=25, pady=25)
# 鼠標(biāo)移動(dòng)時(shí)退出純凈模式
self.root.bind('<Motion>', self.exit_pure_mode_on_move)
def exit_pure_mode_on_move(self, event):
"""鼠標(biāo)移動(dòng)退出純凈模式"""
self.exit_pure_mode()
self.root.unbind('<Motion>')
def exit_pure_mode(self):
"""優(yōu)化退出純凈模式邏輯"""
self.main_container.config(bg="#CCCCCC")
self.text_area.config(padx=20, pady=20)
self.schedule_pure_mode()
def schedule_pure_mode(self):
if self.hide_timer:
self.root.after_cancel(self.hide_timer)
self.hide_timer = self.root.after(PURE_MODE_DELAY, self.enter_pure_mode)
def schedule_auto_save(self):
"""優(yōu)化自動(dòng)保存:添加成功提示(可選)"""
try:
self.save_content()
self.save_config()
except Exception as e:
messagebox.warning("提示", f"自動(dòng)保存失敗:{str(e)}", parent=self.root)
finally:
self.root.after(AUTO_SAVE_INTERVAL, self.schedule_auto_save)
def set_font_size(self, size):
self.current_font_size = size
self.update_font()
self.save_config()
self.create_context_menu()
def update_font(self):
new_font = font.Font(family=self.current_font_family, size=self.current_font_size)
self.text_area.config(
font=new_font,
fg=self.current_font_color,
insertbackground=self.current_font_color
)
def choose_color(self):
color = colorchooser.askcolor(color=self.current_font_color, title="選擇文字顏色")
if color[1]:
self.current_font_color = color[1]
self.update_font()
self.save_config()
def choose_bg_color(self):
color = colorchooser.askcolor(color=self.current_bg_color, title="選擇背景顏色")
if color[1]:
self.current_bg_color = color[1]
self.main_frame.config(bg=self.current_bg_color)
self.text_area.config(bg=self.current_bg_color)
self.save_config()
def toggle_bold(self):
try:
if self.text_area.tag_ranges("sel"):
current_tags = self.text_area.tag_names("sel.first")
if "bold" in current_tags:
self.text_area.tag_remove("bold", "sel.first", "sel.last")
else:
bold_font = font.Font(self.text_area, self.text_area.cget("font"))
bold_font.configure(weight="bold")
self.text_area.tag_configure("bold", font=bold_font)
self.text_area.tag_add("bold", "sel.first", "sel.last")
except tk.TclError:
pass
def show_menu(self, event):
if not self.resizing:
self.menu.post(event.x_root, event.y_root)
self.resizing = False
def set_alpha(self, alpha_val):
self.current_alpha = alpha_val
self.root.attributes('-alpha', alpha_val)
self.save_config()
self.create_context_menu()
def on_closing(self):
"""優(yōu)化關(guān)閉邏輯:更友好的提示"""
if not messagebox.askyesno("確認(rèn)退出", "確定要退出極簡(jiǎn)便簽嗎?\n(內(nèi)容會(huì)自動(dòng)保存)", parent=self.root):
return
password = simpledialog.askstring(
"安全驗(yàn)證",
"請(qǐng)輸入關(guān)閉密碼:",
parent=self.root,
show="*"
)
if password is None:
return
elif password == self.close_password:
self.save_content()
self.save_config()
self.root.destroy()
else:
messagebox.showerror("密碼錯(cuò)誤", f"密碼不正確!\n\n當(dāng)前默認(rèn)密碼:{DEFAULT_PASSWORD}(若未修改)",
parent=self.root)
def bind_events(self):
"""修復(fù):補(bǔ)充鼠標(biāo)釋放事件,重置調(diào)整狀態(tài),避免沖突"""
# 基礎(chǔ)交互
self.text_area.bind('<Alt-Button-1>', self.start_alt_move)
self.text_area.bind('<Alt-B1-Motion>', self.do_alt_move)
self.text_area.bind('<Alt-ButtonRelease-1>', self.stop_alt_move)
self.text_area.bind("<Button-3>", self.show_menu)
self.text_area.bind("<Button-1>", self.on_text_click)
self.text_area.bind("<Key>", self.on_text_input)
self.text_area.bind("<Control-MouseWheel>", self.on_mouse_wheel)
# 快捷鍵綁定
self.root.bind('<Control-b>', lambda e: self.toggle_bold())
self.root.bind('<Control-a>', lambda e: self.select_all())
self.root.bind('<Control-c>', lambda e: self.copy_text())
self.root.bind('<Control-v>', lambda e: self.paste_text())
self.root.bind('<Control-z>', lambda e: self.text_area.edit_undo())
self.root.bind('<Control-y>', lambda e: self.text_area.edit_redo())
self.root.bind('<Control-q>', lambda e: self.on_closing())
self.root.bind('<Alt-F4>', lambda e: self.on_closing())
# 調(diào)整大小(核心修復(fù))
self.main_container.bind('<Motion>', self.check_resize_cursor)
self.main_container.bind('<Button-1>', self.start_resize)
self.main_container.bind('<B1-Motion>', self.do_resize)
self.main_container.bind('<ButtonRelease-1>', self._stop_resize)
def on_text_input(self, event):
"""輸入文字時(shí)移除初始提示"""
if self.text_area.tag_ranges("hint"):
self.text_area.delete("hint.first", "hint.last")
self.text_area.tag_remove("hint", "1.0", tk.END)
self.schedule_pure_mode()
def copy_text(self):
self.text_area.event_generate("<<Copy>>")
def paste_text(self):
self.text_area.event_generate("<<Paste>>")
def select_all(self):
self.text_area.tag_add("sel", "1.0", tk.END)
def clear_text(self):
if messagebox.askyesno("確認(rèn)清空", "確定要清空所有內(nèi)容嗎?\n此操作不可撤銷!", parent=self.root):
self.text_area.delete("1.0", tk.END)
self.save_content()
def save_content(self):
try:
with open(CONTENT_FILE, 'w', encoding='utf-8') as f:
content = self.text_area.get("1.0", tk.END)
f.write(content)
except Exception as e:
messagebox.showerror("錯(cuò)誤", f"保存內(nèi)容失?。簕str(e)}", parent=self.root)
def load_content(self):
if os.path.exists(CONTENT_FILE):
try:
with open(CONTENT_FILE, 'r', encoding='utf-8') as f:
content = f.read()
self.text_area.delete("1.0", tk.END)
self.text_area.insert("1.0", content)
except Exception as e:
messagebox.showerror("錯(cuò)誤", f"加載內(nèi)容失?。簕str(e)}", parent=self.root)
def save_config(self):
config = {
'font_family': self.current_font_family,
'font_size': self.current_font_size,
'font_color': self.current_font_color,
'bg_color': self.current_bg_color,
'alpha': self.current_alpha,
'geometry': self.root.geometry(),
'is_topmost': self.is_topmost
}
try:
with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
except Exception as e:
messagebox.showerror("錯(cuò)誤", f"保存配置失?。簕str(e)}", parent=self.root)
def load_config(self):
if os.path.exists(CONFIG_FILE):
try:
with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
config = json.load(f)
self.current_font_family = config.get('font_family', self.current_font_family)
self.current_font_size = config.get('font_size', self.current_font_size)
self.current_font_color = config.get('font_color', self.current_font_color)
self.current_bg_color = config.get('bg_color', self.current_bg_color)
self.current_alpha = config.get('alpha', self.current_alpha)
self.is_topmost = config.get('is_topmost', self.is_topmost)
if 'geometry' in config:
self.root.geometry(config['geometry'])
except Exception as e:
messagebox.warning("提示", f"加載配置失敗,使用默認(rèn)設(shè)置:{str(e)}", parent=self.root)
def on_text_click(self, event=None):
current_padding = int(self.text_area.cget("padx"))
if current_padding > 20:
self.exit_pure_mode()
else:
self.schedule_pure_mode()
def on_mouse_wheel(self, event):
if event.delta > 0:
new_size = min(self.current_font_size + 1, 72)
else:
new_size = max(self.current_font_size - 1, 8)
if new_size != self.current_font_size:
self.current_font_size = new_size
self.update_font()
self.save_config()
self.create_context_menu()
if __name__ == "__main__":
root = tk.Tk()
app = BorderlessStickyNote(root)
root.mainloop()以上就是基于Python編寫(xiě)一個(gè)win10桌面便簽工具的詳細(xì)內(nèi)容,更多關(guān)于Python桌面便簽工具的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python中os.path模塊的8個(gè)神奇函數(shù)分享
在Python編程中,os.path模塊是一個(gè)非常重要的模塊,它提供了用于處理文件路徑和目錄的函數(shù),本文將介紹os.path模塊中最常用的8個(gè)內(nèi)置函數(shù),需要的可以參考下2023-11-11
Python編程scoketServer實(shí)現(xiàn)多線程同步實(shí)例代碼
這篇文章主要介紹了Python編程scoketServer實(shí)現(xiàn)多線程同步實(shí)例代碼,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
python 判斷文件還是文件夾的簡(jiǎn)單實(shí)例
詳解Python使用OpenCV如何確定一個(gè)對(duì)象的方向
Python調(diào)用實(shí)現(xiàn)最小二乘法的方法詳解
Python爬蟲(chóng)之Selenium實(shí)現(xiàn)鍵盤(pán)事件

