fuzzy search add-in for excel

本文介绍了一款为Excel设计的模糊查找插件,该插件能够帮助用户更高效地进行数据匹配和处理工作。通过使用此插件,可以显著提高数据处理的速度和准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. http://blogs.msdn.com/b/business_intelligence_labs/archive/2011/04/27/fuzzy-lookup-add-in-for-excel.aspx?Redirected=true
  2. http://www.microsoft.com/en-us/download/details.aspx?id=15011

转载于:https://www.cnblogs.com/dmdj/p/3630536.html

import os import re import time import logging import tkinter as tk from tkinter import ttk, messagebox, filedialog, scrolledtext from collections import Counter import openpyxl import datetime 增强的日志配置 def setup_logger(): “”“配置并返回日志记录器”“” logger = logging.getLogger(‘SCLMultiProcessor’) logger.setLevel(logging.DEBUG) # 创建文件处理器 log_file = 'scl_processor.log' file_handler = logging.FileHandler(log_file, encoding='utf-8') file_handler.setLevel(logging.DEBUG) # 创建控制台处理器 console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) # 创建格式化器 formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) # 应用格式化器 file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) # 添加处理器 logger.addHandler(file_handler) logger.addHandler(console_handler) # 记录启动信息 logger.info("=" * 50) logger.info(f"SCL Multi-Processor 启动于 {datetime.datetime.now()}") logger.info("=" * 50) return logger 获取日志记录器 logger = setup_logger() class ExcelColorDetector: “”“Excel单元格颜色检测器”“” def init(self): self.NO_FILL = “无填充” def is_no_fill(self, cell): """检查单元格是否无填充颜色""" try: # 检查是否存在填充属性 if not hasattr(cell, 'fill') or cell.fill is None: return True # 检查填充类型 if cell.fill.patternType is None or cell.fill.patternType == 'none': return True # 检查背景色是否为默认(白色或无) if hasattr(cell.fill, 'bgColor') and cell.fill.bgColor.rgb == '00000000': return True return False except Exception as e: logger.error(f"颜色检测错误: {str(e)}") return True class ColumnFinder: “”“列查找器,支持任意位置查找列名”“” def init(self, sheet, max_search_rows=100): self.sheet = sheet self.max_search_rows = max_search_rows self.column_positions = {} logger.debug(f"列查找器初始化: 最大搜索行数={max_search_rows}") def find_column(self, column_name): """查找指定列名在表格中的位置""" logger.debug(f"查找列: {column_name}") if column_name in self.column_positions: pos = self.column_positions[column_name] logger.debug(f"从缓存中找到列: {column_name} -> {pos}") return pos # 在指定行数范围内查找 max_row = min(self.sheet.max_row, self.max_search_rows) logger.debug(f"搜索范围: 1-{max_row}行") for row_idx in range(1, max_row + 1): for col_idx in range(1, self.sheet.max_column + 1): cell = self.sheet.cell(row=row_idx, column=col_idx) if cell.value and str(cell.value).strip() == column_name: pos = (row_idx, col_idx) self.column_positions[column_name] = pos logger.info(f"找到列 '{column_name}' 位置: 行={row_idx}, 列={col_idx}") return pos logger.warning(f"未找到列: {column_name}") return None 在SCL处理器中使用高级列查找器 class SCLMultiProcessor: def init(self, root): self.root = root self.root.title(“SCL文件处理系统 - 多条件统计版”) self.root.geometry(“1000x700”) # 初始化变量 self.input_file = None self.color_detector = ExcelColorDetector() self.progress_var = tk.DoubleVar() # 列映射表 self.target_columns = { "diff_no_fill": 16, # P列 "diff_fill": 23, # W列 "diff_add_no_fill": 27, # AA列 "diff_add_fill": 30, # AD列 "diff_change_no_fill": 34, # AH列 "diff_change_fill": 37, # AK列 "diff_delete_no_fill": 42, # AP列 "diff_delete_fill": 45, # AS列 "valid_yes_no_fill": 50, # AX列 "valid_yes_fill": 53, # BA列 "valid_no_no_fill": 57, # BE列 "valid_no_fill": 60, # BH列 "valid_yes_reason_no_fill": 62, # BL列 "valid_yes_reason_fill": 65, # BO列 "valid_no_reason_no_fill": 71, # BS列 "valid_no_reason_fill": 74, # BV列 "background_no_fill": 78, # BZ列 "background_fill": 85 # CG列 } # 创建主框架 self.main_frame = ttk.Frame(root, padding="10") self.main_frame.pack(fill=tk.BOTH, expand=True) # 创建UI self.create_ui() # 记录UI初始化完成 logger.info("用户界面初始化完成") def create_ui(self): """创建用户界面""" # 文件选择区域 file_frame = ttk.LabelFrame(self.main_frame, text="文件选择", padding="10") file_frame.pack(fill=tk.X, pady=5) # 输入文件选择 input_frame = ttk.Frame(file_frame) input_frame.pack(fill=tk.X, pady=5) ttk.Label(input_frame, text="输入文件:").pack(side=tk.LEFT, padx=5) self.input_path_var = tk.StringVar() input_entry = ttk.Entry(input_frame, textvariable=self.input_path_var, width=70) input_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) ttk.Button(input_frame, text="浏览...", command=self.browse_input_file).pack(side=tk.LEFT, padx=5) # 配置区域 config_frame = ttk.LabelFrame(self.main_frame, text="处理配置", padding="10") config_frame.pack(fill=tk.X, pady=5) # 列名配置 col_frame = ttk.Frame(config_frame) col_frame.pack(fill=tk.X, pady=5) ttk.Label(col_frame, text="差分列名:").grid(row=0, column=0, padx=5, sticky=tk.W) self.diff_col_var = tk.StringVar(value="差分種別") ttk.Entry(col_frame, textvariable=self.diff_col_var, width=15).grid(row=0, column=1, padx=5, sticky=tk.W) ttk.Label(col_frame, text="备注列名:").grid(row=0, column=2, padx=5, sticky=tk.W) self.note_col_var = tk.StringVar(value="备注") ttk.Entry(col_frame, textvariable=self.note_col_var, width=15).grid(row=0, column=3, padx=5, sticky=tk.W) ttk.Label(col_frame, text="判断列名:").grid(row=1, column=0, padx=5, sticky=tk.W) self.valid_col_var = tk.StringVar(value="差分の判断有意/無効") ttk.Entry(col_frame, textvariable=self.valid_col_var, width=15).grid(row=1, column=1, padx=5, sticky=tk.W) ttk.Label(col_frame, text="理由列名:").grid(row=1, column=2, padx=5, sticky=tk.W) self.reason_col_var = tk.StringVar(value="判断理由") ttk.Entry(col_frame, textvariable=self.reason_col_var, width=15).grid(row=1, column=3, padx=5, sticky=tk.W) ttk.Label(col_frame, text="背景列名:").grid(row=1, column=4, padx=5, sticky=tk.W) self.background_col_var = tk.StringVar(value="変更背景") ttk.Entry(col_frame, textvariable=self.background_col_var, width=15).grid(row=1, column=5, padx=5, sticky=tk.W) # 搜索选项 search_frame = ttk.Frame(config_frame) search_frame.pack(fill=tk.X, pady=5) ttk.Label(search_frame, text="最大搜索行数:").grid(row=0, column=0, padx=5, sticky=tk.W) self.max_search_var = tk.IntVar(value=100) ttk.Entry(search_frame, textvariable=self.max_search_var, width=5).grid(row=0, column=1, padx=5, sticky=tk.W) ttk.Label(search_frame, text="文件前缀:").grid(row=0, column=2, padx=5, sticky=tk.W) self.prefix_var = tk.StringVar(value="SCL_") ttk.Entry(search_frame, textvariable=self.prefix_var, width=10).grid(row=0, column=3, padx=5, sticky=tk.W) # 日志选项 log_frame = ttk.Frame(config_frame) log_frame.pack(fill=tk.X, pady=5) ttk.Label(log_frame, text="日志级别:").grid(row=0, column=0, padx=5, sticky=tk.W) self.log_level_var = tk.StringVar(value="INFO") log_level_combo = ttk.Combobox( log_frame, textvariable=self.log_level_var, width=10, state="readonly" ) log_level_combo['values'] = ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL') log_level_combo.grid(row=0, column=1, padx=5, sticky=tk.W) log_level_combo.bind("<<ComboboxSelected>>", self.change_log_level) # 处理按钮 btn_frame = ttk.Frame(self.main_frame) btn_frame.pack(fill=tk.X, pady=10) ttk.Button(btn_frame, text="开始处理", command=self.process_file).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="查看日志", command=self.view_log).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="导出配置", command=self.export_config).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="加载配置", command=self.load_config).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="清空日志", command=self.clear_log).pack(side=tk.LEFT, padx=5) # 进度条 progress_frame = ttk.Frame(self.main_frame) progress_frame.pack(fill=tk.X, pady=5) ttk.Label(progress_frame, text="处理进度:").pack(side=tk.LEFT, padx=5) self.progress_bar = ttk.Progressbar( progress_frame, variable=self.progress_var, maximum=100, length=700 ) self.progress_bar.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) self.progress_label = ttk.Label(progress_frame, text="0%") self.progress_label.pack(side=tk.LEFT, padx=5) # 结果展示区域 result_frame = ttk.LabelFrame(self.main_frame, text="处理结果", padding="10") result_frame.pack(fill=tk.BOTH, expand=True, pady=5) # 结果文本框 self.result_text = scrolledtext.ScrolledText( result_frame, wrap=tk.WORD, height=20 ) self.result_text.pack(fill=tk.BOTH, expand=True) self.result_text.config(state=tk.DISABLED) # 状态栏 self.status_var = tk.StringVar(value="就绪") status_bar = ttk.Label(self.main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W) status_bar.pack(fill=tk.X, pady=5) logger.info("UI创建完成") def change_log_level(self, event=None): """更改日志级别""" level = self.log_level_var.get() logger.setLevel(getattr(logging, level)) logger.info(f"日志级别已更改为: {level}") def clear_log(self): """清空日志文件""" try: with open('scl_processor.log', 'w', encoding='utf-8') as log_file: log_file.write("") logger.info("日志文件已清空") messagebox.showinfo("成功", "日志文件已清空") except Exception as e: logger.error(f"清空日志失败: {str(e)}") messagebox.showerror("错误", f"清空日志失败: {str(e)}") def browse_input_file(self): """浏览输入文件""" file_path = filedialog.askopenfilename( filetypes=[ ("Excel 文件", "*.xlsx *.xls"), ("所有文件", "*.*") ] ) if file_path: self.input_path_var.set(file_path) self.input_file = file_path logger.info(f"已选择输入文件: {file_path}") def process_file(self): """处理文件""" if not self.input_file: messagebox.showwarning("警告", "请先选择输入文件") logger.warning("未选择输入文件") return try: # 重置结果 self.result_text.config(state=tk.NORMAL) self.result_text.delete(1.0, tk.END) self.result_text.insert(tk.END, "开始处理...\n") self.result_text.see(tk.END) self.result_text.config(state=tk.DISABLED) self.status_var.set("开始处理文件...") self.root.update() # 获取输入文件目录 input_dir = os.path.dirname(self.input_file) logger.info(f"开始处理文件: {self.input_file}") logger.info(f"文件目录: {input_dir}") # 使用openpyxl加载工作簿(保留格式) wb = openpyxl.load_workbook(self.input_file) sheet = wb.active logger.info(f"工作簿加载成功, 工作表: {sheet.title}") # 获取配置参数 diff_col_name = self.diff_col_var.get() note_col_name = self.note_col_var.get() valid_col_name = self.valid_col_var.get() reason_col_name = self.reason_col_var.get() background_col_name = self.background_col_var.get() prefix = self.prefix_var.get() max_search_rows = self.max_search_var.get() logger.info(f"配置参数: 差分列名={diff_col_name}, 备注列名={note_col_name}") logger.info(f"判断列名={valid_col_name}, 理由列名={reason_col_name}, 背景列名={background_col_name}") # 扫描E列(第5列) total_rows = sheet.max_row processed_count = 0 found_files = 0 logger.info(f"开始扫描E列, 总行数: {total_rows}") start_time = time.time() for row_idx in range(1, total_rows + 1): # 更新进度 progress = (row_idx / total_rows) * 100 self.progress_var.set(progress) self.progress_label.config(text=f"{progress:.1f}%") self.root.update() cell = sheet.cell(row=row_idx, column=5) cell_value = str(cell.value) if cell.value else "" # 检查是否包含前缀的文件名 if prefix in cell_value: # 提取文件名(可能有多个以空格分隔) file_names = re.findall(fr'{prefix}[^\s]+', cell_value) logger.info(f"行 {row_idx}: 找到文件: {', '.join(file_names)}") result_lines = [] for file_name in file_names: file_path = os.path.join(input_dir, file_name) # 检查文件是否存在 if not os.path.exists(file_path): result_lines.append(f"{file_name}: 文件不存在") logger.warning(f"文件不存在: {file_path}") continue # 处理SCL文件 results = self.process_scl_file( file_path, diff_col_name, note_col_name, valid_col_name, reason_col_name, background_col_name, max_search_rows ) # 将结果写入主Excel文件的不同列 for rule_name, result_str in results.items(): target_col = self.target_columns.get(rule_name) if target_col: target_cell = sheet.cell(row=row_idx, column=target_col) target_cell.value = result_str # 添加到结果列表 result_lines.append(f"{file_name}: 处理完成") found_files += 1 # 更新结果文本框 self.result_text.config(state=tk.NORMAL) self.result_text.insert( tk.END, f"行 {row_idx} 处理结果:\n" + "\n".join(result_lines) + "\n\n" ) self.result_text.see(tk.END) self.result_text.config(state=tk.DISABLED) processed_count += 1 # 保存修改后的Excel文件 output_path = self.input_file.replace(".xlsx", "_processed.xlsx") wb.save(output_path) logger.info(f"结果已保存到: {output_path}") elapsed_time = time.time() - start_time self.status_var.set(f"处理完成! 找到 {found_files} 个文件, 耗时 {elapsed_time:.2f} 秒") logger.info(f"处理完成! 找到 {found_files} 个文件, 耗时 {elapsed_time:.2f} 秒") # 更新结果文本框 self.result_text.config(state=tk.NORMAL) self.result_text.insert( tk.END, f"\n处理完成! 找到 {found_files} 个文件, 耗时 {elapsed_time:.2f} 秒\n" f"结果已保存到: {output_path}\n" ) self.result_text.see(tk.END) self.result_text.config(state=tk.DISABLED) messagebox.showinfo("完成", f"处理完成! 找到 {found_files} 个文件\n结果已保存到: {output_path}") except Exception as e: error_msg = f"处理文件时出错: {str(e)}" logger.exception(f"处理文件时出错: {str(e)}") messagebox.showerror("错误", error_msg) self.status_var.set(f"错误: {str(e)}") # 更新结果文本框 self.result_text.config(state=tk.NORMAL) self.result_text.insert(tk.END, f"\n错误: {error_msg}\n") self.result_text.see(tk.END) self.result_text.config(state=tk.DISABLED) def process_scl_file(self, file_path, diff_col_name, note_col_name, valid_col_name, reason_col_name, background_col_name, max_search_rows): """处理单个SCL文件并返回所有统计结果""" results = {} try: logger.info(f"开始处理SCL文件: {file_path}") # 加载SCL文件 scl_wb = openpyxl.load_workbook(file_path) scl_sheet = scl_wb.active logger.info(f"工作表加载成功: {scl_sheet.title}, 总行数: {scl_sheet.max_row}") # 创建列查找器 column_finder = AdvancedColumnFinder( scl_sheet, max_search_rows=max_search_rows, fuzzy_match=True # 启用模糊匹配 ) # 查找所有需要的列 diff_col_pos = column_finder.find_column(diff_col_name) note_col_pos = column_finder.find_column(note_col_name) valid_col_pos = column_finder.find_column(valid_col_name) reason_col_pos = column_finder.find_column(reason_col_name) background_col_pos = column_finder.find_column(background_col_name) # 如果找到多行列,则使用起始行作为列头行 if valid_col_pos: valid_header_row, valid_col_idx = valid_col_pos logger.info(f"找到多行列 '{valid_col_name}' 在列 {valid_col_idx}") else: logger.error(f"未找到列: {valid_col_name}") valid_col_idx = None # 获取列索引 diff_col_idx = diff_col_pos[1] if diff_col_pos else None note_col_idx = note_col_pos[1] if note_col_pos else None valid_col_idx = valid_col_pos[1] if valid_col_pos else None reason_col_idx = reason_col_pos[1] if reason_col_pos else None background_col_idx = background_col_pos[1] if background_col_pos else None # 记录列位置 logger.info(f"列位置: 差分={diff_col_idx}, 备注={note_col_idx}, 判断={valid_col_idx}, 理由={reason_col_idx}, 背景={background_col_idx}") # 初始化统计结果 stats = { "diff_no_fill": [], # 规则1 "diff_fill": [], # 规则2 "diff_add_no_fill": [], # 规则3 "diff_add_fill": [], # 规则4 "diff_change_no_fill": [], # 规则5 "diff_change_fill": [], # 规则6 "diff_delete_no_fill": [], # 规则7 "diff_delete_fill": [], # 规则8 "valid_yes_no_fill": [], # 规则9 "valid_yes_fill": [], # 规则10 "valid_no_no_fill": [], # 规则11 "valid_no_fill": [], # 规则12 "valid_yes_reason_no_fill": [], # 规则13 "valid_yes_reason_fill": [], # 规则14 "valid_no_reason_no_fill": [], # 规则15 "valid_no_reason_fill": [], # 规则16 "background_no_fill": [], # 规则17 "background_fill": [] # 规则18 } # 遍历所有行 start_row = max( diff_col_pos[0] if diff_col_pos else 1, note_col_pos[0] if note_col_pos else 1, valid_col_pos[0] if valid_col_pos else 1, reason_col_pos[0] if reason_col_pos else 1, background_col_pos[0] if background_col_pos else 1 ) + 1 logger.info(f"从第 {start_row} 行开始处理数据") for row_idx in range(start_row, scl_sheet.max_row + 1): # 获取所有需要的单元格 diff_cell = scl_sheet.cell(row_idx, diff_col_idx) if diff_col_idx else None note_cell = scl_sheet.cell(row_idx, note_col_idx) if note_col_idx else None valid_cell = scl_sheet.cell(row_idx, valid_col_idx) if valid_col_idx else None reason_cell = scl_sheet.cell(row_idx, reason_col_idx) if reason_col_idx else None background_cell = scl_sheet.cell(row_idx, background_col_idx) if background_col_idx else None # 获取备注值 note_value = str(note_cell.value).strip() if note_cell and note_cell.value else None # 规则1: 差分种别无颜色填充 if diff_cell and self.color_detector.is_no_fill(diff_cell) and note_value: stats["diff_no_fill"].append(note_value) # 规则2: 差分种别有颜色填充 if diff_cell and not self.color_detector.is_no_fill(diff_cell) and note_value: stats["diff_fill"].append(note_value) # 规则3: 差分种别="追加"且无颜色填充 if (diff_cell and diff_cell.value == "追加" and self.color_detector.is_no_fill(diff_cell) and note_value): stats["diff_add_no_fill"].append(note_value) # 规则4: 差分种别="追加"且有颜色填充 if (diff_cell and diff_cell.value == "追加" and not self.color_detector.is_no_fill(diff_cell) and note_value): stats["diff_add_fill"].append(note_value) # 规则5: 差分种别="変更"且无颜色填充 if (diff_cell and diff_cell.value == "変更" and self.color_detector.is_no_fill(diff_cell) and note_value): stats["diff_change_no_fill"].append(note_value) # 规则6: 差分种别="変更"且有颜色填充 if (diff_cell and diff_cell.value == "変更" and not self.color_detector.is_no_fill(diff_cell) and note_value): stats["diff_change_fill"].append(note_value) # 规则7: 差分种别="削除"且无颜色填充 if (diff_cell and diff_cell.value == "削除" and self.color_detector.is_no_fill(diff_cell) and note_value): stats["diff_delete_no_fill"].append(note_value) # 规则8: 差分种别="削除"且有颜色填充 if (diff_cell and diff_cell.value == "削除" and not self.color_detector.is_no_fill(diff_cell) and note_value): stats["diff_delete_fill"].append(note_value) # 规则9: 判断="有意"且无颜色填充 if (valid_cell and valid_cell.value == "有意" and self.color_detector.is_no_fill(valid_cell) and note_value): stats["valid_yes_no_fill"].append(note_value) # 规则10: 判断="有意"且有颜色填充 if (valid_cell and valid_cell.value == "有意" and not self.color_detector.is_no_fill(valid_cell) and note_value): stats["valid_yes_fill"].append(note_value) # 规则11: 判断="無効"且无颜色填充 if (valid_cell and valid_cell.value == "無効" and self.color_detector.is_no_fill(valid_cell) and note_value): stats["valid_no_no_fill"].append(note_value) # 规则12: 判断="無効"且有颜色填充 if (valid_cell and valid_cell.value == "無効" and not self.color_detector.is_no_fill(valid_cell) and note_value): stats["valid_no_fill"].append(note_value) # 规则13: 判断="有意"且理由无颜色填充 if (valid_cell and valid_cell.value == "有意" and reason_cell and self.color_detector.is_no_fill(reason_cell) and note_value): stats["valid_yes_reason_no_fill"].append(note_value) # 规则14: 判断="有意"且理由有颜色填充 if (valid_cell and valid_cell.value == "有意" and reason_cell and not self.color_detector.is_no_fill(reason_cell) and note_value): stats["valid_yes_reason_fill"].append(note_value) # 规则15: 判断="無効"且理由无颜色填充 if (valid_cell and valid_cell.value == "無効" and reason_cell and self.color_detector.is_no_fill(reason_cell) and note_value): stats["valid_no_reason_no_fill"].append(note_value) # 规则16: 判断="無効"且理由有颜色填充 if (valid_cell and valid_cell.value == "無効" and reason_cell and not self.color_detector.is_no_fill(reason_cell) and note_value): stats["valid_no_reason_fill"].append(note_value) # 规则17: 背景无颜色填充 if background_cell and self.color_detector.is_no_fill(background_cell) and note_value: stats["background_no_fill"].append(note_value) # 规则18: 背景有颜色填充 if background_cell and not self.color_detector.is_no_fill(background_cell) and note_value: stats["background_fill"].append(note_value) # 处理统计结果 for rule, values in stats.items(): if not values: results[rule] = "/" logger.info(f"{rule}: 无数据") else: counter = Counter(values) result_lines = [f"{value},{count}" for value, count in counter.most_common()] results[rule] = "\n".join(result_lines) logger.info(f"{rule}: 找到 {len(values)} 条数据") return results except Exception as e: error_msg = f"处理SCL文件失败: {str(e)}" logger.exception(f"处理SCL文件失败: {file_path} - {str(e)}") # 返回错误信息 return {rule: f"错误: {str(e)}" for rule in self.target_columns} def view_log(self): """查看日志""" log_window = tk.Toplevel(self.root) log_window.title("处理日志") log_window.geometry("800x600") log_frame = ttk.Frame(log_window, padding="10") log_frame.pack(fill=tk.BOTH, expand=True) # 日志文本框 log_text = scrolledtext.ScrolledText( log_frame, wrap=tk.WORD, height=30 ) log_text.pack(fill=tk.BOTH, expand=True) # 读取日志文件 log_file = 'scl_processor.log' try: if not os.path.exists(log_file): with open(log_file, 'w', encoding='utf-8') as f: f.write("日志文件已创建,暂无记录\n") with open(log_file, 'r', encoding='utf-8') as log_file: log_content = log_file.read() log_text.insert(tk.END, log_content) except Exception as e: log_text.insert(tk.END, f"无法读取日志文件: {str(e)}") # 设置为只读 log_text.config(state=tk.DISABLED) # 添加刷新按钮 refresh_btn = ttk.Button(log_frame, text="刷新日志", command=lambda: self.refresh_log(log_text)) refresh_btn.pack(pady=5) logger.info("日志查看窗口已打开") def refresh_log(self, log_text): """刷新日志内容""" log_text.config(state=tk.NORMAL) log_text.delete(1.0, tk.END) try: with open('scl_processor.log', 'r', encoding='utf-8') as log_file: log_content = log_file.read() log_text.insert(tk.END, log_content) except Exception as e: log_text.insert(tk.END, f"刷新日志失败: {str(e)}") log_text.config(state=tk.DISABLED) log_text.see(tk.END) logger.info("日志已刷新") def export_config(self): """导出配置到文件""" config = { "diff_col": self.diff_col_var.get(), "note_col": self.note_col_var.get(), "valid_col": self.valid_col_var.get(), "reason_col": self.reason_col_var.get(), "background_col": self.background_col_var.get(), "prefix": self.prefix_var.get(), "max_search": self.max_search_var.get(), "log_level": self.log_level_var.get() } file_path = filedialog.asksaveasfilename( defaultextension=".json", filetypes=[("JSON 文件", "*.json"), ("所有文件", "*.*")] ) if file_path: try: with open(file_path, 'w', encoding='utf-8') as f: f.write(str(config)) messagebox.showinfo("成功", f"配置已导出到: {file_path}") logger.info(f"配置已导出到: {file_path}") except Exception as e: messagebox.showerror("错误", f"导出配置失败: {str(e)}") logger.error(f"导出配置失败: {str(e)}") def load_config(self): """从文件加载配置""" file_path = filedialog.askopenfilename( filetypes=[("JSON 文件", "*.json"), ("所有文件", "*.*")] ) if file_path: try: with open(file_path, 'r', encoding='utf-8') as f: config = eval(f.read()) self.diff_col_var.set(config.get("diff_col", "差分種別")) self.note_col_var.set(config.get("note_col", "备注")) self.valid_col_var.set(config.get("valid_col", "差分の判断\n有意/無効")) self.reason_col_var.set(config.get("reason_col", "判断理由")) self.background_col_var.set(config.get("background_col", "変更背景")) self.prefix_var.set(config.get("prefix", "SCL_")) self.max_search_var.set(config.get("max_search", 100)) self.log_level_var.set(config.get("log_level", "INFO")) self.change_log_level() messagebox.showinfo("成功", "配置已加载") logger.info(f"配置已从 {file_path} 加载") except Exception as e: messagebox.showerror("错误", f"加载配置失败: {str(e)}") logger.error(f"加载配置失败: {str(e)}") if name == “main”: root = tk.Tk() app = SCLMultiProcessor(root) root.mainloop() 在这个上面改,差分の判断有意/無効是列名,在一个单元格内分成了两行,我希望正确查找这个列名
08-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值