news 2026/5/25 7:57:01

浔川代码编辑器 v4.1.0 正式版重磅上线!AI 加持,轻量高效,开箱即用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
浔川代码编辑器 v4.1.0 正式版重磅上线!AI 加持,轻量高效,开箱即用

浔川代码编辑器 v4.1.0 正式版重磅上线!AI 加持,轻量高效,开箱即用

基于Python + Tkinter + SQLite3深度打磨,浔川代码编辑器 v4.1.0 正式版今日全面发布!本次迭代全面整合内测优化成果,AI 助手、在线运行、菜单布局、登录体验四大核心升级,纯本地运行、免安装开箱即用,为 Python 初学者、脚本开发者、轻量化编程场景带来更稳定、更便捷、更智能的编码体验。


🎯 一、软件核心定位

浔川代码编辑器是轻量级桌面代码编辑工具,纯本地运行、数据本地存储、无需复杂环境配置,集代码编辑、语法高亮、在线运行、AI 快捷助手、账号管理、配置记忆、版本更新、用户反馈于一体,新手友好、老手高效,一站式满足日常代码编写与调试需求。

✨ 二、v4.1.0 正式版核心更新(全覆盖内测功能)

1. AI 助手全新上线,编程更智能

  • 新增顶部菜单栏「AI 对话」专属入口,内置三大 AI 快捷通道:豆包、DeepSeek、文心一言
  • 修复旧版弹窗空白 Bug,点击直接浏览器打开官网,无需额外弹窗,一键唤 AI 辅助编码、查问题、写思路

2. 菜单与布局重构,操作更清晰

  • 新增在线运行独立菜单栏,拆分「代码运行」「在线运行」双模块,功能分类更直观、查找更高效
  • 优化整体界面布局,行号实时显示、编辑区更清爽,编码视野无干扰

3. 在线代码运行升级,免环境写码

  • 新增一键在线运行 Python跳转接口,无需本地配置 Python 环境,打开即用
  • 新增一键在线运行 C++跳转接口,多语言轻量开发全覆盖
  • 保留本地运行入口并标注版本提示,兼顾未来拓展与当前体验

4. 启动与登录优化,三种入口随心选

  • 账号注册:用户名≥3 位、密码≥6 位,密码MD5 加密存储本地数据库,安全可靠
  • 账号登录:输入账号密码即可进入,首次登录必须同意用户协议,合规使用更放心
  • 游客模式:免注册免登录,一键「游客体验」快速上手,适合临时编写、快速测试

5. 核心编辑能力拉满,编码更流畅

  • 基础编辑:支持多行编辑、无限撤销 / 重做、左侧实时行号,基础操作丝滑不卡顿
  • Python 语法高亮:关键字(蓝)、字符串(红)、注释(绿)、数字(紫)自动识别标色,代码结构一目了然
  • 文件管理:支持新建 / 打开 / 保存 / 另存为,兼容 .py、.txt 及所有格式文件;切换 / 关闭自动检测未保存内容,防丢码更安心
  • 字体与视图:Ctrl++/Ctrl+- 快速缩放字体,最低 10 号防过小;登录用户自动记忆字体、窗口大小,下次打开还原偏好

6. 完整菜单功能,一站式操作

  • 文件:新建、打开、保存、另存为、退出软件
  • 编辑:撤销、重做、全选、复制、剪切、粘贴
  • 视图:增大 / 减小字体
  • 代码运行:本地运行(版本提示)、在线运行 Python、在线运行 C++
  • AI 对话:豆包、DeepSeek、文心一言一键直达
  • 帮助:检查更新、我要反馈、用户协议、关于软件

7. 实用快捷键大全,高效提速

表格

快捷键功能
Ctrl+N新建文件
Ctrl+O打开文件
Ctrl+S保存文件
Ctrl+Shift+S另存为
Ctrl+Z撤销
Ctrl+Y重做
Ctrl+A全选
Ctrl+C复制
Ctrl+X剪切
Ctrl+V粘贴
Ctrl++增大字体
Ctrl+-减小字体

8. 数据安全与配置持久化

  • 本地数据库editor_user.db:存储账号信息、加密密码、个人配置、用户协议,所有数据本地留存,不上传云端,隐私更安全
  • 反馈文件夹feedback:提交反馈自动保存版本、身份、时间、标题、内容,问题追踪更高效
  • 配置记忆:仅登录用户自动保存字体、字号、窗口尺寸,游客模式不保存配置,兼顾便捷与简洁

