开发双PDF同窗口渲染程序遇到三类技术问题求助
试卷与答卷PDF同窗口渲染问题修复
我正在开发一款程序,用于导入试卷PDF和答卷PDF两份文件,要求将二者在同一窗口中渲染并支持垂直滚动。以下是修复后的Python代码:
import tkinter as tk from tkinter import filedialog from tkinter import ttk from PIL import Image, ImageTk import os from pdf2image import convert_from_path class PDFViewerApp: def __init__(self, root): self.root = root self.root.title("PDF Question Cropper") self.frame = ttk.Frame(self.root) self.frame.pack(fill="both", expand=True) self.question_file = None self.answer_file = None self.question_label = ttk.Label(self.frame, text="No question file selected.") self.question_label.pack(pady=5) self.select_question_button = ttk.Button(self.frame, text="Select Question PDF", command=self.select_question_pdf) self.select_question_button.pack(pady=5) self.answer_label = ttk.Label(self.frame, text="No answer file selected.") self.answer_label.pack(pady=5) self.select_answer_button = ttk.Button(self.frame, text="Select Answer PDF", command=self.select_answer_pdf) self.select_answer_button.pack(pady=5) self.confirm_button = ttk.Button(self.frame, text="Confirm and Process", command=self.process_pdfs) self.confirm_button.pack(pady=10) self.new_window = None self.pdf_canvas1 = None self.pdf_canvas2 = None self.photo_list1 = [] # 保存图片引用,避免被垃圾回收 self.photo_list2 = [] def select_question_pdf(self): self.question_file = filedialog.askopenfilename(title="Select Question PDF", filetypes=[("PDF Files", "*.pdf")]) if self.question_file: self.question_label.config(text=f"Question PDF: {os.path.basename(self.question_file)}") def select_answer_pdf(self): self.answer_file = filedialog.askopenfilename(title="Select Answer PDF", filetypes=[("PDF Files", "*.pdf")]) if self.answer_file: self.answer_label.config(text=f"Answer PDF: {os.path.basename(self.answer_file)}") def process_pdfs(self): if not self.question_file or not self.answer_file: return self.open_new_window() def open_new_window(self): self.new_window = tk.Toplevel(self.root) self.new_window.title("Question & Answer Viewer") self.new_window.geometry("1200x800") self.pdf_viewer_frame = ttk.Frame(self.new_window) self.pdf_viewer_frame.pack(fill=tk.BOTH, expand=True) # 左侧试卷区域:画布+滚动条 left_frame = ttk.Frame(self.pdf_viewer_frame) left_frame.pack(side="left", fill="both", expand=True, padx=5, pady=5) self.pdf_canvas1 = tk.Canvas(left_frame) self.scrollbar1 = ttk.Scrollbar(left_frame, orient="vertical", command=self.pdf_canvas1.yview) self.scrollbar1.pack(side="right", fill="y") self.pdf_canvas1.config(yscrollcommand=self.scrollbar1.set) self.pdf_canvas1.pack(side="left", fill="both", expand=True) # 右侧答卷区域:画布+滚动条 right_frame = ttk.Frame(self.pdf_viewer_frame) right_frame.pack(side="right", fill="both", expand=True, padx=5, pady=5) self.pdf_canvas2 = tk.Canvas(right_frame) self.scrollbar2 = ttk.Scrollbar(right_frame, orient="vertical", command=self.pdf_canvas2.yview) self.scrollbar2.pack(side="right", fill="y") self.pdf_canvas2.config(yscrollcommand=self.scrollbar2.set) self.pdf_canvas2.pack(side="left", fill="both", expand=True) self.file_label = ttk.Label(self.new_window, text="Processing...") self.file_label.pack(pady=5) self.display_pdfs() def display_pdfs(self): if not self.question_file or not self.answer_file: return question_pages = convert_from_path(self.question_file) answer_pages = convert_from_path(self.answer_file) if not question_pages or not answer_pages: self.file_label.config(text="No pages found in selected PDFs.") return # 统一画布宽度为两份PDF的最大页面宽度 max_width = max(page.width for page in question_pages + answer_pages) # 计算总高度为两份PDF的最大总页数高度 total_height = max(sum(p.height for p in question_pages), sum(p.height for p in answer_pages)) # 拼接试卷所有页面为长图 question_full_img = Image.new('RGB', (max_width, total_height), (255, 255, 255)) current_y = 0 for page in question_pages: question_full_img.paste(page, (0, current_y)) current_y += page.height # 拼接答卷所有页面为长图 answer_full_img = Image.new('RGB', (max_width, total_height), (255, 255, 255)) current_y = 0 for page in answer_pages: answer_full_img.paste(page, (0, current_y)) current_y += page.height # 转换为Tkinter可用格式 photo1 = ImageTk.PhotoImage(image=question_full_img, master=self.new_window) photo2 = ImageTk.PhotoImage(image=answer_full_img, master=self.new_window) # 保存引用防止被回收 self.photo_list1.append(photo1) self.photo_list2.append(photo2) # 设置画布滚动区域和显示尺寸 self.pdf_canvas1.config(scrollregion=(0, 0, max_width, total_height), width=max_width//2) self.pdf_canvas2.config(scrollregion=(0, 0, max_width, total_height), width=max_width//2) # 绘制完整长图 self.pdf_canvas1.create_image(0, 0, image=photo1, anchor=tk.NW) self.pdf_canvas2.create_image(0, 0, image=photo2, anchor=tk.NW) # 更新状态标签 self.file_label.config( text=f"Question PDF: {os.path.basename(self.question_file)} ({len(question_pages)} pages)\n" f"Answer PDF: {os.path.basename(self.answer_file)} ({len(answer_pages)} pages)" ) if __name__ == "__main__": root = tk.Tk() app = PDFViewerApp(root) root.mainloop()
问题修复说明
1. 两份文件显示空间不一致
- 为试卷和答卷分别创建独立子框架,每个子框架包含画布和对应滚动条
- 两个子框架均设置
fill="both", expand=True,确保平分窗口空间 - 添加内边距避免内容紧贴窗口边缘
2. 滚动条位置错误
- 将每个滚动条与对应画布放在同一子框架内,滚动条固定在子框架右侧
- 实现滚动条与对应文件的一一对应,不再重叠挤在窗口最右侧
3. 仅显示最后一页
- 将所有PDF页面拼接成单张长图,一次性绘制到画布上
- 用列表保存图片引用,避免Tkinter垃圾回收机制删除图片
- 设置画布滚动区域为长图完整尺寸,支持垂直滚动浏览全部页面
内容的提问来源于stack exchange,提问作者jonathanlin1112
相关产品推荐
相关产品推荐

