Python中使用滚动条显示大图

5

我想使用tkinter(Python 3)显示一张图片。该图片非常长,因此我想添加一个垂直滚动条。这是我尝试过的:

(基于此问题:在Python中的Tkinter画布上为.jpg图像添加滚动条

import tkinter
import PIL.Image, PIL.ImageTk

# Create a window
window = tkinter.Tk()

frame = tkinter.Frame(window, bd=2) # relief=SUNKEN)

frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(0, weight=1)

xscrollbar = tkinter.Scrollbar(frame, orient=tkinter.HORIZONTAL)
xscrollbar.grid(row=1, column=0, sticky=tkinter.E+tkinter.W)

yscrollbar = tkinter.Scrollbar(frame)
yscrollbar.grid(row=0, column=1, sticky=tkinter.N+tkinter.S)

canvas = tkinter.Canvas(frame, bd=0, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)
canvas.grid(row=0, column=0, sticky=tkinter.N+tkinter.S+tkinter.E+tkinter.W)
canvas.config(scrollregion=canvas.bbox(tkinter.ALL))

File = "FILEPATH"
img = PIL.ImageTk.PhotoImage(PIL.Image.open(File))
canvas.create_image(0,0,image=img, anchor="nw")

xscrollbar.config(command=canvas.xview)
yscrollbar.config(command=canvas.yview)

frame.pack()
window.mainloop()

我得到了以下内容:

我可以绘制图像,但滚动条不起作用。 它们只是灰色的且无法使用。

在此输入图片描述

3个回答

10
如果你想要一个可滚动的图像小部件,最好的方法是创建一个可滚动图像类,它可以更好地整理并使代码更漂亮。因此,我为此创建了一个类,并添加了绑定<MouseWheel>,这样用户就可以通过鼠标方便地滚动查看图片。

以下是代码示例

import tkinter

class ScrollableImage(tkinter.Frame):
    def __init__(self, master=None, **kw):
        self.image = kw.pop('image', None)
        sw = kw.pop('scrollbarwidth', 10)
        super(ScrollableImage, self).__init__(master=master, **kw)
        self.cnvs = tkinter.Canvas(self, highlightthickness=0, **kw)
        self.cnvs.create_image(0, 0, anchor='nw', image=self.image)
        # Vertical and Horizontal scrollbars
        self.v_scroll = tkinter.Scrollbar(self, orient='vertical', width=sw)
        self.h_scroll = tkinter.Scrollbar(self, orient='horizontal', width=sw)
        # Grid and configure weight.
        self.cnvs.grid(row=0, column=0,  sticky='nsew')
        self.h_scroll.grid(row=1, column=0, sticky='ew')
        self.v_scroll.grid(row=0, column=1, sticky='ns')
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        # Set the scrollbars to the canvas
        self.cnvs.config(xscrollcommand=self.h_scroll.set, 
                           yscrollcommand=self.v_scroll.set)
        # Set canvas view to the scrollbars
        self.v_scroll.config(command=self.cnvs.yview)
        self.h_scroll.config(command=self.cnvs.xview)
        # Assign the region to be scrolled 
        self.cnvs.config(scrollregion=self.cnvs.bbox('all'))
        self.cnvs.bind_class(self.cnvs, "<MouseWheel>", self.mouse_scroll)

    def mouse_scroll(self, evt):
        if evt.state == 0 :
            self.cnvs.yview_scroll(-1*(evt.delta), 'units') # For MacOS
            self.cnvs.yview_scroll(int(-1*(evt.delta/120)), 'units') # For windows
        if evt.state == 1:
            self.cnvs.xview_scroll(-1*(evt.delta), 'units') # For MacOS
            self.cnvs.xview_scroll(int(-1*(evt.delta/120)), 'units') # For windows

如何使用该类?

ScrollableImage 类视为Tkinter的小部件,就像使用其他Tkinter小部件一样。如果您查看tkinter源代码,您会发现每个小部件都是一个类。

有不同的方法可以使用 ScrollableImage

  1. 将上述代码保存到新的<name>.py(例如:"scrollimage.py")文件中作为包,并在同一目录中导入到主类中,如 from scrollimage import ScrollableImage,然后像正常小部件一样使用它。

  2. 或者可以在主文件的导入之后将 ScrollableImage 类放在顶部,然后像正常小部件一样使用它。

示例:

import tkinter as tk
# Import the package if saved in a different .py file else paste 
# the ScrollableImage class right after your imports.
from scrollimage import ScrollableImage   

root = tk.Tk()

# PhotoImage from tkinter only supports:- PGM, PPM, GIF, PNG format.
# To use more formats use PIL ImageTk.PhotoImage
img = tk.PhotoImage(file="logo.png")

image_window = ScrollableImage(root, image=img, scrollbarwidth=6, 
                               width=200, height=200)
image_window.pack()

root.mainloop()

在Windows上,绑定<MouseWheel>需要一些修改,例如将event.delta除以120。在macOS上不需要进行任何修改。而在X11上,你需要绑定<Button-4><Button-5>,并将event.delta除以120。
有关绑定<MouseWheel>在不同平台上的工作原理和详细信息,请参考上面提供的链接:Tkinter Mousewheel Binding
如果想要了解如何在Tkinter中正确应用OOPs,可以参考上面提供的链接:Best way to structure Tkinter application.。使用OOPs时,你可以继承Tkinter的任何小部件并对其进行修改,以创建新的小部件和有用的类,从而更好地制作Tkinter应用程序。

@Henry:我添加了更多有用的信息,这将帮助你更好地学习。 - Saad
1
非常感谢!这非常友善和有用! - henry
1
我得到了以下错误:Tkinter回调中的异常 Traceback(最近的调用最后): File“C:\ Users \ Anaconda3 \ lib \ tkinter \ __ init__.py”,第1702行,在__call__中 返回self.func(* args) File“<ipython-input-15-9870be16a69f>”,第31行,鼠标滚动 self.yview_scroll(-1 *(evt.delta / 120),'units')#对于Windows File“C:\ Users \ Anaconda3 \ lib \ tkinter \ __ init__.py”,第1748行,在yview_scroll中 self.tk.call(self._w,'yview','scroll',number,what) _tkinter.TclError:预期整数但得到“1.0” - henry
@henry:这是因为scroll需要整数值,而“1.0”是浮点值,修复很简单,只需将其转换为整数即可。我已经编辑了我的帖子并进行了修复。由于我使用的是Macos,无法测试它。希望现在能够正常工作。 - Saad
@Saad 你能否修改你的类,使得图像不是出现在画布的左上角,而是出现在其他坐标?我尝试通过修改这一行代码 self.cnvs.create_image(0, 0, anchor='nw', image=self.image) 来实现,但是没有任何变化。 - Юрій Ярош
显示剩余5条评论

4
把这行代码放置在:
canvas.config(scrollregion=canvas.bbox(tkinter.ALL))

之后:

canvas.create_image(0,0,image=img, anchor="nw")
< p >或画布不包括滚动区域中的图像。


4

在绘制图像后,设置画布的滚动区域:

canvas.create_image(0, 0, image=img, anchor="nw")
canvas.config(scrollregion=canvas.bbox(tkinter.ALL))

快速问题:您知道如何增加tkinter图形的大小吗? - henry
@henry - 如果你指的是PhotoImage,你可以使用PIL.ImageTk.PhotoImage(PIL.Image.open(File).resize((width, height)))。 - Maximouse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接