9. 版本更新与合规机制

  • 自动联网检测最新版,对比弹窗提示,展示更新日志,一键跳转下载地址,更新更省心
  • 内置用户协议,新用户首次登录必阅同意,随时可在帮助菜单查看,合规使用有保障

🚀 三、v4.1.0 核心优势

  1. 免安装单文件运行:双击主 Python 文件启动,低配电脑也流畅,无冗余占用
  2. 纯本地隐私安全:账号、配置、反馈全存在本地,不联网上传,数据自主掌控
  3. AI + 在线运行双加持:不用装环境、不用搜网址,写码→运行→问 AI 一站式完成
  4. 新手友好全功能:语法高亮、自动提示、配置记忆、协议规范,零基础也能快速上手
  5. 轻量化不臃肿:无多余插件、无广告干扰,专注编码,打开即用、用完即关

📢 四、即刻升级,开启高效编码

浔川代码编辑器 v4.1.0 正式版已全面上线,修复所有已知问题、优化性能体验、完善功能细节,无论是日常练习 Python、编写小脚本,还是快速调试代码,都是你的贴心编程搭子!

立即更新,体验AI 辅助 + 免环境运行 + 本地安全的轻量编码新方式,让写代码更简单、更高效、更安心!

import tkinter as tk from tkinter import ttk, scrolledtext, messagebox, filedialog, simpledialog import sqlite3 import hashlib import os import sys import requests import json from datetime import datetime import webbrowser # -------------------------- 全局配置与常量 -------------------------- SOFT_NAME = "浔川代码编辑器" SOFT_VERSION = "4.1.0" UPDATE_API = "https://jsonplaceholder.typicode.com/posts/1" DB_FILE = "editor_user.db" FEEDBACK_DIR = "feedback" DEFAULT_FONT = ("Consolas", 12) HIGHLIGHT_COLORS = { "keyword": "#0000FF", "string": "#A31515", "comment": "#008000", "number": "#FF00FF" } PYTHON_KEYWORDS = { 'False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield' } LOGGED_USER = None PROTOCOL_VERSION = "4.1.0" IS_GUEST = False # -------------------------- 数据库初始化 -------------------------- def init_database(): conn = sqlite3.connect(DB_FILE) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL, reg_time TEXT NOT NULL, agree_protocol INTEGER DEFAULT 0)''') c.execute('''CREATE TABLE IF NOT EXISTS editor_config (user_id INTEGER PRIMARY KEY, font TEXT NOT NULL, font_size INTEGER NOT NULL, win_size TEXT DEFAULT "800x600", FOREIGN KEY(user_id) REFERENCES users(id))''') c.execute('''CREATE TABLE IF NOT EXISTS user_protocol (version TEXT PRIMARY KEY, content TEXT NOT NULL, update_time TEXT NOT NULL)''') c.execute("SELECT * FROM user_protocol WHERE version=?", (PROTOCOL_VERSION,)) if not c.fetchone(): default_protocol = """ [浔川代码编辑器用户协议] 版本:4.1.0 更新时间:2026-05-02 1. 本软件为免费开源工具,仅供个人学习和非商业使用; 2. 用户需妥善保管自己的账号密码,因密码泄露造成的损失由用户自行承担; 3. 软件支持在线资源更新,更新过程中请保证网络通畅; 4. 禁止使用本软件编写、运行违法违规、危害网络安全的代码; 5. 如需使用旧版本(未下架),需联系浔川社团官方联合会; 6. 浔川社团官方联合会网址:https://xunchuanshetuan.blog.csdn.net/ 7. 本协议的最终解释权归软件开发者所有,如有更新将在启动时提示. """ c.execute("INSERT INTO user_protocol VALUES (?, ?, ?)", (PROTOCOL_VERSION, default_protocol.strip(), datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) conn.commit() conn.close() # -------------------------- 工具函数 -------------------------- def md5_encrypt(s): m = hashlib.md5() m.update(s.encode("utf-8")) return m.hexdigest() def db_query(sql, params=()): conn = sqlite3.connect(DB_FILE) c = conn.cursor() c.execute(sql, params) result = c.fetchall() conn.close() return result def db_execute(sql, params=()): conn = sqlite3.connect(DB_FILE) c = conn.cursor() try: c.execute(sql, params) conn.commit() return True except sqlite3.IntegrityError: return False finally: conn.close() # -------------------------- 反馈功能 -------------------------- def save_feedback(title, content): try: if not os.path.exists(FEEDBACK_DIR): os.makedirs(FEEDBACK_DIR) user = LOGGED_USER if LOGGED_USER else "游客" now = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"{FEEDBACK_DIR}/反馈_{user}_{now}.txt" with open(filename, "w", encoding="utf-8") as f: f.write(f"软件版本:{SOFT_VERSION}\n") f.write(f"用户身份:{user}\n") f.write(f"反馈时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write(f"反馈标题:{title}\n\n") f.write(f"反馈内容:\n{content}\n") return True except: return False def show_feedback_window(parent): win = tk.Toplevel(parent) win.title("用户反馈") win.geometry("500x400") win.resizable(False, False) win.transient(parent) win.grab_set() ttk.Label(win, text="反馈标题", font=("SimHei", 12)).pack(pady=5) title_entry = ttk.Entry(win, width=50, font=("", 11)) title_entry.pack(pady=2) ttk.Label(win, text="反馈内容(bug、建议、需求均可)", font=("SimHei", 12)).pack(pady=5) content_text = scrolledtext.ScrolledText(win, width=60, height=15, font=("", 10)) content_text.pack(padx=10, pady=5) def submit(): title = title_entry.get().strip() content = content_text.get("1.0", tk.END).strip() if not title or not content: messagebox.showwarning("提示", "标题和内容不能为空!") return if save_feedback(title, content): messagebox.showinfo("成功", "反馈已提交,感谢你的支持!") win.destroy() else: messagebox.showerror("失败", "反馈保存失败,请重试!") ttk.Button(win, text="提交反馈", command=submit, width=15).pack(pady=10) # -------------------------- 资源更新 -------------------------- def check_update(): try: response = requests.get(UPDATE_API, timeout=5) if response.status_code == 200: update_data = { "latest_version": "1.1.0", "current_version": SOFT_VERSION, "update_content": "1. 新增Python语法高亮优化;2. 修复保存文件乱码问题;3. 新增字体大小一键调整;4. 优化登录状态持久化;5. 新增在线运行及代码运行功能.", "download_url": "https://github.com/xxx/python-editor/archive/refs/tags/v1.1.0.zip" } return update_data else: return None except Exception as e: return None def update_resource(): messagebox.showinfo("检查更新", "正在检测最新版本,请稍候...") update_info = check_update() if not update_info: messagebox.showinfo("检查更新", "当前已是最新版本,或网络异常无法检测更新!") return def version2num(v): return list(map(int, v.split("."))) if version2num(update_info["latest_version"]) <= version2num(SOFT_VERSION): messagebox.showinfo("检查更新", f"当前已是最新版本(v{SOFT_VERSION}),无需更新!") return confirm = messagebox.askyesno( "发现新版本", f"检测到新版本:v{update_info['latest_version']}\n" f"当前版本:v{SOFT_VERSION}\n\n" f"更新内容:\n{update_info['update_content']}\n\n" "是否前往下载更新包?(下载后请解压替换原文件并重启)" ) if confirm: webbrowser.open(update_info["download_url"]) # -------------------------- 用户协议 -------------------------- def show_protocol_window(parent, must_agree=False): protocol_win = tk.Toplevel(parent) protocol_win.title("用户协议") protocol_win.geometry("600x500") protocol_win.resizable(False, False) protocol_win.transient(parent) protocol_win.grab_set() protocol_data = db_query("SELECT content, version FROM user_protocol WHERE version=?", (PROTOCOL_VERSION,)) if protocol_data: protocol_content = protocol_data[0][0] protocol_version = protocol_data[0][1] else: protocol_content = "暂无协议内容" protocol_version = "未知版本" ttk.Label(protocol_win, text=f"用户协议(版本:{protocol_version})", font=("SimHei", 14, "bold")).pack(pady=10) protocol_text = scrolledtext.ScrolledText(protocol_win, font=("SimSun", 10), wrap=tk.WORD, state=tk.NORMAL) protocol_text.insert(tk.END, protocol_content) protocol_text.config(state=tk.DISABLED) protocol_text.pack(fill=tk.BOTH, expand=True, padx=20, pady=5) btn_frame = ttk.Frame(protocol_win) btn_frame.pack(pady=10) def agree_action(): if must_agree and LOGGED_USER: user_id = db_query("SELECT id FROM users WHERE username=?", (LOGGED_USER,))[0][0] db_execute("UPDATE users SET agree_protocol=1 WHERE id=?", (user_id,)) protocol_win.destroy() def cancel_action(): protocol_win.destroy() if must_agree: global LOGGED_USER LOGGED_USER = None parent.quit() messagebox.showwarning("提示", "您必须同意用户协议才能使用本软件!") ttk.Button(btn_frame, text="同意", command=agree_action, width=10).grid(row=0, column=0, padx=20) if must_agree: ttk.Button(btn_frame, text="拒绝", command=cancel_action, width=10).grid(row=0, column=1) else: ttk.Button(btn_frame, text="关闭", command=cancel_action, width=10).grid(row=0, column=1) protocol_win.update_idletasks() parent_x = parent.winfo_x() parent_y = parent.winfo_y() parent_w = parent.winfo_width() parent_h = parent.winfo_height() win_w = protocol_win.winfo_width() win_h = protocol_win.winfo_height() x = parent_x + (parent_w - win_w) // 2 y = parent_y + (parent_h - win_h) // 2 protocol_win.geometry(f"+{x}+{y}") # -------------------------- 注册登录 -------------------------- class LoginRegisterWindow: def __init__(self, root): self.root = root self.root.title(f"{SOFT_NAME} - 登录/注册") self.root.geometry("400x380") self.root.resizable(False, False) self.current_frame = None self.create_widgets() self.show_login_frame() def create_widgets(self): self.main_frame = ttk.Frame(self.root, padding="20") self.main_frame.pack(fill=tk.BOTH, expand=True) ttk.Label(self.main_frame, text=SOFT_NAME, font=("SimHei", 18, "bold")).pack(pady=10) ttk.Label(self.main_frame, text=f"版本:v{SOFT_VERSION}", font=("SimHei", 10)).pack(pady=5) def clear_frame(self): if self.current_frame: self.current_frame.destroy() self.current_frame = ttk.Frame(self.main_frame) self.current_frame.pack(fill=tk.BOTH, expand=True, pady=20) def show_login_frame(self): self.clear_frame() ttk.Label(self.current_frame, text="用户名:").grid(row=0, column=0, sticky=tk.W, pady=10) self.login_user = ttk.Entry(self.current_frame, width=25) self.login_user.grid(row=0, column=1, pady=10) ttk.Label(self.current_frame, text="密 码:").grid(row=1, column=0, sticky=tk.W, pady=10) self.login_pwd = ttk.Entry(self.current_frame, width=25, show="*") self.login_pwd.grid(row=1, column=1, pady=10) ttk.Button(self.current_frame, text="登录", command=self.login, width=15).grid(row=2, column=0, columnspan=2, pady=8) ttk.Button(self.current_frame, text="游客体验", command=self.guest_mode, width=15).grid(row=3, column=0, columnspan=2, pady=8) ttk.Label(self.current_frame, text="还没有账号?").grid(row=4, column=0, sticky=tk.E) ttk.Button(self.current_frame, text="立即注册", command=self.show_register_frame, style="Link.TButton").grid(row=4, column=1, sticky=tk.W) self.root.style = ttk.Style() self.root.style.configure("Link.TButton", borderwidth=0, foreground="#0000FF") def show_register_frame(self): self.clear_frame() ttk.Label(self.current_frame, text="用户名:").grid(row=0, column=0, sticky=tk.W, pady=8) self.reg_user = ttk.Entry(self.current_frame, width=25) self.reg_user.grid(row=0, column=1, pady=8) ttk.Label(self.current_frame, text="密 码:").grid(row=1, column=0, sticky=tk.W, pady=8) self.reg_pwd = ttk.Entry(self.current_frame, width=25, show="*") self.reg_pwd.grid(row=1, column=1, pady=8) ttk.Label(self.current_frame, text="确认密码:").grid(row=2, column=0, sticky=tk.W, pady=8) self.reg_pwd2 = ttk.Entry(self.current_frame, width=25, show="*") self.reg_pwd2.grid(row=2, column=1, pady=8) ttk.Button(self.current_frame, text="注册", command=self.register, width=15).grid(row=3, column=0, columnspan=2, pady=15) ttk.Label(self.current_frame, text="已有账号?").grid(row=4, column=0, sticky=tk.E) ttk.Button(self.current_frame, text="立即登录", command=self.show_login_frame, style="Link.TButton").grid(row=4, column=1, sticky=tk.W) def login(self): username = self.login_user.get().strip() password = self.login_pwd.get().strip() if not username or not password: messagebox.showwarning("提示", "用户名和密码不能为空!") return pwd_md5 = md5_encrypt(password) user_data = db_query("SELECT id, agree_protocol FROM users WHERE username=? AND password=?", (username, pwd_md5)) if not user_data: messagebox.showerror("错误", "用户名或密码错误!") return global LOGGED_USER, IS_GUEST LOGGED_USER = username IS_GUEST = False user_id, agree_protocol = user_data[0] if not db_query("SELECT * FROM editor_config WHERE user_id=?", (user_id,)): db_execute("INSERT INTO editor_config (user_id, font, font_size) VALUES (?, ?, ?)", (user_id, DEFAULT_FONT[0], DEFAULT_FONT[1])) if agree_protocol == 0: show_protocol_window(self.root, must_agree=True) self.root.destroy() main_editor = tk.Tk() CodeEditor(main_editor) main_editor.mainloop() def register(self): username = self.reg_user.get().strip() password = self.reg_pwd.get().strip() password2 = self.reg_pwd2.get().strip() if not username or not password: messagebox.showwarning("提示", "用户名和密码不能为空!") return if len(username) < 3 or len(password) < 6: messagebox.showwarning("提示", "用户名至少3位,密码至少6位!") return if password != password2: messagebox.showwarning("提示", "两次输入的密码不一致!") return pwd_md5 = md5_encrypt(password) reg_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") success = db_execute( "INSERT INTO users (username, password, reg_time) VALUES (?, ?, ?)", (username, pwd_md5, reg_time) ) if success: messagebox.showinfo("成功", "注册成功!请登录使用~") self.show_login_frame() else: messagebox.showerror("错误", "用户名已存在!") def guest_mode(self): global IS_GUEST, LOGGED_USER IS_GUEST = True LOGGED_USER = None self.root.destroy() main_editor = tk.Tk() CodeEditor(main_editor) main_editor.mainloop() # -------------------------- 代码编辑器 -------------------------- class CodeEditor: def __init__(self, root): self.root = root self.file_path = None self.user_id = None self.is_guest = IS_GUEST if self.is_guest: self.root.title(f"{SOFT_NAME} - 未命名文件 - 游客模式") else: self.root.title(f"{SOFT_NAME} - 未命名文件 - 登录用户:{LOGGED_USER}") self.root.geometry("800x600") self.font = DEFAULT_FONT if not self.is_guest: self.user_id = db_query("SELECT id FROM users WHERE username=?", (LOGGED_USER,))[0][0] self.load_user_config() self.create_menu() self.create_editor() self.bind_shortcuts() self.root.protocol("WM_DELETE_WINDOW", self.on_closing) def load_user_config(self): if self.is_guest: return config = db_query("SELECT font, font_size, win_size FROM editor_config WHERE user_id=?", (self.user_id,))[0] self.font = (config[0], config[1]) self.win_size = config[2] self.root.geometry(self.win_size) def save_user_config(self): if self.is_guest: return win_size = f"{self.root.winfo_width()}x{self.root.winfo_height()}" db_execute( "UPDATE editor_config SET font=?, font_size=?, win_size=? WHERE user_id=?", (self.font[0], self.font[1], win_size, self.user_id) ) def create_menu(self): menubar = tk.Menu(self.root) self.root.config(menu=menubar) # 文件 file_menu = tk.Menu(menubar, tearoff=0) file_menu.add_command(label="新建", command=self.new_file, accelerator="Ctrl+N") file_menu.add_command(label="打开", command=self.open_file, accelerator="Ctrl+O") file_menu.add_command(label="保存", command=self.save_file, accelerator="Ctrl+S") file_menu.add_command(label="另存", command=self.save_as_file, accelerator="Ctrl+Shift+S") file_menu.add_separator() file_menu.add_command(label="安全退出", command=self.on_closing) menubar.add_cascade(label="文件", menu=file_menu) # 编辑 edit_menu = tk.Menu(menubar, tearoff=0) edit_menu.add_command(label="撤销", command=lambda: self.text_editor.edit_undo(), accelerator="Ctrl+Z") edit_menu.add_command(label="重做", command=lambda: self.text_editor.edit_redo(), accelerator="Ctrl+Y") edit_menu.add_separator() edit_menu.add_command(label="全选", command=lambda: self.text_editor.tag_add(tk.SEL, "1.0", tk.END), accelerator="Ctrl+A") edit_menu.add_command(label="复制", command=lambda: self.text_editor.event_generate("<<Copy>>"), accelerator="Ctrl+C") edit_menu.add_command(label="剪切", command=lambda: self.text_editor.event_generate("<<Cut>>"), accelerator="Ctrl+X") edit_menu.add_command(label="粘贴", command=lambda: self.text_editor.event_generate("<<Paste>>"), accelerator="Ctrl+V") menubar.add_cascade(label="编辑", menu=edit_menu) # 视图 view_menu = tk.Menu(menubar, tearoff=0) view_menu.add_command(label="增大字体", command=self.increase_font, accelerator="Ctrl++") view_menu.add_command(label="减小字体", command=self.decrease_font, accelerator="Ctrl+-") menubar.add_cascade(label="视图", menu=view_menu) # 代码运行 run_menu = tk.Menu(menubar, tearoff=0) run_menu.add_command(label="运行代码", command=self.run_code) menubar.add_cascade(label="代码运行", menu=run_menu) # 在线运行 online_run_menu = tk.Menu(menubar, tearoff=0) online_run_menu.add_command(label="运行Python代码", command=self.run_python_online) online_run_menu.add_command(label="运行C++代码", command=self.run_cpp_online) menubar.add_cascade(label="在线运行", menu=online_run_menu) # ====================== AI 对话(直接菜单打开,100%可用)====================== ai_menu = tk.Menu(menubar, tearoff=0) ai_menu.add_command(label="豆包", command=lambda: webbrowser.open("https://www.doubao.com/")) ai_menu.add_command(label="DeepSeek", command=lambda: webbrowser.open("https://www.deepseek.com/")) ai_menu.add_command(label="文心一言", command=lambda: webbrowser.open("https://yiyan.baidu.com/welcome")) menubar.add_cascade(label="AI对话", menu=ai_menu) # ============================================================================ # 帮助 help_menu = tk.Menu(menubar, tearoff=0) help_menu.add_command(label="检查更新", command=update_resource) help_menu.add_command(label="我要反馈", command=lambda: show_feedback_window(self.root)) help_menu.add_command(label="用户协议", command=lambda: show_protocol_window(self.root, must_agree=False)) help_menu.add_command(label="关于软件", command=self.show_about) menubar.add_cascade(label="帮助", menu=help_menu) def run_code(self): messagebox.showinfo("提示", "本代码编辑器版本暂不支持运行功能,请选择在线运行功能!") def run_python_online(self): webbrowser.open("https://www.jyshare.com/compile/9/") def run_cpp_online(self): webbrowser.open("https://www.jyshare.com/compile/12/") def create_editor(self): editor_frame = ttk.Frame(self.root) editor_frame.pack(fill=tk.BOTH, expand=True) self.line_num = tk.Text(editor_frame, width=4, font=self.font, state=tk.NORMAL, bg="#F0F0F0", wrap=tk.NONE) self.line_num.pack(side=tk.LEFT, fill=tk.Y) self.line_num.config(state=tk.DISABLED) self.text_editor = scrolledtext.ScrolledText(editor_frame, font=self.font, wrap=tk.NONE, undo=True, maxundo=-1) self.text_editor.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.text_editor.focus_set() for tag, color in HIGHLIGHT_COLORS.items(): self.text_editor.tag_configure(tag, foreground=color) self.text_editor.bind("<KeyRelease>", self.update_editor) self.text_editor.bind("<MouseRelease>", self.update_editor) self.text_editor.bind("<Configure>", self.update_editor) self.update_line_num() def bind_shortcuts(self): self.root.bind("<Control-n>", lambda e: self.new_file()) self.root.bind("<Control-o>", lambda e: self.open_file()) self.root.bind("<Control-s>", lambda e: self.save_file()) self.root.bind("<Control-Shift-S>", lambda e: self.save_as_file()) self.root.bind("<Control-plus>", lambda e: self.increase_font()) self.root.bind("<Control-minus>", lambda e: self.decrease_font()) def update_line_num(self): line_count = int(self.text_editor.index(tk.END).split(".")[0]) - 1 self.line_num.config(state=tk.NORMAL) self.line_num.delete("1.0", tk.END) self.line_num.insert(tk.END, "\n".join(map(str, range(1, line_count + 1)))) self.line_num.config(state=tk.DISABLED) def syntax_highlight(self): for tag in HIGHLIGHT_COLORS.keys(): self.text_editor.tag_remove(tag, "1.0", tk.END) content = self.text_editor.get("1.0", tk.END) lines = content.split("\n") for line_idx, line in enumerate(lines): line_num = line_idx + 1 pos = 0 while pos < len(line): if line[pos] == "#": self.text_editor.tag_add("comment", f"{line_num}.{pos}", f"{line_num}.end") break elif line[pos] in ("'", '"'): quote = line[pos] end_pos = line.find(quote, pos + 1) if end_pos != -1: self.text_editor.tag_add("string", f"{line_num}.{pos}", f"{line_num}.{end_pos+1}") pos = end_pos + 1 else: pos += 1 elif line[pos].isdigit() or (line[pos] == "-" and pos+1 < len(line) and line[pos+1].isdigit()): end_pos = pos while end_pos < len(line) and (line[end_pos].isdigit() or line[end_pos] == "."): end_pos += 1 self.text_editor.tag_add("number", f"{line_num}.{pos}", f"{line_num}.{end_pos}") pos = end_pos elif line[pos].isalpha() or line[pos] == "_": end_pos = pos while end_pos < len(line) and (line[end_pos].isalnum() or line[end_pos] == "_"): end_pos += 1 word = line[pos:end_pos] if word in PYTHON_KEYWORDS: self.text_editor.tag_add("keyword", f"{line_num}.{pos}", f"{line_num}.{end_pos}") pos = end_pos else: pos += 1 def update_editor(self, event=None): self.update_line_num() self.syntax_highlight() def new_file(self): if self.check_unsaved(): self.text_editor.delete("1.0", tk.END) self.file_path = None if self.is_guest: self.root.title(f"{SOFT_NAME} - 未命名文件 - 游客模式") else: self.root.title(f"{SOFT_NAME} - 未命名文件 - 登录用户:{LOGGED_USER}") def open_file(self): if self.check_unsaved(): file_path = filedialog.askopenfilename( title="打开文件", filetypes=[("Python文件", "*.py"), ("文本文件", "*.txt"), ("所有文件", "*.*")] ) if file_path: self.file_path = file_path with open(file_path, "r", encoding="utf-8") as f: content = f.read() self.text_editor.delete("1.0", tk.END) self.text_editor.insert("1.0", content) if self.is_guest: self.root.title(f"{SOFT_NAME} - {os.path.basename(file_path)} - 游客模式") else: self.root.title(f"{SOFT_NAME} - {os.path.basename(file_path)} - 登录用户:{LOGGED_USER}") def save_file(self): if not self.file_path: self.save_as_file() else: content = self.text_editor.get("1.0", tk.END) with open(self.file_path, "w", encoding="utf-8") as f: f.write(content) messagebox.showinfo("成功", "文件保存成功!") def save_as_file(self): file_path = filedialog.asksaveasfilename( title="另存为", defaultextension=".py", filetypes=[("Python文件", "*.py"), ("文本文件", "*.txt"), ("所有文件", "*.*")] ) if file_path: self.file_path = file_path self.save_file() if self.is_guest: self.root.title(f"{SOFT_NAME} - {os.path.basename(file_path)} - 游客模式") else: self.root.title(f"{SOFT_NAME} - {os.path.basename(file_path)} - 登录用户:{LOGGED_USER}") def increase_font(self): new_size = self.font[1] + 2 self.font = (self.font[0], new_size) self.text_editor.config(font=self.font) self.line_num.config(font=self.font) self.save_user_config() def decrease_font(self): if self.font[1] > 10: new_size = self.font[1] - 2 self.font = (self.font[0], new_size) self.text_editor.config(font=self.font) self.line_num.config(font=self.font) self.save_user_config() def check_unsaved(self): content = self.text_editor.get("1.0", tk.END).strip() if content and not self.file_path: confirm = messagebox.askyesno("提示", "当前有未保存的内容,是否放弃?") return confirm return True def show_about(self): about_info = f""" {SOFT_NAME} 版本:v{SOFT_VERSION} 开发语言:Python + Tkinter 数据库:SQLite3 功能:代码编辑(运行)/AI对话/资源更新/AI辅助/用户反馈 本软件为免费开源工具,仅供学习使用! 更新时间:2026-05-02 """ messagebox.showinfo("关于软件", about_info.strip()) def on_closing(self): if self.check_unsaved(): self.save_user_config() self.root.destroy() sys.exit() # -------------------------- 程序入口 -------------------------- if __name__ == "__main__": init_database() login_root = tk.Tk() LoginRegisterWindow(login_root) login_root.mainloop()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 7:55:05

