我正在尝试编写一个程序,该程序将包含两个文件:试卷和答卷。这两个文件应该在同一个窗口中渲染,并且有一个可以使用的垂直滚动条。
下面是我的代码:
import tkinter as tk
from tkinter import filedialog
from tkinter import ttk
from tkinter import *
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()
self.select_question_button = ttk.Button(self.frame, text="Select Question PDF", command=self.select_question_pdf)
self.select_question_button.pack()
self.answer_label = ttk.Label(self.frame, text="No answer file selected.")
self.answer_label.pack()
self.select_answer_button = ttk.Button(self.frame, text="Select Answer PDF", command=self.select_answer_pdf)
self.select_answer_button.pack()
self.confirm_button = ttk.Button(self.frame, text="Confirm and Process", command=self.process_pdfs)
self.confirm_button.pack()
self.new_window = None
self.pdf_canvas1 = None
self.pdf_canvas2 = None
def select_question_pdf(self):
self.question_file = filedialog.askopenfilename(title="Select Question 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")
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 Cropper")
self.pdf_viewer_frame = ttk.Frame(self.new_window)
self.pdf_viewer_frame.pack(fill=tk.BOTH, expand=True)
self.pdf_canvas1 = tk.Canvas(self.pdf_viewer_frame, xscrollincrement=1)
self.pdf_canvas2 = tk.Canvas(self.pdf_viewer_frame, xscrollincrement=1)
self.scrollbar1 = ttk.Scrollbar(self.pdf_viewer_frame, orient="vertical", command=self.pdf_canvas1.yview)
self.scrollbar2 = ttk.Scrollbar(self.pdf_viewer_frame, orient="vertical", command=self.pdf_canvas2.yview)
self.scrollbar1.pack(side="right", fill="y")
self.scrollbar2.pack(side="right", fill="y")
self.pdf_canvas1.config(yscrollcommand=self.scrollbar1.set)
self.pdf_canvas2.config(yscrollcommand=self.scrollbar2.set)
self.pdf_canvas1.pack(side="left", fill="both", expand=True)
self.pdf_canvas2.pack(side="right", fill="both", expand=True)
self.file_label = ttk.Label(self.new_window, text="Processing...")
self.file_label.pack()
self.display_pdfs()
def display_pdfs(self):
if self.question_file and self.answer_file:
question_pages = convert_from_path(self.question_file)
answer_pages = convert_from_path(self.answer_file)
if question_pages and answer_pages:
max_width = max(page.width for page in question_pages + answer_pages)
max_height = max(page.height for page in question_pages + answer_pages)
for page in range(min(len(question_pages), len(answer_pages))):
img1 = question_pages[page]
img2 = answer_pages[page]
img1_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
img2_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
img1_blank.paste(img1, (0, 0))
img2_blank.paste(img2, (0, 0))
photo1 = ImageTk.PhotoImage(master=self.new_window, image=img1_blank)
photo2 = ImageTk.PhotoImage(master=self.new_window, image=img2_blank)
canvas_width = max_width
canvas_height = max_height
self.pdf_canvas1.config(scrollregion=(0, 0, canvas_width, canvas_height), width=canvas_width, height=canvas_height)
self.pdf_canvas2.config(scrollregion=(0, 0, canvas_width, canvas_height), width=canvas_width, height=canvas_height)
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.pdf_canvas1.photo = photo1
self.pdf_canvas2.photo = photo2
self.file_label.config(text=f"Question File: {os.path.basename(self.question_file)}\nAnswer File: {os.path.basename(self.answer_file)} - Page {page + 1}")
if __name__ == "__main__":
root = tk.Tk()
app = PDFViewerApp(root)
root.mainloop()
如果有人能提供帮助,那就太好了。
目前我面临三个主要问题:
这两个文件在窗口中占用的空间量不同;位于左侧的试卷显得更大。
两个滚动条被挤压到右侧,而不是位于每个显示文件的相对右侧。
这两个文件无法完全渲染。在我对当前文件的测试中,似乎只显示第三页。
对于问题#1,我无法重现该问题,因为您已经使用相同尺寸的空白图像来显示 PDF 页面图像:
img1_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
img2_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
对于问题#2,您需要按正确的顺序打包画布和滚动条:
self.pdf_canvas1.pack(side="left", fill="both", expand=True)
self.scrollbar1.pack(side="left", fill="y")
self.pdf_canvas2.pack(side="left", fill="both", expand=True)
self.scrollbar2.pack(side="left", fill="y")
对于问题 #3,您使用了相同的一组变量来存储图像引用并将图像放在相同的位置 (0, 0),因此只会显示两个 PDF 文件的最后一个图像。您需要使用两个列表来存储两个 PDF 文件中的图像并将它们放在正确的位置。另外,将图像放入画布后,您还需要更新两个画布的
scrollregion
选项:
def display_pdfs(self):
if self.question_file and self.answer_file:
question_pages = convert_from_path(self.question_file)
answer_pages = convert_from_path(self.answer_file)
if question_pages and answer_pages:
max_width = max(page.width for page in question_pages + answer_pages)
max_height = max(page.height for page in question_pages + answer_pages)
# offset y for showing page images
dy = max_height + 5
# set the size of the canvases
self.pdf_canvas1.config(width=max_width, height=max_height)
self.pdf_canvas2.config(width=max_width, height=max_height)
# lists to store the page images
self.pdf_canvas1.imagelist = []
self.pdf_canvas2.imagelist = []
for page in range(min(len(question_pages), len(answer_pages))):
img1 = question_pages[page]
img2 = answer_pages[page]
img1_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
img2_blank = Image.new('RGB', (max_width, max_height), (255, 255, 255))
img1_blank.paste(img1, (0, 0))
img2_blank.paste(img2, (0, 0))
photo1 = ImageTk.PhotoImage(master=self.new_window, image=img1_blank)
photo2 = ImageTk.PhotoImage(master=self.new_window, image=img2_blank)
# calculate correct y position of current page image
self.pdf_canvas1.create_image(0, page*dy, image=photo1, anchor=tk.NW)
self.pdf_canvas2.create_image(0, page*dy, image=photo2, anchor=tk.NW)
# save the references of the page images
self.pdf_canvas1.imagelist.append(photo1)
self.pdf_canvas2.imagelist.append(photo2)
self.file_label.config(text=f"Question File: {os.path.basename(self.question_file)}\nAnswer File: {os.path.basename(self.answer_file)} - Page {page + 1}")
# update scrollregion option of the two canvases
self.pdf_canvas1.config(scrollregion=self.pdf_canvas1.bbox("all"))
self.pdf_canvas2.config(scrollregion=self.pdf_canvas2.bbox("all"))