本文介绍了PhotoImage没有响应tkinter Scale小部件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Python脚本,该脚本允许用户在tkinter画布小部件中打开图像.该程序将打印出新图像应具有的尺寸,但仅显示原始图像.如何用新尺寸刷新画布.

I have a python script which allows a user to open up an image in a tkinter canvas widget. The program is printing out the size that the new image should be, but only the original image shows up. How do I refresh the canvas with the new size.

这是python代码:

Here is the python code:

from Tkinter import *
import tkFileDialog
from PIL import ImageTk, Image
factor = 1.0
width_org = 500
height_org = 500
mGui = Tk()
mGui.geometry("600x600")
mGui.configure(background = 'yellow')
frame = Frame(mGui, width = 400, height = 400)
frame.pack(anchor = 'nw')
frame.configure(background = 'red')
canvasframe = Canvas(frame, width = 400, height = 400, scrollregion = (-500,-500,500,500))
hbar = Scrollbar(frame,orient=HORIZONTAL)
hbar.pack(side=BOTTOM, fill = X)
hbar.configure(command= canvasframe.xview)
vbar = Scrollbar(frame,orient = VERTICAL )
vbar.pack(side=RIGHT, fill = Y)
vbar.configure(command= canvasframe.yview)
canvasframe.configure(xscrollcommand= hbar.set, yscrollcommand= vbar.set)
canvasframe.pack( expand = True, fill = BOTH)
pil_img = Image.open("rose-flower-500x500.jpg")
img = ImageTk.PhotoImage(pil_img)
def openit():
    in_path = tkFileDialog.askopenfilename()
    try:
        pil_img = Image.open(in_path)
    except IOError:
        pass
    width_org, height_org = pil_img.size
    try:
        img = ImageTk.PhotoImage(pil_img)
    except IOError:
        pass

    canvasframe.create_image(20,20, image = img)
    canvasframe.img = img
valueList = [25, 50, 100, 150, 200]
def valuecheck(value):
    newval = min(valueList, key=lambda x:abs(x-float(value)))
    scalepic.set(newval)
    factor = newval/100.0
    w = int(width_org*factor)
    h = int(height_org*factor)
    print (w, h)
    pil_img = pil_img.resize((w,h),Image.ANTIALIAS)
    img = ImageTk.PhotoImage(pil_img)
    canvasframe.create_image(20,20, image =img)
openpic = Button(mGui, text = "Open", command = openit).pack()
scalelabel = Label(mGui, text = "Resize Image").pack()
scalepic = Scale(mGui, from_=min(valueList), to=max(valueList), command=valuecheck, orient = HORIZONTAL)
scalepic.set(100)
scalepic.pack()

mGui.mainloop()

此外,如何打开新图像?我在考虑for循环和某种处理方法,但是我不确定语法.

Also, how can I open a new image? I'm thinking of a for loop and some kind of dispose method, but I'm not sure about the syntax.

编辑类中的部分代码

from Tkinter import *
import tkFileDialog
from PIL import ImageTk, Image


factor = 1.0
width_org = 500
height_org = 500
class MainApp(Frame):
    def createControls(self):
        frame = Frame(self, width = 600, height = 500)
        frame.configure(background = 'red')
        frame.pack(anchor = 'nw')
        canvasframe = Canvas(frame, width = 600, height = 500, scrollregion = (-600,-500,600,500))
        canvasframe.configure(xscrollcommand= hbar.set, yscrollcommand= vbar.set)
        canvasframe.pack(expand = True, fill = BOTH)
        hbar = Scrollbar(frame, orient=HORIZONTAL)
        hbar.pack(side=BOTTOM, fill=X)
        hbar.configure(command= canvasframe.xview)
        vbar = Scrollbar(frame, orient=VERTICAL)
        vbar.pack(side=RIGHT, fill = Y)
        vbar.configure(command= canvasframe.yview)


    def __init__(self, parent):
        Frame.__init__(self, parent, width = 800, height = 600, background = 'yellow')
        self.pack()
        self.createControls()


root = Tk()
app = MainApp(parent =root)

app.mainloop()

推荐答案

您忘记了将对新PhotoImage的引用保存在canvasframe.img中,因此在valuecheck返回时会收集垃圾.

You forgot to save the reference to the new PhotoImage in canvasframe.img, so it gets garbage collected when valuecheck returns.

此外,除了使用create_image为重新缩放的图像创建新的Canvas图像外,您还应该通过itemconfig来简单地更新现有的图像.为此,您需要保存create_image返回的商品ID号.例如,在openit中,

Also, rather than creating a new Canvas image with create_image for the rescaled image you should simply update the existing one via itemconfig. To do that, you need to save the item id number returned by create_image. Eg, in openit, do

canvasframe.imgid = canvasframe.create_image(20,20, image = img)

然后在创建新的PhotoImage之后在valuecheck

And then in valuecheck, after you create the new PhotoImage do

canvasframe.img = img
canvasframe.itemconfig(canvasframe.imgid, image=img)

您不必将imgimgid存储为canvasframe的属性,但是在这种情况下很方便.如果您在画布上有很多必须跟踪的东西,那将变得很混乱.但是对于较大的Tkinter程序,最好将所有内容放入一个或多个类中.它使事情更有条理,更易于访问.

You don't have to store img and imgid as attributes of canvasframe, but it's convenient in this case. It would get messy though if you had lots of things on the canvas that you had to track. But for larger Tkinter programs it's a good idea to put everything into one or more classes. It makes things more organized, and easier to access.

这篇关于PhotoImage没有响应tkinter Scale小部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 18:28