I am trying to write a PDF viewer in Python/Tkinter using the PyMuPDF library. I can successfully open the document and render the first page, but when attempting to move to the next page by deleting the Canvas image and creating a new one from the new page I get a blank screen. The first page is deleted, but the second page doesn't show.
However when I run the program through VS Code and set a debug breakpoint in the nxtBtn_Click
function and step through it line by line, the second page will appear in the window as expected when the function completes.
I have tried, but get the same results:
- Using
canvas.update_idletasks()
to force a re-paint of the canvas. - Splitting the delete step and the create_image step to the ondown and onup events.
- Using a callback function passed to
window.after_idle
- Updating the exiting image with a new image
canvas.itemconfig(canvasPdf, image = tkimg)
I am running Python 3.7.1 on Windows 10.
from tkinter import *
from PIL import Image, ImageTk
import fitz
import math
window = Tk()
window.geometry("800x800")
doc = fitz.open(r"<<Path to pdf here>>")
currentPage = 0
canvas = Canvas(window, width=800, height=600)
canvas.grid(column=0, row=0)
pix = doc[currentPage].getPixmap()
shrinkFactor = int(canvas.cget("height")) / pix.height
mode = "RGBA" if pix.alpha else "RGB"
img = Image.frombytes(mode, [pix.width, pix.height], pix.samples)
img = img.resize((math.floor(pix.width * shrinkFactor), math.floor(pix.height * shrinkFactor)))
tkimg = ImageTk.PhotoImage(img)
canvasPdfs = canvas.create_image(0, 0, anchor=NW, image=tkimg)
def nxtBtn_Click(event):
global doc, currentPage, canvas, canvasPdfs
canvas.delete(canvasPdfs)
currentPage += 1
pix = doc[currentPage].getPixmap()
shrinkFactor = int(canvas.cget("height")) / pix.height
mode = "RGBA" if pix.alpha else "RGB"
img = Image.frombytes(mode, [pix.width, pix.height], pix.samples)
img = img.resize((math.floor(pix.width * shrinkFactor), math.floor(pix.height * shrinkFactor)))
tkimg = ImageTk.PhotoImage(img)
canvasPdfs = canvas.create_image(0, 0, anchor=NW, image=tkimg)
nxtBtn = Button(window, text="Next")
nxtBtn.grid(column=0, row=1)
nxtBtn.bind("<Button-1>", func=nxtBtn_Click)
window.mainloop()