在 Python 中使用滚动条显示大图像

Posted

技术标签:

【中文标题】在 Python 中使用滚动条显示大图像【英文标题】:Show Large Image using Scrollbar in Python 【发布时间】:2019-09-26 08:47:00 【问题描述】:

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

(基于这个问题:Scrollbars for a .jpg image on a Tkinter Canvas in Python)

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()

我得到以下信息:

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

【问题讨论】:

【参考方案1】:

如果您想要一个可滚动的图像小部件,那么最好的方法是创建一个可排列的可滚动图像类,让您的代码看起来更漂亮。所以我为此创建了一个类,并添加了 bind <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 小部件一样使用,因为如果您看到 source code of tkinter,每个其他小部件都是一个单独的类。

您可以通过多种方式使用ScrollableImage

    将上述代码保存到新的&lt;name&gt;.py(例如:“scrollimage.py”) 文件作为同一目录中的包,然后导入到您的主类中,如from scrollimage import ScrollableImage 和然后将其用作普通小部件。

    或者您可以在导入主文件后将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()

绑定 &lt;MouseWheel&gt; 需要在窗口上进行一些修改,例如将 event.delta 除以 120。在 macOS 上不需要修改。在 X11 上,您需要同时绑定 &lt;Button-4&gt;&lt;Button-5&gt; 并将 event.delta 除以 120。

Tkinter Mousewheel Binding

更多关于bind &lt;MouseWheel&gt;的细节以及它在不同平台上的工作方式可以查看上面的链接。

Best way to structure Tkinter application.

您可以参考上面的链接详细了解如何在 Tkinter 中正确应用 oops。当您使用 OOP 时,您始终可以继承 Tkinter 的任何小部件并对其进行修改以制作新的小部件和有用的类,从而帮助您更好地使用 Tkinter 制作应用程序。

【讨论】:

哇!非常感谢你的课!似乎非常有用。我对 tkinter 很陌生。你将如何使用它?你介意添加一个小例子吗?谢谢。 @Henry:我添加了更多有用的信息,这将帮助您更好地学习。 非常感谢!你真是太好了,非常有帮助! 我收到以下错误:Tkinter 回调 Traceback 中的异常(最近一次调用最后一次):文件“C:\Users\Anaconda3\lib\tkinter_init_.py”,第 1702 行,在 call 中返回 self.func(*args) 文件“”,第 31 行,在 mouse_scroll self.yview_scroll(-1*(evt.delta/ 120), 'units') # For windows File "C:\Users\Anaconda3\lib\tkinter_init_.py", line 1748, in yview_scroll self.tk.call(self._w, ' yview', 'scroll', number, what) _tkinter.TclError: expected integer but got "1.0" @henry:这是因为scroll 采用整数值,而“1.0”是浮点值,修复很简单,只需将其转换为整数即可。我编辑了我的帖子并修复了它。由于我在 Macos 上,我无法对其进行测试。希望它现在可以工作。【参考方案2】:

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

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

【讨论】:

快速提问:你知道如何增加 tkinter 图形大小吗? @henry - 如果你指的是 PhotoImage,你可以使用 PIL.ImageTk.PhotoImage(PIL.Image.open(File).resize((width, height))) 太棒了。谢谢!【参考方案3】:

放线:

canvas.config(scrollregion=canvas.bbox(tkinter.ALL))

之后:

canvas.create_image(0,0,image=img, anchor="nw")

或画布在滚动区域中不包含图像。

【讨论】:

以上是关于在 Python 中使用滚动条显示大图像的主要内容,如果未能解决你的问题,请参考以下文章

python滚动条使用场景

通过 StoryBoard 在滚动视图中平移大图像

如何在html表格上显示滚动条

突出显示滚动条上的特定区域

闪烁水平滚动条

边缘表格中的溢出滚动条无法正确显示