Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/eclipse/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中的重构(在Eclipse中提取新方法)_Python_Eclipse - Fatal编程技术网

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

Python中的重构(在Eclipse中提取新方法),python,eclipse,Python,Eclipse,我正试图在Eclipse中将一些Python 2.7代码重构为一个新方法。在下面的注释标记的块上使用Eclipse的重构->提取方法之后,我的图像不再显示在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.

我正试图在Eclipse中将一些Python 2.7代码重构为一个新方法。在下面的注释标记的块上使用Eclipse的
重构->提取方法之后,我的图像不再显示在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()   
有人能解释一下为什么图像会消失,并提出一个解决方案,这样我就可以在不丢失图像的情况下进行重构吗

重构后:

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

from PIL import Image, ImageTk

def extractedMethod(root):
    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)

def myCallback():
    pass

root = Tk()
extractedMethod(root)

root.mainloop()   

谢谢。

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

如前所述:

必须在Python程序中保留对image对象的引用,方法是将其存储在全局变量中,或将其附加到另一个对象

注意:当Python对PhotoImage对象进行垃圾收集时(例如,当您从将图像存储在局部变量中的函数返回时),即使图像由Tkinter小部件显示,图像也会被清除

为了避免这种情况,程序必须保留对图像对象的额外引用。一种简单的方法是将图像分配给小部件属性,如下所示:

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

因此,快速而肮脏的解决方案是将其添加到
extractedMethod
的顶部:

global photo1
def extractedMethod(root):
    global photo1  # added
    ...
…或将其添加到
label1=Label(image=photo1)
行之后:

label1.photo = photo1

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

即使是微不足道的版本,如中所示也可以工作:

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设计,在这种设计中,您的对象实际上代表了某些东西,如:


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

问题在于,否则,
photo1
是一个局部变量,函数返回时会立即丢弃,因此函数中对它的引用将无效


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

中的一个bug造成的。也许你可以显示重构前后的代码外观->提取方法。编辑文章以在重构后显示代码将
def myCallback():
放在
def extractedMethod(root)之前:
.Martineau-不起作用。谢谢。非常感谢你花时间回答这个问题!我没想到会得到如此有力的答复。这正是我所需要的——不仅仅是得到答案,而是展示正确的方法。这不是Tkinter中的一个bug,而是一个有文档记录的设计选择。虽然我同意这是一个奇怪的,不太像蟒蛇的设计选择,但它仍然是故意的。(或者至少考虑到有意选择Tkinter将Python名称映射到Tcl名称,而不是将值映射到值,这是经过深思熟虑的结果。)
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
def extractedMethod(root):
    global photo1  # added
    ...