<think>我们将在原有程序的基础上进行修改,将执行结果不弹出消息框,而是显示在程序界面的日志框中。
修改点:
1. 在界面上添加一个文本框(Text控件)作为日志输出区域。
2. 将原来使用messagebox显示的信息(错误信息、完成信息)改为输出到日志框。
3. 在执行重命名过程中,将每一步操作的结果(成功或失败)也输出到日志框。
我们将对程序做以下调整:
- 在界面底部添加一个日志框(带滚动条)
- 创建一个日志函数(如:`log_message(message)`)用于向日志框添加消息
- 替换原来的messagebox调用为日志函数调用
同时,为了更好的用户体验,我们还将:
- 日志框设置为只读
- 自动滚动到最新日志
注意:由于Tkinter是单线程的,长时间操作可能会导致界面无响应,但我们的重命名操作通常很快,所以暂时不考虑多线程。
修改后的代码:</think>下面是根据您的要求修改后的程序,将执行结果改为在日志框中显示,而不是弹出提示框:
```python
import os
import json
import tkinter as tk
from tkinter import filedialog, scrolledtext
class FileRenamerApp:
def __init__(self, root):
self.root = root
self.root.title("文件批量重命名工具")
self.root.geometry("800x600")
# 加载配置
self.config_file = "file_renamer_config.json"
self.config = self.load_config()
# 创建UI
self.create_widgets()
# 绑定关闭事件
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
def load_config(self):
"""加载配置文件"""
try:
if os.path.exists(self.config_file):
with open(self.config_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
self.log_message(f"加载配置失败: {e}")
return {"path": "", "rules": []}
def save_config(self):
"""保存配置到文件"""
try:
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(self.config, f, ensure_ascii=False, indent=2)
self.log_message("配置已保存")
except Exception as e:
self.log_message(f"保存配置失败: {e}", "error")
def create_widgets(self):
"""创建UI组件"""
# 主框架
main_frame = tk.Frame(self.root)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 路径选择部分
path_frame = tk.LabelFrame(main_frame, text="目标路径")
path_frame.pack(fill=tk.X, pady=5)
tk.Label(path_frame, text="路径:").pack(side=tk.LEFT)
self.path_var = tk.StringVar(value=self.config.get("path", ""))
self.path_entry = tk.Entry(path_frame, textvariable=self.path_var, width=60)
self.path_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
tk.Button(path_frame, text="浏览...", command=self.browse_path).pack(side=tk.LEFT)
# 规则列表框架
rules_frame = tk.LabelFrame(main_frame, text="重命名规则")
rules_frame.pack(fill=tk.BOTH, expand=True, pady=5)
# 滚动条容器
scroll_container = tk.Frame(rules_frame)
scroll_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 添加滚动条
scrollbar = tk.Scrollbar(scroll_container)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 创建规则画布
self.rules_canvas = tk.Canvas(
scroll_container,
yscrollcommand=scrollbar.set
)
self.rules_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=self.rules_canvas.yview)
# 内部框架用于放置规则行
self.rules_inner_frame = tk.Frame(self.rules_canvas)
self.rules_canvas.create_window((0, 0), window=self.rules_inner_frame, anchor="nw")
# 绑定事件
self.rules_inner_frame.bind("<Configure>", self.on_frame_configure)
self.rules_canvas.bind("<Configure>", self.on_canvas_configure)
# 添加规则按钮
tk.Button(rules_frame, text="添加规则", command=self.add_rule).pack(pady=5)
# 日志框架
log_frame = tk.LabelFrame(main_frame, text="操作日志")
log_frame.pack(fill=tk.BOTH, expand=True, pady=5)
# 日志文本框
self.log_text = scrolledtext.ScrolledText(
log_frame,
wrap=tk.WORD,
height=8,
state='normal'
)
self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.log_text.config(state='disabled') # 默认禁用编辑
# 加载保存的规则
self.load_rules()
# 添加初始日志
self.log_message("程序已启动")
if self.config.get("path"):
self.log_message(f"已加载路径: {self.config['path']}")
if self.config.get("rules"):
self.log_message(f"已加载 {len(self.config['rules'])} 条重命名规则")
def on_frame_configure(self, event):
"""更新画布滚动区域"""
self.rules_canvas.configure(scrollregion=self.rules_canvas.bbox("all"))
def on_canvas_configure(self, event):
"""更新内部框架宽度"""
self.rules_canvas.itemconfig(1, width=event.width)
def browse_path(self):
"""浏览文件夹路径"""
path = filedialog.askdirectory()
if path:
self.path_var.set(path)
self.log_message(f"已选择路径: {path}")
def add_rule(self, a_str="", b_str=""):
"""添加新的重命名规则行"""
row_frame = tk.Frame(self.rules_inner_frame)
row_frame.pack(fill=tk.X, pady=5)
# A字符串输入
a_var = tk.StringVar(value=a_str)
tk.Label(row_frame, text="查找字符串:").pack(side=tk.LEFT)
a_entry = tk.Entry(row_frame, textvariable=a_var, width=20)
a_entry.pack(side=tk.LEFT, padx=5)
# B字符串输入
b_var = tk.StringVar(value=b_str)
tk.Label(row_frame, text="替换为:").pack(side=tk.LEFT, padx=(10, 0))
b_entry = tk.Entry(row_frame, textvariable=b_var, width=20)
b_entry.pack(side=tk.LEFT, padx=5)
# 执行按钮
tk.Button(
row_frame,
text="执行",
command=lambda: self.execute_rename(a_var.get(), b_var.get())
).pack(side=tk.LEFT, padx=10)
# 删除按钮
tk.Button(
row_frame,
text="删除",
command=lambda: self.remove_rule(row_frame)
).pack(side=tk.LEFT)
# 保存行引用
row_frame.a_var = a_var
row_frame.b_var = b_var
self.log_message(f"已添加规则: '{a_str}' -> '{b_str}'")
self.update_scrollregion()
def remove_rule(self, row_frame):
"""删除规则行"""
a_str = row_frame.a_var.get()
b_str = row_frame.b_var.get()
row_frame.destroy()
self.log_message(f"已删除规则: '{a_str}' -> '{b_str}'")
self.update_scrollregion()
def load_rules(self):
"""加载保存的规则"""
for rule in self.config.get("rules", []):
self.add_rule(rule.get("a", ""), rule.get("b", ""))
def log_message(self, message, level="info"):
"""向日志框添加消息"""
self.log_text.config(state='normal')
# 根据级别添加前缀和颜色
if level == "error":
prefix = "[错误] "
tag = "error"
elif level == "warning":
prefix = "[警告] "
tag = "warning"
else:
prefix = "[信息] "
tag = "info"
# 添加带时间戳的消息
from datetime import datetime
timestamp = datetime.now().strftime("%H:%M:%S")
full_message = f"{timestamp} {prefix}{message}\n"
# 插入消息并应用标签
self.log_text.insert(tk.END, full_message, tag)
# 滚动到底部
self.log_text.see(tk.END)
self.log_text.config(state='disabled')
# 配置标签样式
if level == "error":
self.log_text.tag_config("error", foreground="red")
elif level == "warning":
self.log_text.tag_config("warning", foreground="orange")
def execute_rename(self, a_str, b_str):
"""执行重命名操作"""
path = self.path_var.get()
if not path or not os.path.isdir(path):
self.log_message("请选择有效路径", "error")
return
if not a_str:
self.log_message("查找字符串不能为空", "error")
return
self.log_message(f"开始执行重命名: '{a_str}' -> '{b_str}'")
self.log_message(f"目标路径: {path}")
# 获取所有文件
try:
files = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
self.log_message(f"找到 {len(files)} 个文件")
except Exception as e:
self.log_message(f"读取目录失败: {str(e)}", "error")
return
# 执行重命名
renamed_count = 0
for filename in files:
if a_str in filename:
new_name = filename.replace(a_str, b_str)
# 避免无意义的操作
if new_name == filename:
self.log_message(f"跳过 '{filename}' (无变化)", "warning")
continue
try:
os.rename(
os.path.join(path, filename),
os.path.join(path, new_name)
)
renamed_count += 1
self.log_message(f"重命名: '{filename}' -> '{new_name}'")
except Exception as e:
self.log_message(f"重命名失败: '{filename}' -> '{new_name}': {str(e)}", "error")
self.log_message(f"操作完成! 成功重命名 {renamed_count} 个文件")
def update_scrollregion(self):
"""更新滚动区域"""
self.rules_canvas.configure(scrollregion=self.rules_canvas.bbox("all"))
def on_closing(self):
"""关闭窗口时保存配置"""
# 收集所有规则
self.config["path"] = self.path_var.get()
self.config["rules"] = []
# 从所有行中收集规则
for child in self.rules_inner_frame.winfo_children():
if hasattr(child, 'a_var') and hasattr(child, 'b_var'):
a_str = child.a_var.get()
b_str = child.b_var.get()
if a_str: # 只保存非空规则
self.config["rules"].append({"a": a_str, "b": b_str})
# 保存配置
self.save_config()
self.log_message("程序关闭中...")
self.root.destroy()
if __name__ == "__main__":
root = tk.Tk()
app = FileRenamerApp(root)
root.mainloop()
```
### 主要修改内容:
1. **添加日志框**:
- 使用 `scrolledtext.ScrolledText` 创建带滚动条的日志文本框
- 日志框位于界面底部,显示所有操作信息
- 支持不同级别的日志(信息、警告、错误)
2. **日志功能实现**:
```python
def log_message(self, message, level="info"):
"""向日志框添加消息"""
self.log_text.config(state='normal')
# 添加带时间戳的消息
from datetime import datetime
timestamp = datetime.now().strftime("%H:%M:%S")
full_message = f"{timestamp} [信息] {message}\n"
# 根据级别修改前缀和颜色
if level == "error":
full_message = f"{timestamp} [错误] {message}\n"
self.log_text.tag_config("error", foreground="red")
self.log_text.insert(tk.END, full_message, "error")
elif level == "warning":
full_message = f"{timestamp} [警告] {message}\n"
self.log_text.tag_config("warning", foreground="orange")
self.log_text.insert(tk.END, full_message, "warning")
else:
self.log_text.insert(tk.END, full_message)
# 滚动到底部
self.log_text.see(tk.END)
self.log_text.config(state='disabled')
```
3. **替换所有弹出提示**:
- 将所有 `messagebox.showinfo` 和 `messagebox.showerror` 替换为 `log_message` 调用
- 添加详细的执行过程日志,包括文件列表、重命名操作等
4. **界面优化**:
- 添加分组框架(LabelFrame)使界面更清晰
- 优化布局,使各区域比例更合理
- 添加程序启动和关闭时的日志记录
5. **操作细节改进**:
- 添加时间戳到每条日志
- 不同级别的日志使用不同颜色(信息-黑色,警告-橙色,错误-红色)
- 跳过无变化的文件重命名操作
- 显示找到的文件数量
### 使用说明:
1. **界面布局**:
- 顶部:目标路径选择区域
- 中部:重命名规则区域(可滚动)
- 底部:日志区域(带滚动条)
2. **操作流程**:
1. 选择目标路径(手动输入或浏览)
2. 添加重命名规则(点击"添加规则"按钮)
3. 在规则行中设置查找字符串和替换字符串
4. 点击"执行"按钮执行单个规则的重命名
5. 所有操作结果实时显示在日志框中
3. **日志功能**:
- 自动记录所有操作和结果
- 不同级别日志使用不同颜色
- 每条日志包含时间戳
- 支持滚动查看历史记录
4. **关闭程序**:
- 自动保存所有配置到JSON文件
- 添加关闭日志记录
### 优势:
1. **无干扰操作**:不再弹出干扰性的消息框
2. **完整历史记录**:所有操作都有日志记录,便于追溯
3. **错误诊断**:详细的错误信息帮助快速定位问题
4. **操作透明**:实时显示每一步操作的结果
5. **用户体验**:不同级别的日志使用不同颜色,提高可读性