使用Tkinter画布小部件添加放大和缩小?

我如何将放大和缩小添加到以下脚本,我想将其绑定到鼠标滚轮。如果您正在Linux上测试此脚本,请不要忘记将MouseWheel事件更改为Button-4和Button-5。

from Tkinter import * 

import Image, ImageTk

class GUI:

def __init__(self,root):

frame = Frame(root, bd=2, relief=SUNKEN)

frame.grid_rowconfigure(0, weight=1)

frame.grid_columnconfigure(0, weight=1)

xscrollbar = Scrollbar(frame, orient=HORIZONTAL)

xscrollbar.grid(row=1, column=0, sticky=E+W)

yscrollbar = Scrollbar(frame)

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

self.canvas = Canvas(frame, bd=0, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set, xscrollincrement = 10, yscrollincrement = 10)

self.canvas.grid(row=0, column=0, sticky=N+S+E+W)

File = "PATH TO JPG PICTURE HERE"

self.img = ImageTk.PhotoImage(Image.open(File))

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

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

xscrollbar.config(command=self.canvas.xview)

yscrollbar.config(command=self.canvas.yview)

frame.pack()

self.canvas.bind("<Button 3>",self.grab)

self.canvas.bind("<B3-Motion>",self.drag)

root.bind("<MouseWheel>",self.zoom)

def grab(self,event):

self._y = event.y

self._x = event.x

def drag(self,event):

if (self._y-event.y < 0): self.canvas.yview("scroll",-1,"units")

elif (self._y-event.y > 0): self.canvas.yview("scroll",1,"units")

if (self._x-event.x < 0): self.canvas.xview("scroll",-1,"units")

elif (self._x-event.x > 0): self.canvas.xview("scroll",1,"units")

self._x = event.x

self._y = event.y

def zoom(self,event):

if event.delta>0: print "ZOOM IN!"

elif event.delta<0: print "ZOOM OUT!"

root = Tk()

GUI(root)

root.mainloop()

回答:

据我所知,内置的Tkinter Canvas类缩放不会自动缩放图像。如果无法使用自定义窗口小部件,则可以缩放原始图像,并在调用缩放功能时将其替换在画布上。

下面的代码片段可以合并到您的原始类中。它执行以下操作:

  1. 缓存的结果Image.open()
  2. 添加了一个redraw()计算缩放图像的功能,并将其添加到画布上,还删除了先前绘制的图像(如果有)。
  3. 将鼠标坐标用作图像放置的一部分。我只是传递x and y给该create_image函数以显示图像位置如何随着鼠标移动而移动。您可以将其替换为自己的中心/偏移量计算。
  4. 这使用了Linux鼠标滚轮按钮4和5(您需要将其通用化才能在Windows等系统上使用)。

(已 )代码:

class GUI:

def __init__(self, root):

# ... omitted rest of initialization code

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

self.scale = 1.0

self.orig_img = Image.open(File)

self.img = None

self.img_id = None

# draw the initial image at 1x scale

self.redraw()

# ... rest of init, bind buttons, pack frame

def zoom(self,event):

if event.num == 4:

self.scale *= 2

elif event.num == 5:

self.scale *= 0.5

self.redraw(event.x, event.y)

def redraw(self, x=0, y=0):

if self.img_id:

self.canvas.delete(self.img_id)

iw, ih = self.orig_img.size

size = int(iw * self.scale), int(ih * self.scale)

self.img = ImageTk.PhotoImage(self.orig_img.resize(size))

self.img_id = self.canvas.create_image(x, y, image=self.img)

# tell the canvas to scale up/down the vector objects as well

self.canvas.scale(ALL, x, y, self.scale, self.scale)

我做了一些不同比例的测试,发现resize / create_image正在使用大量内存。我在具有32GB RAM的Mac

Pro上使用540x375 JPEG进行了测试。这是用于不同比例因子的内存:

 1x  (500,     375)      14 M

2x (1000, 750) 19 M

4x (2000, 1500) 42 M

8x (4000, 3000) 181 M

16x (8000, 6000) 640 M

32x (16000, 12000) 1606 M

64x (32000, 24000) ...

reached around ~7400 M and ran out of memory, EXC_BAD_ACCESS in _memcpy

鉴于以上所述,一种更有效的解决方案可能是确定将在其中显示图像的视口的大小,围绕鼠标坐标中心计算裁剪矩形,使用rect裁剪图像,然后仅缩放裁剪的部分。这应该使用常量内存来存储临时图像。否则,您可能需要使用第三方Tkinter控件来为您执行此裁剪/窗口缩放。

工作但过分简化的裁剪逻辑,只是为了让您入门:

    def redraw(self, x=0, y=0):

if self.img_id: self.canvas.delete(self.img_id)

iw, ih = self.orig_img.size

# calculate crop rect

cw, ch = iw / self.scale, ih / self.scale

if cw > iw or ch > ih:

cw = iw

ch = ih

# crop it

_x = int(iw/2 - cw/2)

_y = int(ih/2 - ch/2)

tmp = self.orig_img.crop((_x, _y, _x + int(cw), _y + int(ch)))

size = int(cw * self.scale), int(ch * self.scale)

# draw

self.img = ImageTk.PhotoImage(tmp.resize(size))

self.img_id = self.canvas.create_image(x, y, image=self.img)

gc.collect()

以上是 使用Tkinter画布小部件添加放大和缩小? 的全部内容, 来源链接: utcz.com/qa/401644.html

回到顶部