Python Tkinter Canvas PDF Viewer下一页渲染仅在调试时有效
我正在尝试使用PyMuPDF库用Python/Tkinter编写一个PDF查看器。我可以成功地打开文档并呈现第一页,但是当尝试通过删除画布图像并从新页面创建新图像来移动到下一页时,我会看到一个空白屏幕。第一页被删除,但第二页不显示 但是,当我通过VS代码运行程序,并在Python Tkinter Canvas PDF Viewer下一页渲染仅在调试时有效,python,python-3.x,tkinter,tkinter-canvas,pymupdf,Python,Python 3.x,Tkinter,Tkinter Canvas,Pymupdf,我正在尝试使用PyMuPDF库用Python/Tkinter编写一个PDF查看器。我可以成功地打开文档并呈现第一页,但是当尝试通过删除画布图像并从新页面创建新图像来移动到下一页时,我会看到一个空白屏幕。第一页被删除,但第二页不显示 但是,当我通过VS代码运行程序,并在nxtBtn_Click函数中设置调试断点并逐行执行时,当函数完成时,第二页将按预期显示在窗口中 我试过了,但得到了同样的结果: 使用canvas.update_idletasks()强制重新绘制画布 将删除步骤和创建映像步骤拆分
nxtBtn_Click
函数中设置调试断点并逐行执行时,当函数完成时,第二页将按预期显示在窗口中
我试过了,但得到了同样的结果:
- 使用
强制重新绘制画布canvas.update_idletasks()
- 将删除步骤和创建映像步骤拆分为ondown和onup事件
- 使用传递到
窗口的回调函数。空闲后
- 使用新图像更新现有图像
canvas.itemconfig(canvasPdf,image=tkimg)
从tkinter导入*
从PIL导入图像,ImageTk
进口菲茨
输入数学
window=Tk()
窗口几何(“800x800”)
doc=fitz.open(r“”)
currentPage=0
画布=画布(窗口,宽度=800,高度=600)
canvas.grid(列=0,行=0)
pix=doc[currentPage].getPixmap()
收缩系数=int(canvas.cget(“高度”))/pix.height
mode=“RGBA”如果pix.alpha或“RGB”
img=Image.frombytes(模式,[pix.width,pix.height],pix.samples)
img=img.resize((数学地板(pix.width*收缩因子)、数学地板(pix.height*收缩因子)))
tkimg=ImageTk.PhotoImage(img)
canvasPdfs=canvas.create_image(0,0,anchor=NW,image=tkimg)
def nxtBtn_单击(事件):
全局文档、当前页面、画布、画布PDF
canvas.delete(canvasPdfs)
当前页面+=1
pix=doc[currentPage].getPixmap()
收缩系数=int(canvas.cget(“高度”))/pix.height
mode=“RGBA”如果pix.alpha或“RGB”
img=Image.frombytes(模式,[pix.width,pix.height],pix.samples)
img=img.resize((数学地板(pix.width*收缩因子)、数学地板(pix.height*收缩因子)))
tkimg=ImageTk.PhotoImage(img)
canvasPdfs=canvas.create_image(0,0,anchor=NW,image=tkimg)
nxtBtn=按钮(窗口,text=“下一步”)
nxtBtn.grid(列=0,行=1)
绑定(“,func=nxtBtn\u单击)
window.mainloop()
第一页的tkimg
是一个全局变量,因此只要图像可见,它就会一直存在(实际上太长了,因为它在您升级页面后仍然存在)。但是,后续页面的tkimg
是一个局部变量,因此当单击处理程序函数退出时,图像会立即被垃圾收集。@jasonharper:tkimg确实停留了太长时间,但它没有解释第二个图像不显示的原因。我确实尝试过在nxtBtn\u Click
中将tkimg设置为全局变量,以便用本地变量覆盖全局变量(既允许对旧tkimg进行垃圾收集,也防止对新映像进行垃圾收集)。这与第二页没有显示的结果相同,除非我正在调试。我很确定这是@BryanOakley的副本:我想你是对的。通过不使用全局tkimg
,而是在画布对象本身上创建一个属性:canvas.image=ImageTk.PhotoImage(img)
,我解决了这个问题。我假设调试一定会弄乱垃圾收集,这解释了为什么它在调试模式下工作。第一页的tkimg
是一个全局变量,因此只要图像可见,它就会一直存在(实际上太长了,因为它在升级页面后仍然存在)。但是,后续页面的tkimg
是一个局部变量,因此当单击处理程序函数退出时,图像会立即被垃圾收集。@jasonharper:tkimg确实停留了太长时间,但它没有解释第二个图像不显示的原因。我确实尝试过在nxtBtn\u Click
中将tkimg设置为全局变量,以便用本地变量覆盖全局变量(既允许对旧tkimg进行垃圾收集,也防止对新映像进行垃圾收集)。这与第二页没有显示的结果相同,除非我正在调试。我很确定这是@BryanOakley的副本:我想你是对的。通过不使用全局tkimg
,而是在画布对象本身上创建一个属性:canvas.image=ImageTk.PhotoImage(img)
,我解决了这个问题。我假设调试一定会弄乱垃圾收集,并解释为什么它在调试模式下工作。