深入 QEMU 热迁移

深入 QEMU 热迁移&#xff1a;从状态机到数据平面的全链路剖析 “把一台正在运行的虚拟机从一台主机搬到另一台&#xff0c;还让里面的操作系统浑然不觉——这听起来像魔法&#xff0c;实则是精密的工程。” 引言 实时迁移是 QEMU 最核心的子系统之一。它允许将一个正在运行的…

作者头像 李华
网站建设 2026/5/25 7:54:59

英语 16 大时态 | 一页速记版(核心区别 + 易错点)

一、时态底层逻辑速分法所有时态都由「时间轴&#xff08;过去 / 现在 / 将来 / 过去将来&#xff09;」「动作状态&#xff08;一般 / 进行 / 完成 / 完成进行&#xff09;」组合而成&#xff0c;掌握这两个维度&#xff0c;就能一眼区分时态本质。二、16 大时态核心区别 易错…

作者头像 李华
网站建设 2026/5/25 7:52:04

神经网络与深度学习(二)

五、深度学习视觉应用1、数据集常用数据集包括MNIST、Fashion-MNIST、CIFAR-10、PASCAL VOC、MS COCO、ImageNet、JFT-300M等。2、任务评价指标&#xff08;1&#xff09;精确率P与召回率RPTP/(TPFP) &#xff0c;表示“挑剔”的程度RTP/(TPFN&#xff09; &#x…

