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