①新增方法:打开差分文档和SCL EXCEL文件
def open_diff_doc_and_scl(data, office_instances, scl_file_path):
“”“打开差分文档和对应的SCL文件”“”
filename = data.get(“filename”)
fext = os.path.splitext(filename)[1]
scl_instance = None
# 打开差分文档 if fext in [".doc", ".docx", ".docm"]: app, fullname = open_word_document_ex(filename) office_instances.append((app, fullname)) elif fext in [".xls", ".xlsx", ".xlsm"]: app, fullname = open_excel_document_ex(filename) office_instances.append((app, fullname)) # 打开对应的SCL文件 scl_app, scl_fullname = open_excel_document_ex(scl_file_path) scl_instance = (scl_app, scl_fullname) # 调整窗口布局(包含SCL文件) diff_office_ui_layout(office_instances, scl_instance)
return scl_instance
②调整完整窗口布局,在原方法上修改:
def diff_office_ui_layout(office_instances, scl_instance=None):
“”“窗口布局:差分文档左右排列在上半部分,SCL文件在下半部分”“”
# 获取屏幕尺寸
screen_width = win32api.GetSystemMetrics(0)
screen_height = win32api.GetSystemMetrics(1)
# 计算各区域尺寸 half_width = screen_width // 2 half_height = screen_height // 2 quarter_height = screen_height // 4 # 处理差分文档窗口(最多两个) doc_instances = [inst for inst in office_instances if not scl_instance or inst[1] != scl_instance[1]] for idx, (app, fullname) in enumerate(doc_instances[:2]): try: window_title = os.path.basename(fullname) hwnd = find_window(window_title) if hwnd: # 第一个文档在左上角 if idx == 0: move_window(hwnd, 0, 0, half_width, half_height) # 第二个文档在右上角 elif idx == 1: move_window(hwnd, half_width, 0, half_width, half_height) # 确保窗口可见 win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) win32gui.BringWindowToTop(hwnd) except Exception as e: logging.error(f"Adjusting doc window failed: {str(e)}") # 处理SCL文件窗口(如果存在) if scl_instance: try: scl_app, scl_fullname = scl_instance scl_title = os.path.basename(scl_fullname) scl_hwnd = find_window(scl_title) if scl_hwnd: # SCL文件占据整个下半部分 move_window(scl_hwnd, 0, half_height, screen_width, half_height) # 确保窗口可见 win32gui.ShowWindow(scl_hwnd, win32con.SW_RESTORE) win32gui.BringWindowToTop(scl_hwnd) # Excel特定优化:激活工作表滚动区域 if get_file_type(scl_fullname) == "excel": scl_app.Visible = True scl_app.WindowState = win32com.client.constants.xlNormal except Exception as e: logging.error(f"Adjusting SCL window failed: {str(e)}")
③在原方法init_com_diff上修改,加上了SCL初始化
def init_com_diff(data: dict, office_instances: list, scl_instance=None):
“”“初始化差分文档并调整窗口布局”“”
logging.info(“Initializing COM components for diff documents”)
fext = data.get(“fext”)
file_list = data.get(“file_list”)
# 确保只保留当前需要显示的文档实例 active_files = set(file_list) to_remove = [] for i, (app, fullname) in enumerate(office_instances): if fullname not in active_files: to_remove.append(i) # 反向删除以避免索引问题 for i in sorted(to_remove, reverse=True): try: app, fullname = office_instances.pop(i) close_pre_instance([(app, fullname)]) logging.info(f"Closed unused document: {fullname}") except Exception as e: logging.error(f"Error closing document instance: {str(e)}") # 打开新的文档 for file in file_list: # 检查是否已经打开 already_open = False for _, fullname in office_instances: if file == fullname and find_window(os.path.basename(file)): already_open = True break if not already_open: logging.info(f"Opening new document: {file}") try: if fext in [".doc", ".docx", ".docm"]: office_instances.append(open_word_document_ex(file)) elif fext in [".xls", ".xlsx", ".xlsm"]: office_instances.append(open_excel_document_ex(file)) except Exception as e: logging.error(f"Error opening document {file}: {str(e)}") # 调整窗口布局(包含SCL文件) diff_office_ui_layout(office_instances, scl_instance) logging.info("Document initialization complete")
adjust_layout_with_scl(OFFICE_INSTANCES, SCL_INSTANCE)
④更健壮的window打开函数
def open_excel_document_ex(file_path):
“”“打开Excel文档并返回应用实例和完整路径”“”
try:
excel = win32com.client.Dispatch(“Excel.Application”)
excel.Visible = True
wb = excel.Workbooks.Open(file_path)
excel.WindowState = win32com.client.constants.xlNormal # 确保窗口正常状态
return excel, os.path.abspath(file_path)
except Exception as e:
logging.error(f"Error opening Excel document: {str(e)}")
return None, file_path
def open_word_document_ex(file_path):
“”“打开Word文档并返回应用实例和完整路径”“”
try:
word = win32com.client.Dispatch(“Word.Application”)
word.Visible = True
doc = word.Documents.Open(file_path)
word.WindowState = win32com.client.constants.wdWindowStateNormal # 确保窗口正常状态
return word, os.path.abspath(file_path)
except Exception as e:
logging.error(f"Error opening Word document: {str(e)}")
return None, file_path
def find_window(window_title, timeout=5):
“”“更健壮的窗口查找函数,支持超时重试”“”
start_time = time.time()
hwnd = win32gui.FindWindow(None, window_title)
# 如果找不到窗口,尝试模糊匹配 while not hwnd and (time.time() - start_time) < timeout: windows = [] def callback(hwnd, extra): if win32gui.IsWindowVisible(hwnd): title = win32gui.GetWindowText(hwnd) if window_title in title: windows.append(hwnd) win32gui.EnumWindows(callback, None) if windows: return windows[0] # 返回第一个匹配的窗口 # 等待一段时间后重试 time.sleep(0.3) hwnd = win32gui.FindWindow(None, window_title)
return hwnd
⑤安全关闭所有实例,在原方法上修改的,添加了SCL
def close_office_instances(instances):
“”“安全关闭所有Office文档实例”“”
for app, fullname in instances:
try:
if isinstance(app, win32com.client.Dispatch):
file_type = get_file_type(fullname)
if file_type == “word”:
app.Documents.Close(False)
app.Quit()
elif file_type == “excel”:
app.Workbooks.Close()
app.Quit()
except Exception as e:
logging.error(f"Error closing document {fullname}: {str(e)}")
⑥定位SCL文件中的变更点行,变更点行号=变更点序号+3
def highlight_scl_excel(data):
“”“高亮SCL Excel文件中的变更点行”“”
change_index = data.get(“change_index”)
filename = data.get(“filename”)
if not filename or change_index is None: logging.warning("缺少文件名或变更点序号") return False basename = os.path.basename(filename) scl_instance = scl_instances.get(basename) if scl_instance: scl_app, scl_fullname = scl_instance # 计算目标行(变更点序号→行号映射) target_row = change_index + 3 # 基础行号映射 # 查找Excel窗口句柄 hwnd = find_window(basename) if hwnd: # 激活并置顶Excel窗口 win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) win32gui.SetForegroundWindow(hwnd) try: # 获取当前活动的Excel应用实例 if scl_app: excel = scl_app else: excel = win32com.client.GetActiveObject("Excel.Application") # 遍历所有打开的工作簿 for workbook in excel.Workbooks: # 检查是否为目标工作簿 if workbook.FullName.lower() == scl_fullname.lower(): try: # 获取活动工作表 sheet = workbook.ActiveSheet # 清除之前的高亮 clear_excel_highlights(sheet) # 高亮目标行(Excel行号从1开始) target_range = sheet.Rows(target_row) target_range.Interior.Color = 0xFFFF00 # RGB黄色 # 添加变更点标记 add_change_marker(sheet, target_row, change_index) # 滚动到可见位置(目标行上方5行) excel.ActiveWindow.ScrollRow = max(1, target_row - 5) logging.info(f"已高亮变更点 #{change_index} (行号: {target_row})") return True except Exception as e: logging.error(f"高亮Excel行时出错: {str(e)}") logging.warning(f"未找到工作簿: {basename}") except Exception as e: logging.error(f"访问Excel时出错: {str(e)}") else: logging.warning(f"未找到Excel窗口: {basename}") else: logging.warning(f"未找到SCL实例: {basename}")
return False
⑦清除工作表中所有高亮
def clear_excel_highlights(sheet):
“”“清除工作表中的所有高亮”“”
try:
# 遍历所有行,清除黄色高亮
last_row = sheet.UsedRange.Rows.Count
for row in range(1, last_row + 1):
if sheet.Rows(row).Interior.Color == 0xFFFF00:
sheet.Rows(row).Interior.ColorIndex = 0 # 清除颜色
except Exception as e:
logging.warning(f"清除高亮时出错: {str(e)}")
⑧在指定行添加变更点标记
def add_change_marker(sheet, row, change_index):
“”“在指定行添加变更点标记”“”
try:
# 在变更点行的右侧添加标记
sheet.Cells(row, 1).Value = f"变更点 #{change_index}"
sheet.Cells(row, 1).Font.Bold = True
sheet.Cells(row, 1).Font.Color = 0xFF0000 # 红色
except Exception as e:
logging.warning(f"添加变更标记失败: {str(e)}")
⑨修改方法task_handler,新增SCL部分
def task_handler(queue):
“”“任务处理器,负责Office的所有操作”“”
logging.info(“[task handler] sub thread start to run.”)
# 存储Office的实例 office_instances = [] # 存储SCL文件的实例 scl_instances = {}
用上述的子方法,刚刚的代码又重新加了好几个功能,
# 打开文档
if label == "open":
pythoncom.CoInitialize()
init_com_diff(data, office_instances)
# pythoncom.CoUninitialize()
# 文档定位
elif label == "operate" and office_instances:
pythoncom.CoInitialize()
office_location(data, office_instances)
# pythoncom.CoUninitialize()
# 关闭文档
elif label == "close" and office_instances:
pythoncom.CoInitialize()
close_office_instances(office_instances)
# 清除标记
elif label == "clear" and office_instances:
pythoncom.CoInitialize()
clear_office_mark(data, office_instances)
# 重置office界面
elif label == "reset" and office_instances:
diff_office_ui_layout(office_instances)
我只需要这几个,SCL文件和差分文档一起打开
最新发布