You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:37:45