Python中的重构(在Eclipse中提取新方法)

2024-03-29 00:11:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试在Eclipse中将一些Python2.7代码重构成一个新方法。在下面用注释标记的块上使用Eclipse的Refactoring->Extract method之后,我的图像不再显示在GUI中:

from Tkinter import Tk, Button, W, E, N, S, Label, Frame

from PIL import Image, ImageTk

def myCallback():
    pass

root = Tk()

# start refactor method here

root.geometry('400x400')
runButton = Button(root, text="Run",bg='green',
    command=myCallback)
runButton.grid(row=2, column=0,
        padx=10, pady=10)
quitButton = Button(root, text="Quit",
command=root.quit)
quitButton.grid(row=2, column=1,
        padx=10, pady=10)

frame1 = Frame(width=200, height=200)
frame1.grid(row=1, column=0, columnspan=1, rowspan=1,
        sticky=W+E+N+S, padx=10, pady=10)
image1 = Image.open("C:/Users/me/Pictures/house.jpg")
size = 64,64
image1.thumbnail(size, Image.ANTIALIAS)
photo1 = ImageTk.PhotoImage(image1) 
label1 = Label(image=photo1) 
label1.grid(row=0, column=10, columnspan=1, rowspan=1,
        sticky=N+E, padx=10, pady=10)

# end refactor method here

root.mainloop()   

有人能解释一下为什么图像会消失,并提出一个解决方案,这样我就可以在不丢失图像的情况下进行重构?在

重构后:

^{pr2}$

谢谢。在


Tags: from图像imageimportcolumnbuttonrootmethod
2条回答

问题是您过早地释放了PhotoImage对象。在

the docs解释:

You must keep a reference to the image object in your Python program, either by storing it in a global variable, or by attaching it to another object.

Note: When a PhotoImage object is garbage-collected by Python (e.g. when you return from a function which stored an image in a local variable), the image is cleared even if it’s being displayed by a Tkinter widget.

To avoid this, the program must keep an extra reference to the image object. A simple way to do this is to assign the image to a widget attribute, like this:

label = Label(image=photo)
label.image = photo # keep a reference!
label.pack()

您可能认为将其作为image参数传递给Label构造函数可以使其保持活动状态。但是它没有;Label实际上并没有保留对PhotoImage对象的引用,只有在mainloop开始之后运行的Tcl代码中的实际标签构造才这样做。(这类似于弱引用,但不是有意的或明确的引用,如果有帮助的话)

因此,快速而棘手的解决方案是要么将其添加到extractedMethod的顶部:

^{pr2}$

…或在label1 = Label(image=photo1)行后添加:

label1.photo = photo1

避免这种情况的一个更好的方法是使用OO设计而不是平面过程设计,这样您就有了一些合理的对象来拥有所有的引用。在

即使是琐碎的版本,如these examples所示也可以:

class Foo(object):
    def __init__(self, root):
        # put the code from extractedMethod here,
        # but prefix every local variable with self,
        # and do the same for myCallback.
    def myCallback(self):
        pass

但是你最好使用一个真正的OO设计,你的对象实际上代表一些东西,比如the official examples

class MyFrame(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.create_widgets()
    def myCallback(self):
        pass
    def create_widgets(self):
        # put the code from extractedMethod here,
        # again prefixing things with self

一种解决方案是在extractedMethod()的开头添加一行:

def extractedMethod(root):
    global photo1  # added
    ...

问题是,否则photo1是一个局部变量,一旦函数返回就会被丢弃,因此在函数中对它的引用将变得无效。在

有人可能会认为label1 = Label(image=photo1)语句会增加它的引用计数并阻止这种情况的发生,但显然它不是这样工作的。我以前见过这种情况,我个人怀疑这是由于Tkinter中的一个错误引起的。。。在

相关问题 更多 >