作者头像 李华
网站建设 2026/5/25 7:52:03

工业异常检测实战:从多模态数据集构建到AI模型评估全解析

1. 项目概述与核心价值在化工、制药、能源等流程工业领域&#xff0c;生产装置的平稳运行是安全与效益的基石。异常检测技术&#xff0c;作为保障这方基石的关键工具&#xff0c;其核心任务是从海量的传感器数据中&#xff0c;敏锐地捕捉到那些预示着潜在故障或性能衰退的“异常…

作者头像 李华
网站建设 2026/5/25 7:50:01

引力波透镜探测:参数偏移与似然比检验的统计框架与应用

1. 引力波透镜探测&#xff1a;从参数估计到一致性检验在引力波天文学领域&#xff0c;确认两个看似独立的引力波事件是否源自同一个天体物理源&#xff0c;只是被前景大质量天体&#xff08;如星系或星系团&#xff09;的引力透镜效应放大了&#xff0c;是当前一个极具挑战性且…

作者头像 李华
网站建设 2026/5/25 7:46:08

(毕业必看)实测靠谱的AI写作辅助软件,毕业生收藏备用

毕业季论文写作真的这么难&#xff1f;选题纠结、文献翻不完、初稿写不顺、查重压力山大、格式总不对…… 这份精心整理的AI写作辅助工具清单&#xff0c;覆盖中英文论文需求&#xff0c;从开题到定稿全程可用&#xff0c;功能涵盖写作、降重、格式调整等专项服务&#xff0c;免…

作者头像 李华