为什么我的 tkinter 代码会发生这种情况?
Why does this happens to my tkinter code?
所以我改天做了一个图像查看器,基本上它的作用是跳到下一张图片,并在我们的图片集结束时返回到第一张图片。
我制作了一个名为 Start 的按钮,它基本上会启动整个图片查看器并显示图片编号 1,
我还制作了一个 关闭 按钮,它将整个事情反转到起点(你会再次看到开始按钮)。
...但是一件很奇怪的事情发生了。
当我按下我的按钮时是这样的顺序:Start
、Next
、关闭,
开始,
下一步` — 整个事情变得疯狂,我的按钮消失了!
抱歉,如果我以非常低效的方式编写代码,那是因为我 2 天前开始学习 python!
我还在每个 if
/elif
的末尾打印了这个打印件,以便更容易调试,但它没有帮助。
from tkinter import *
from PIL import ImageTk,Image
from tkinter.font import *
root = Tk()
img = None
label1 = None
root.geometry('1920x1080')
cimage = "flower1.jpg"
# Functions
def rightpic() :
global cimage
if cimage == "flower1.jpg" :
label1.grid_forget()
label2.grid()
cimage = "flower2.jpg"
print("flower1skip")
elif cimage == "flower2.jpg" :
label2.grid_forget()
label3.grid()
cimage = "flower3.jpg"
print("flower2skip")
elif cimage == "flower3.jpg" :
label3.grid_forget()
label4.grid()
cimage = "flower4.jpg"
print("flower3skip")
elif cimage == "flower4.jpg" :
label4.grid_forget()
label1.grid()
cimage = "flower1.jpg"
print("flower4skip")
def start() :
global cimage
label1.grid(row=0)
buttonright.place(x=900, y=950)
buttonclose.place(x=700, y=950)
def close() :
global cimage
if cimage == "flower1.jpg" :
label1.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed1")
elif cimage == "flower2.jpg" :
label2.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed2")
elif cimage == "flower3.jpg" :
label3.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed3")
elif cimage == "flower4.jpg" :
label4.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed4")
buttons = Button(root,text = "Start!",command=start , bg = "#29a8ab",fg="#cccccc" , padx = 50 ,font=('Helvetica 19 bold'))
buttons.place(x=960,y=540)
buttonright= Button(root,text = "Next!",command=rightpic , bg = "#0e9aa7",fg="#f6cd61" , padx = 50 ,font=('Helvetica 19 bold'))
# buttonright.place(x=900, y=950)
buttonclose= Button(root,text = "Close!",command=close , bg = "#0e9aa7",fg="#f6cd61" , padx = 50 ,font=('Helvetica 19 bold'))
image1 = Image.open("flower1.jpg")
image1 = image1.resize((1920,950) , Image.ANTIALIAS)
image12 = ImageTk.PhotoImage(image1)
label1 = Label(root,image=image12)
image2 = Image.open("flower2.jpg")
image2 = image2.resize((1920,950) , Image.ANTIALIAS)
image13 = ImageTk.PhotoImage(image2)
label2 = Label(root,image=image13)
image3 = Image.open("flower3.jpg")
image3 = image3.resize((1920,950) , Image.ANTIALIAS)
image14 = ImageTk.PhotoImage(image3)
label3 = Label(root,image=image14)
image4 = Image.open("flower4.jpg")
image4 = image4.resize((1920,950) , Image.ANTIALIAS)
image15 = ImageTk.PhotoImage(image4)
label4 = Label(root,image=image15)
# label1.grid(row = 0)
mainloop()
首先我会回答这个问题:为什么按那个顺序点击按钮会消失?
这是因为当 start()
被调用时,它会网格化第一张图像,然后当 rightpic()
被调用时,它会检查 cimage
的值并采取相应的行动,因为当你第一次启动程序时该值设置为 "flower1.jpg"
它评估第一个 if 语句并忘记对第一个图像进行网格化并对第二个图像进行网格化,然后您调用 close()
,它再次检查图像并删除所有内容,但是,cimage
现在是 "flower2.jpg"
,当您再次调用 start()
时,它会网格化第一张图片,但是当调用 rightpic()
时,它会转到 elif cimage == "fower2.jpg"
,但由于第二张图片不是网格化了,没有什么可忘记的,所以它只是将第三个图像网格化在第一个图像下方,并且由于其他按钮是 place()
d 然后这个在 place()
之后调用的网格方法现在将第三个这些按钮上的图像。
解决方案是简单地这样做:
def start() :
global cimage
cimage = "flower1.jpg"
label1.grid(row=0)
buttonright.place(x=900, y=950)
buttonclose.place(x=700, y=950)
这将在每次调用 start()
时将变量重置为第一张图像。
有了这个,我现在将向您展示如何改进您的代码(因为答案必须包含问题的实际答案而不仅仅是建议),主要问题是创建不必要的标签和大量的重复。
重要
我想在其他事情之前提到这一点:我强烈建议在导入某些内容时不要使用通配符 (*
),您应该导入您需要的内容,例如from module import Class1, func_1, var_2
等等或导入整个模块:import module
然后你也可以使用别名:import module as md
或类似的东西,关键是不要导入所有东西,除非你真的知道你在做什么;名称冲突是问题所在。
另外我强烈建议你遵循PEP 8 - Style Guide for Python Code,例如函数定义之间有两行,在逗号(,
)之后而不是之前有一个space,不要放不必要的space如def func() :
,应该是def func():
,一般格式一致,函数和变量名用snake_case
,class用CapitalCase
。您可以简单地看一下我将在此处编写的代码,以更好地理解我的意思。
第一个改进(也可以改进,但稍后会改进)是只有一个标签可以简单地配置(阅读代码中的注释):
# import only what you need to keep the namespace clean
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
# my preference is to define everything that doesn't have to be defined
# after instantiating `Tk` before `Tk` such as these variables and functions
# as they will be called after `Tk` anyways so doesn't really matter but at least helps keep
# the parts that are strictly `tkinter` more together
cimage = "flower1.jpg"
# Functions (changed to `snake_case`)
def right_pic():
# here come some major changes to reduce the code
# what is commented out can be deleted and is how
# it were previously
global cimage
if cimage == "flower1.jpg":
# label1.grid_forget()
# label2.grid()
image_label.config(image=image13)
cimage = "flower2.jpg"
# print("flower1skip")
elif cimage == "flower2.jpg":
# label2.grid_forget()
# label3.grid()
image_label.config(image=image14)
cimage = "flower3.jpg"
# print("flower2skip")
elif cimage == "flower3.jpg":
# label3.grid_forget()
# label4.grid()
image_label.config(image=image15)
cimage = "flower4.jpg"
# print("flower3skip")
elif cimage == "flower4.jpg":
# label4.grid_forget()
# label1.grid()
image_label.config(image=image12)
cimage = "flower1.jpg"
# print("flower4skip")
# put two spaces between funcs (if you have a comment like this that corresponds
# to the function then it also has have two spaces between other functions)
def start():
global cimage
cimage = "flower1.jpg"
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
# here comes the first redundant code (if you read line by line)
# if you notice then every if/elif clause you always call
# button_right.place_forget() and button_close.place_forget()
# since they get always called might as well simply put them only at the end
# (commented out what can be deleted) (what has double ## was even more before)
# global cimage
# if cimage == "flower1.jpg":
# label1.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed1")
# elif cimage == "flower2.jpg":
# label2.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed2")
# elif cimage == "flower3.jpg":
# label3.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed3")
# elif cimage == "flower4.jpg":
# label4.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed4")
#
# # simply have these here at the end, no need to repeat them in each clause
# button_close.place_forget()
# button_right.place_forget()
# the latest version using only one label is as simple as
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
# changed names to match `snake_case`, the main changes are minor
# things such as removing spaces or adding those where needed (take a close look
# this is how it should be to be PEP 8 compliant (not necessary to follow but
# it is how python code was intended to be formatted))
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
# here comes the second repetition (commented out can be deleted)
# if you wanted to make it even more compact you could have done
# sth like this:
# image1 = Image.open("flower1.jpg").resize((1920, 950), Image.ANTIALIAS)
# image12 = ImageTk.PhotoImage(image1)
image1 = Image.open("flower1.jpg")
image1 = image1.resize((1920, 950), Image.ANTIALIAS)
image12 = ImageTk.PhotoImage(image1)
# label1 = Label(root, image=image12)
image2 = Image.open("flower2.jpg")
image2 = image2.resize((1920, 950), Image.ANTIALIAS)
image13 = ImageTk.PhotoImage(image2)
# label2 = Label(root, image=image13)
image3 = Image.open("flower3.jpg")
image3 = image3.resize((1920, 950), Image.ANTIALIAS)
image14 = ImageTk.PhotoImage(image3)
# label3 = Label(root, image=image14)
image4 = Image.open("flower4.jpg")
image4 = image4.resize((1920, 950), Image.ANTIALIAS)
image15 = ImageTk.PhotoImage(image4)
# label4 = Label(root, image=image15)
image_label = Label(root, image=image12)
# best practice is to use `<Tk>.mainloop()` instead of plain `mainloop()`
# so in this case `Tk` is assigned to `root` so this:
root.mainloop()
同样的代码只是删除了评论:
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
cimage = "flower1.jpg"
def right_pic():
global cimage
if cimage == "flower1.jpg":
image_label.config(image=image13)
cimage = "flower2.jpg"
elif cimage == "flower2.jpg":
image_label.config(image=image14)
cimage = "flower3.jpg"
elif cimage == "flower3.jpg":
image_label.config(image=image15)
cimage = "flower4.jpg"
elif cimage == "flower4.jpg":
image_label.config(image=image12)
cimage = "flower1.jpg"
def start():
global cimage
cimage = "flower1.jpg"
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
image1 = Image.open("flower1.jpg")
image1 = image1.resize((1920, 950), Image.ANTIALIAS)
image12 = ImageTk.PhotoImage(image1)
image2 = Image.open("flower2.jpg")
image2 = image2.resize((1920, 950), Image.ANTIALIAS)
image13 = ImageTk.PhotoImage(image2)
image3 = Image.open("flower3.jpg")
image3 = image3.resize((1920, 950), Image.ANTIALIAS)
image14 = ImageTk.PhotoImage(image3)
image4 = Image.open("flower4.jpg")
image4 = image4.resize((1920, 950), Image.ANTIALIAS)
image15 = ImageTk.PhotoImage(image4)
image_label = Label(root, image=image12)
root.mainloop()
(如您所见,代码已经更短了)
现在介绍一个非常高级的方法,它不使用 if/elif
您使用它的方式,基本上非常可扩展:
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
# define some lists here (since no direct relation to `tkinter`)
# the main loop is after `Tk`
# note that these are basically relative paths to images (also note that now
# to add new image you really only need to add it to this list)
img_names = ['flower1.jpg', 'flower2.jpg', 'flower3.jpg', 'flower4.jpg']
# another fancier option would be to use sth like this:
# import os
# img_names = [f'images/{name}' for name in os.listdir('images')]
# now this would create a list of relative paths to all files listed in
# directory named `"images"` that is relative to this script (obs
# you can change the dir name and stuff, this is just an example)
# so now if you only had images in that dir, you could simply only
# add images to that directory and they will be added to this list every time you
# run this code which is great
# this is to keep track of the current index, that allows for easier looping
# note tho that there are many options of how to loop over
# those images, this should be the most understandable tho
index = 0
def right_pic():
# now that there is an image list you can simply iterate over that
# keeping track of the index
global index
index += 1
# add this if statement to not cause errors
# and to allow for looping over
if index == len(img_lst): # use length because the last index is the length - 1
index = 0
image_label.config(image=img_lst[index])
def start():
# define index as global so that it can be changed
global index
# reset it to 0 every time you call `start()`
index = 0
# config the label to now contain the first image
image_label.config(image=img_lst[index])
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
# create images and append to the above defined list
img_lst = []
for img in img_names:
image = Image.open(img).resize((1920, 950), Image.ANTIALIAS)
photo = ImageTk.PhotoImage(image)
img_lst.append(photo)
# a short list comprehension to do this exact same thing but in one line:
# img_lst = [ImageTk.PhotoImage(Image.open(img_name).resize((1920, 950), Image.ANTIALIAS)) for img_name in img_names]
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
# create the image label but don't yet put image there
# so that it can be done in the `start()` function
# so that it resets every time you press `start()`
image_label = Label(root)
root.mainloop()
上面的代码没有注释(但请花时间阅读它们以获得所有建议):
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
img_names = ['flower1.jpg', 'flower2.jpg', 'flower3.jpg', 'flower4.jpg']
index = 0
def right_pic():
global index
index += 1
if index == len(img_lst):
index = 0
image_label.config(image=img_lst[index])
def start():
global index
index = 0
image_label.config(image=img_lst[index])
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
img_lst = []
for img in img_names:
image = Image.open(img).resize((1920, 950), Image.ANTIALIAS)
photo = ImageTk.PhotoImage(image)
img_lst.append(photo)
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
image_label = Label(root)
root.mainloop()
你可以很容易地看出这段代码有多短,但你也必须理解
它的可扩展性如何,因为您真正需要添加更多图像的是向列表中添加更多名称(或使用评论中提到的 os.listdir()
方法)。
请注意,我没有测试任何代码,因为我没有图像,但它们应该可以工作(如果不能,请告诉我,我会尝试修复)。
一些来源:
- Great unofficial
tkinter
docs (I use them quite a lot when I have questions about tkinter
)
- Simpler unofficial
tkinter
docs (they are probably easier to understand and include examples)
- This is a playlist of
tkinter
tutorials but the one this link leads to is actually about image viewer (they are all pretty great but this is on topic)
- For other python tutorials I really suggest Corey Schafer (not that much GUIs but the tutorials are very well made)
如果还有什么问题,尽管问,我会尽力解答。
所以我改天做了一个图像查看器,基本上它的作用是跳到下一张图片,并在我们的图片集结束时返回到第一张图片。 我制作了一个名为 Start 的按钮,它基本上会启动整个图片查看器并显示图片编号 1, 我还制作了一个 关闭 按钮,它将整个事情反转到起点(你会再次看到开始按钮)。
...但是一件很奇怪的事情发生了。
当我按下我的按钮时是这样的顺序:Start
、Next
、关闭,
开始,
下一步` — 整个事情变得疯狂,我的按钮消失了!
抱歉,如果我以非常低效的方式编写代码,那是因为我 2 天前开始学习 python!
我还在每个 if
/elif
的末尾打印了这个打印件,以便更容易调试,但它没有帮助。
from tkinter import *
from PIL import ImageTk,Image
from tkinter.font import *
root = Tk()
img = None
label1 = None
root.geometry('1920x1080')
cimage = "flower1.jpg"
# Functions
def rightpic() :
global cimage
if cimage == "flower1.jpg" :
label1.grid_forget()
label2.grid()
cimage = "flower2.jpg"
print("flower1skip")
elif cimage == "flower2.jpg" :
label2.grid_forget()
label3.grid()
cimage = "flower3.jpg"
print("flower2skip")
elif cimage == "flower3.jpg" :
label3.grid_forget()
label4.grid()
cimage = "flower4.jpg"
print("flower3skip")
elif cimage == "flower4.jpg" :
label4.grid_forget()
label1.grid()
cimage = "flower1.jpg"
print("flower4skip")
def start() :
global cimage
label1.grid(row=0)
buttonright.place(x=900, y=950)
buttonclose.place(x=700, y=950)
def close() :
global cimage
if cimage == "flower1.jpg" :
label1.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed1")
elif cimage == "flower2.jpg" :
label2.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed2")
elif cimage == "flower3.jpg" :
label3.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed3")
elif cimage == "flower4.jpg" :
label4.grid_forget()
buttonclose.place_forget()
buttonright.place_forget()
print("closed4")
buttons = Button(root,text = "Start!",command=start , bg = "#29a8ab",fg="#cccccc" , padx = 50 ,font=('Helvetica 19 bold'))
buttons.place(x=960,y=540)
buttonright= Button(root,text = "Next!",command=rightpic , bg = "#0e9aa7",fg="#f6cd61" , padx = 50 ,font=('Helvetica 19 bold'))
# buttonright.place(x=900, y=950)
buttonclose= Button(root,text = "Close!",command=close , bg = "#0e9aa7",fg="#f6cd61" , padx = 50 ,font=('Helvetica 19 bold'))
image1 = Image.open("flower1.jpg")
image1 = image1.resize((1920,950) , Image.ANTIALIAS)
image12 = ImageTk.PhotoImage(image1)
label1 = Label(root,image=image12)
image2 = Image.open("flower2.jpg")
image2 = image2.resize((1920,950) , Image.ANTIALIAS)
image13 = ImageTk.PhotoImage(image2)
label2 = Label(root,image=image13)
image3 = Image.open("flower3.jpg")
image3 = image3.resize((1920,950) , Image.ANTIALIAS)
image14 = ImageTk.PhotoImage(image3)
label3 = Label(root,image=image14)
image4 = Image.open("flower4.jpg")
image4 = image4.resize((1920,950) , Image.ANTIALIAS)
image15 = ImageTk.PhotoImage(image4)
label4 = Label(root,image=image15)
# label1.grid(row = 0)
mainloop()
首先我会回答这个问题:为什么按那个顺序点击按钮会消失?
这是因为当 start()
被调用时,它会网格化第一张图像,然后当 rightpic()
被调用时,它会检查 cimage
的值并采取相应的行动,因为当你第一次启动程序时该值设置为 "flower1.jpg"
它评估第一个 if 语句并忘记对第一个图像进行网格化并对第二个图像进行网格化,然后您调用 close()
,它再次检查图像并删除所有内容,但是,cimage
现在是 "flower2.jpg"
,当您再次调用 start()
时,它会网格化第一张图片,但是当调用 rightpic()
时,它会转到 elif cimage == "fower2.jpg"
,但由于第二张图片不是网格化了,没有什么可忘记的,所以它只是将第三个图像网格化在第一个图像下方,并且由于其他按钮是 place()
d 然后这个在 place()
之后调用的网格方法现在将第三个这些按钮上的图像。
解决方案是简单地这样做:
def start() :
global cimage
cimage = "flower1.jpg"
label1.grid(row=0)
buttonright.place(x=900, y=950)
buttonclose.place(x=700, y=950)
这将在每次调用 start()
时将变量重置为第一张图像。
有了这个,我现在将向您展示如何改进您的代码(因为答案必须包含问题的实际答案而不仅仅是建议),主要问题是创建不必要的标签和大量的重复。
重要
我想在其他事情之前提到这一点:我强烈建议在导入某些内容时不要使用通配符 (*
),您应该导入您需要的内容,例如from module import Class1, func_1, var_2
等等或导入整个模块:import module
然后你也可以使用别名:import module as md
或类似的东西,关键是不要导入所有东西,除非你真的知道你在做什么;名称冲突是问题所在。
另外我强烈建议你遵循PEP 8 - Style Guide for Python Code,例如函数定义之间有两行,在逗号(,
)之后而不是之前有一个space,不要放不必要的space如def func() :
,应该是def func():
,一般格式一致,函数和变量名用snake_case
,class用CapitalCase
。您可以简单地看一下我将在此处编写的代码,以更好地理解我的意思。
第一个改进(也可以改进,但稍后会改进)是只有一个标签可以简单地配置(阅读代码中的注释):
# import only what you need to keep the namespace clean
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
# my preference is to define everything that doesn't have to be defined
# after instantiating `Tk` before `Tk` such as these variables and functions
# as they will be called after `Tk` anyways so doesn't really matter but at least helps keep
# the parts that are strictly `tkinter` more together
cimage = "flower1.jpg"
# Functions (changed to `snake_case`)
def right_pic():
# here come some major changes to reduce the code
# what is commented out can be deleted and is how
# it were previously
global cimage
if cimage == "flower1.jpg":
# label1.grid_forget()
# label2.grid()
image_label.config(image=image13)
cimage = "flower2.jpg"
# print("flower1skip")
elif cimage == "flower2.jpg":
# label2.grid_forget()
# label3.grid()
image_label.config(image=image14)
cimage = "flower3.jpg"
# print("flower2skip")
elif cimage == "flower3.jpg":
# label3.grid_forget()
# label4.grid()
image_label.config(image=image15)
cimage = "flower4.jpg"
# print("flower3skip")
elif cimage == "flower4.jpg":
# label4.grid_forget()
# label1.grid()
image_label.config(image=image12)
cimage = "flower1.jpg"
# print("flower4skip")
# put two spaces between funcs (if you have a comment like this that corresponds
# to the function then it also has have two spaces between other functions)
def start():
global cimage
cimage = "flower1.jpg"
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
# here comes the first redundant code (if you read line by line)
# if you notice then every if/elif clause you always call
# button_right.place_forget() and button_close.place_forget()
# since they get always called might as well simply put them only at the end
# (commented out what can be deleted) (what has double ## was even more before)
# global cimage
# if cimage == "flower1.jpg":
# label1.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed1")
# elif cimage == "flower2.jpg":
# label2.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed2")
# elif cimage == "flower3.jpg":
# label3.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed3")
# elif cimage == "flower4.jpg":
# label4.grid_forget()
# # button_close.place_forget()
# # button_right.place_forget()
# print("closed4")
#
# # simply have these here at the end, no need to repeat them in each clause
# button_close.place_forget()
# button_right.place_forget()
# the latest version using only one label is as simple as
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
# changed names to match `snake_case`, the main changes are minor
# things such as removing spaces or adding those where needed (take a close look
# this is how it should be to be PEP 8 compliant (not necessary to follow but
# it is how python code was intended to be formatted))
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
# here comes the second repetition (commented out can be deleted)
# if you wanted to make it even more compact you could have done
# sth like this:
# image1 = Image.open("flower1.jpg").resize((1920, 950), Image.ANTIALIAS)
# image12 = ImageTk.PhotoImage(image1)
image1 = Image.open("flower1.jpg")
image1 = image1.resize((1920, 950), Image.ANTIALIAS)
image12 = ImageTk.PhotoImage(image1)
# label1 = Label(root, image=image12)
image2 = Image.open("flower2.jpg")
image2 = image2.resize((1920, 950), Image.ANTIALIAS)
image13 = ImageTk.PhotoImage(image2)
# label2 = Label(root, image=image13)
image3 = Image.open("flower3.jpg")
image3 = image3.resize((1920, 950), Image.ANTIALIAS)
image14 = ImageTk.PhotoImage(image3)
# label3 = Label(root, image=image14)
image4 = Image.open("flower4.jpg")
image4 = image4.resize((1920, 950), Image.ANTIALIAS)
image15 = ImageTk.PhotoImage(image4)
# label4 = Label(root, image=image15)
image_label = Label(root, image=image12)
# best practice is to use `<Tk>.mainloop()` instead of plain `mainloop()`
# so in this case `Tk` is assigned to `root` so this:
root.mainloop()
同样的代码只是删除了评论:
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
cimage = "flower1.jpg"
def right_pic():
global cimage
if cimage == "flower1.jpg":
image_label.config(image=image13)
cimage = "flower2.jpg"
elif cimage == "flower2.jpg":
image_label.config(image=image14)
cimage = "flower3.jpg"
elif cimage == "flower3.jpg":
image_label.config(image=image15)
cimage = "flower4.jpg"
elif cimage == "flower4.jpg":
image_label.config(image=image12)
cimage = "flower1.jpg"
def start():
global cimage
cimage = "flower1.jpg"
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
image1 = Image.open("flower1.jpg")
image1 = image1.resize((1920, 950), Image.ANTIALIAS)
image12 = ImageTk.PhotoImage(image1)
image2 = Image.open("flower2.jpg")
image2 = image2.resize((1920, 950), Image.ANTIALIAS)
image13 = ImageTk.PhotoImage(image2)
image3 = Image.open("flower3.jpg")
image3 = image3.resize((1920, 950), Image.ANTIALIAS)
image14 = ImageTk.PhotoImage(image3)
image4 = Image.open("flower4.jpg")
image4 = image4.resize((1920, 950), Image.ANTIALIAS)
image15 = ImageTk.PhotoImage(image4)
image_label = Label(root, image=image12)
root.mainloop()
(如您所见,代码已经更短了)
现在介绍一个非常高级的方法,它不使用 if/elif
您使用它的方式,基本上非常可扩展:
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
# define some lists here (since no direct relation to `tkinter`)
# the main loop is after `Tk`
# note that these are basically relative paths to images (also note that now
# to add new image you really only need to add it to this list)
img_names = ['flower1.jpg', 'flower2.jpg', 'flower3.jpg', 'flower4.jpg']
# another fancier option would be to use sth like this:
# import os
# img_names = [f'images/{name}' for name in os.listdir('images')]
# now this would create a list of relative paths to all files listed in
# directory named `"images"` that is relative to this script (obs
# you can change the dir name and stuff, this is just an example)
# so now if you only had images in that dir, you could simply only
# add images to that directory and they will be added to this list every time you
# run this code which is great
# this is to keep track of the current index, that allows for easier looping
# note tho that there are many options of how to loop over
# those images, this should be the most understandable tho
index = 0
def right_pic():
# now that there is an image list you can simply iterate over that
# keeping track of the index
global index
index += 1
# add this if statement to not cause errors
# and to allow for looping over
if index == len(img_lst): # use length because the last index is the length - 1
index = 0
image_label.config(image=img_lst[index])
def start():
# define index as global so that it can be changed
global index
# reset it to 0 every time you call `start()`
index = 0
# config the label to now contain the first image
image_label.config(image=img_lst[index])
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
# create images and append to the above defined list
img_lst = []
for img in img_names:
image = Image.open(img).resize((1920, 950), Image.ANTIALIAS)
photo = ImageTk.PhotoImage(image)
img_lst.append(photo)
# a short list comprehension to do this exact same thing but in one line:
# img_lst = [ImageTk.PhotoImage(Image.open(img_name).resize((1920, 950), Image.ANTIALIAS)) for img_name in img_names]
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
# create the image label but don't yet put image there
# so that it can be done in the `start()` function
# so that it resets every time you press `start()`
image_label = Label(root)
root.mainloop()
上面的代码没有注释(但请花时间阅读它们以获得所有建议):
from tkinter import Tk, Label, Button
from PIL import Image, ImageTk
img_names = ['flower1.jpg', 'flower2.jpg', 'flower3.jpg', 'flower4.jpg']
index = 0
def right_pic():
global index
index += 1
if index == len(img_lst):
index = 0
image_label.config(image=img_lst[index])
def start():
global index
index = 0
image_label.config(image=img_lst[index])
image_label.grid(row=0)
button_right.place(x=900, y=950)
button_close.place(x=700, y=950)
def close():
image_label.grid_forget()
button_close.place_forget()
button_close.place_forget()
root = Tk()
root.geometry('1920x1080')
img_lst = []
for img in img_names:
image = Image.open(img).resize((1920, 950), Image.ANTIALIAS)
photo = ImageTk.PhotoImage(image)
img_lst.append(photo)
buttons = Button(root, text="Start!", command=start, bg="#29a8ab", fg="#cccccc", padx=50, font='Helvetica 19 bold')
buttons.place(x=960, y=540)
button_right = Button(root, text="Next!", command=right_pic, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
button_close = Button(root, text="Close!", command=close, bg="#0e9aa7", fg="#f6cd61", padx=50, font='Helvetica 19 bold')
image_label = Label(root)
root.mainloop()
你可以很容易地看出这段代码有多短,但你也必须理解
它的可扩展性如何,因为您真正需要添加更多图像的是向列表中添加更多名称(或使用评论中提到的 os.listdir()
方法)。
请注意,我没有测试任何代码,因为我没有图像,但它们应该可以工作(如果不能,请告诉我,我会尝试修复)。
一些来源:
- Great unofficial
tkinter
docs (I use them quite a lot when I have questions abouttkinter
) - Simpler unofficial
tkinter
docs (they are probably easier to understand and include examples) - This is a playlist of
tkinter
tutorials but the one this link leads to is actually about image viewer (they are all pretty great but this is on topic) - For other python tutorials I really suggest Corey Schafer (not that much GUIs but the tutorials are very well made)
如果还有什么问题,尽管问,我会尽力解答。