Python GUI无法终止ocrmypdf.ocr()进程的问题求助
解决方案
核心问题是ocrmypdf.ocr()属于阻塞式调用,直接在GUI主线程运行会导致界面无响应,且无法中途终止。需要将OCR任务放到子线程/子进程中执行,并实现可终止逻辑。
1. 实现取消按钮立即终止任务
方案:使用多进程运行OCR任务(推荐)
多进程可以直接强制终止,避免线程无法直接终止的问题。
import multiprocessing import ocrmypdf from tkinter import Tk, Button, messagebox class PDFProcessor: def __init__(self, root): self.root = root self.current_process = None self.is_running = False # 初始化按钮 self.start_btn = Button(root, text="开始", command=self.start_task) self.start_btn.pack() self.cancel_btn = Button(root, text="取消", command=self.cancel_task) self.cancel_btn.pack() self.close_btn = Button(root, text="关闭", command=self.close_app) self.close_btn.pack() # 绑定窗口关闭事件 self.root.protocol("WM_DELETE_WINDOW", self.close_app) def ocr_task(self, input_path, output_path): """子进程执行的OCR任务""" try: ocrmypdf.ocr(input_path, output_path, skip_text=False) # 根据需求调整参数 except Exception: pass # 可添加错误处理 finally: self.is_running = False def start_task(self): """开始按钮回调""" if self.is_running: return # 实际应用中从GUI获取输入输出路径和关键词 input_pdf = "不可搜索.pdf" output_pdf = "可搜索.pdf" self.is_running = True # 启动子进程执行OCR self.current_process = multiprocessing.Process(target=self.ocr_task, args=(input_pdf, output_pdf)) self.current_process.start() def cancel_task(self): """取消按钮回调""" if not self.is_running or self.current_process is None: return # 终止子进程并回收资源 self.current_process.terminate() self.current_process.join() self.is_running = False messagebox.showinfo("提示", "任务已取消") # 运行GUI if __name__ == "__main__": root = Tk() app = PDFProcessor(root) root.mainloop()
备选方案:使用线程+杀死ocrmypdf子进程
如果不想用多进程,可借助psutil库找到ocrmypdf启动的子进程并终止:
import threading import ocrmypdf import psutil import os from tkinter import Tk, Button, messagebox class PDFProcessor: def __init__(self, root): self.root = root self.ocr_thread = None self.is_running = False self.ocr_child_pid = None self.start_btn = Button(root, text="开始", command=self.start_task) self.start_btn.pack() self.cancel_btn = Button(root, text="取消", command=self.cancel_task) self.cancel_btn.pack() self.close_btn = Button(root, text="关闭", command=self.close_app) self.close_btn.pack() self.root.protocol("WM_DELETE_WINDOW", self.close_app) def get_ocr_child_pid(self): """查找ocrmypdf启动的子进程PID""" current_pid = os.getpid() parent_proc = psutil.Process(current_pid) for child in parent_proc.children(recursive=True): if "tesseract" in child.name() or "ocrmypdf" in child.name(): return child.pid return None def ocr_task(self, input_path, output_path): try: ocrmypdf.ocr(input_path, output_path) except Exception: pass finally: self.is_running = False self.ocr_child_pid = None def start_task(self): if self.is_running: return input_pdf = "不可搜索.pdf" output_pdf = "可搜索.pdf" self.is_running = True self.ocr_thread = threading.Thread(target=self.ocr_task, args=(input_pdf, output_pdf)) self.ocr_thread.start() # 延迟等待子进程启动,再获取PID import time time.sleep(1) self.ocr_child_pid = self.get_ocr_child_pid() def cancel_task(self): if not self.is_running: return # 杀死ocrmypdf子进程 if self.ocr_child_pid: try: proc = psutil.Process(self.ocr_child_pid) proc.terminate() proc.wait() except psutil.NoSuchProcess: pass self.is_running = False if self.ocr_thread: self.ocr_thread.join(timeout=2) messagebox.showinfo("提示", "任务已取消") if __name__ == "__main__": root = Tk() app = PDFProcessor(root) root.mainloop()
2. 实现关闭按钮的确认逻辑
在close_app方法中加入运行状态检查,将以下代码添加到上述类中:
def close_app(self): """关闭按钮/窗口关闭事件回调""" if self.is_running: confirm = messagebox.askyesno("确认关闭", "当前有任务在运行,是否终止任务并关闭程序?") if not confirm: return # 先执行取消逻辑 self.cancel_task() # 关闭GUI窗口 self.root.destroy()
内容的提问来源于stack exchange,提问作者Challa Poorna chandu
相关产品推荐
相关产品推荐

