Сначала отвечу на вопрос: почему кнопки исчезают при нажатии на них в такой последовательности?
Это связано с тем, что при вызове 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 — Руководство по стилю для кода Python, например, иметь две строки между определениями функций, иметь пробел после запятой (,
), но не раньше, не Не ставьте ненужные пробелы, такие как def func() :
, вместо def func():
, в целом используйте единообразное форматирование, для имен функций и переменных используйте snake_case
, для имен классов используйте 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()
, упомянутый в комментариях).
Обратите внимание, что я не проверял коды, так как у меня не было изображений, но они должны работать (если нет, скажите, я постараюсь это исправить).
Некоторые источники:
Если у вас есть еще вопросы, задавайте их, я постараюсь на них ответить.
Проблема довольно забавная, и она заключается в том, что во второй (и другой) раз, когда вы вызываете
next()
,cimage
по-прежнему устанавливается на второе изображение, поэтому он действует так, как если бы ему приходилось сетку третьего, что, вероятно, выталкивает все из окна, проще всего наверное добавитьcimage = 'flower1.jpg'
в начало функцииstart()
def, наверное напишу правильный ответ (через несколько часов) а так же постараюсь показать как улучшить ваш код