Введение
Я пытаюсь создать приложение GUI с tkinter в python, которое имеет 2 кадра, которые связаны друг с другом. Общая идея заключается в создании меню выбора персонажей (как в играх). Все шло хорошо, пока не дошло до изменения текста кнопок разных классов.
Голы
Первый кадр , обозначенный классом A , будет главной страницей приложения и должен отображать на экране 10 кнопок;
Второй кадр, представленный класс B , будет отображаться пользователю только при нажатии любой кнопки в классе A;
В классе B должен отображаться список кнопок. При нажатии любой из кнопок класса B текст этой кнопки должен быть передан в текст кнопки класса A.
Подробная информация о проекте
Это приложение должно работать так, как если бы это было меню выбора игрового персонажа. Воображая таким образом, мы обычно видим этот тип взаимодействия между кадрами;
Существует экран, который показывает количество возможных игроков для каждой игры (В случае этого приложения кнопки класса А будет представлять это), и есть экран, который показывает все символы, доступные для выбора (кнопки класса В);
В кадре класса А будет Параметры игрока: «Игрок 1, Игрок 2, Игрок 3 ...». Поэтому при нажатии на одну из этих кнопок (игрок 1, игрок 2, игрок 3 ...) должно отображаться окно, в котором отображаются все символы (класс B);
При выборе требуемый символ (нажав на одну из кнопок класса B), выбранный символ должен быть передан на главный экран и показан на кнопке, выбранной в классе A. Поскольку я еще не использую изображения, я хочу представить символы с помощью текст кнопок;
Так что, если я нажимаю на «Игрок 1» на главном экране, а затем выбираю «Персонаж 4» на экране выбора, текст для «Игрок» 1 "следует изменить на" Символ 4 "на главном экране и т. Д .;
Generi c Код
Я сделал обобщенное c представление о том, как я строю программу и подробно о том, как я хотел, чтобы она работала.
import tkinter as tk
# Creates the main window
class A(tk.Frame):
"""The class A frame is the main page of the application,
when running the program, it will be the first thing shown to the user."""
def __init__(self, master):
tk.Frame.__init__(self, master)
self.bt_identities_a = [] # this list will be used to save the identities of each button created in class A
# Creates multiple buttons
for i in range(10):
self.bt_a = tk.Button(self, text=f"Player A{i}", command=lambda x=i: self.open_window_of_class_b(x))
self.bt_a.grid()
self.bt_identities_a.append(self.bt_a) # adds the button identity to the list
def open_window_of_class_b(self, n):
"""This is the method responsible for executing class B
and for recognizing which button was clicked in class A
All actions to be performed by the buttons in class B
from now on must be associated with exactly that one
button that was clicked in class A.
"""
# Run class B
B()
# get the button id that was clicked
bt_id = self.bt_identities_a[n]
...
# Creates the secondary window
class B(tk.Toplevel):
"""The class B frame is a secondary page that will only be opened if one of the Class A buttons is clicked."""
def __init__(self):
tk.Toplevel.__init__(self)
self.bt_identities_b = [] # this list will be used to save the identities of each button created in class B
# Creates multiple buttons
for j in range(10):
self.bt_b = tk.Button(self, text=f"Character B{j}",
command=lambda x=j: self.changes_the_text_of_a_button_in_class_a(x))
self.bt_b.grid()
self.bt_identities_b.append(self.bt_b) # adds the button identity to the list
def changes_the_text_of_a_button_in_class_a(self, n):
"""This method should recognize which of the Class B buttons that was clicked,
take the text from this exact button and pass the text to the Class A button
that was clicked just before."""
# get the button id that was clicked
bt_id = self.bt_identities_b[n]
...
root = tk.Tk()
root.geometry("300x300")
app = A(root)
app.pack(fill="both", expand=True)
app.mainloop()
Мой реальный код
И вот полный код, который я сделал так далеко от своего приложения, на случай, если это необходимо.
import tkinter as tk
from itertools import product
# Creating main page
class MainApplication(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
# produce the set of coordinates of the main page buttons
self.row_amount = 2
self.column_amount = 5
self.main_positions = product(range(self.row_amount), range(self.column_amount))
self.main_buttons_identities = []
# Creating main page header
self.lb = tk.Label(self, width=111, height=4, bg="#2c3e50", text="Champions", fg="white", font=50,
justify=tk.CENTER)
self.lb.grid(row=0, column=0, columnspan=5, pady=(0, 50), sticky="snew")
# Creating Done button
self.button = tk.Button(self, width=30, height=3, bg="#2c3e50", relief=tk.RIDGE, text="Done",
fg="white", font=20, command=root.destroy)
self.button.grid(row=3, columnspan=5, pady=(0, 150))
# Creating multiple buttons
for i, item in enumerate(self.main_positions):
self.button_main = tk.Button(self, width=16, height=8, bg="#2c3e50", relief=tk.RIDGE, fg="white",
justify=tk.CENTER, text=f"Champion {i +1}",
command=lambda c=i: [ChampionWindow(), self.clicked_main(c)])
self.button_main.grid(row=item[0] + 1, column=item[1], pady=(0, 50))
self.main_buttons_identities.append(self.button_main)
def clicked_main(self, current_index):
current = self.main_buttons_identities[current_index]
print(current["text"])
# Creating champion select window
class ChampionWindow(tk.Toplevel):
def __init__(self, *args, **kwargs):
tk.Toplevel.__init__(self, *args, **kwargs)
# produce the set of coordinates of the char selection page buttons
self.row_amount = 30
self.column_amount = 5
self.champion_position = product(range(self.row_amount), range(self.column_amount))
self.champions_buttons_identities = []
# scroll bar
self.ch_canvas = tk.Canvas(self, bg="blue", width=470, height=500)
self.ch_frame = tk.Frame(self.ch_canvas, bg="#273c75")
self.vscrollbar = tk.Scrollbar(self, orient="vertical", command=self.ch_canvas.yview)
self.ch_canvas.configure(yscrollcommand=self.vscrollbar.set)
self.ch_canvas.grid(sticky="snew")
self.vscrollbar.grid(row=0, column=3, sticky="sn")
self.ch_canvas.create_window((0, 0), window=self.ch_frame, anchor="nw")
self.ch_frame.bind("<Configure>", self.scroll)
# Creating multiple buttons
for i, itm in enumerate(self.champion_position):
self.button_champion = tk.Button(self.ch_frame, width=12, height=6, bg="#2c3e50",
relief=tk.RIDGE, fg="white", justify=tk.CENTER,
command=lambda c=i: [self.clicked_champion(c), self.destroy()],
text=f"Pick champ {i+1}")
self.button_champion.grid(row=itm[0], column=itm[1])
self.champions_buttons_identities.append(self.button_champion)
def scroll(self, ch_event):
self.ch_canvas.configure(scrollregion=self.ch_canvas.bbox("all"))
def clicked_champion(self, champ_index):
champ = self.champions_buttons_identities[champ_index]
print(champ["text"])
if __name__ == "__main__":
root = tk.Tk()
root.title("Champion")
root.geometry("1000x570+450+200")
root.resizable(False, False)
app = MainApplication(root)
app.configure(background="#34495e")
app.pack(fill="both", expand=True)
app.mainloop()
GUI images
Чтобы было проще понять, что я пытаюсь сделать, я свяжу изображения из главного окна и выбор персонажа окно.
Главное окно (Отображает игроков)
Окно выбора персонажа (Отображает доступные символы)