Home > OS >  Tkinter creates buttons before required arary is edited
Tkinter creates buttons before required arary is edited

Time:02-01

import customtkinter
from PIL import Image
from extractData import *

ActiceSpecs = []

root = customtkinter.CTk()
root.geometry("500x350")
root.title("Badcrew raiding tool")
root.iconbitmap("badcrew.ico")
app_width = 500
app_height = 350
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x = (screen_width / 2) - (app_width / 2)
y = (screen_height / 2) - (app_height / 2)
root.geometry(f'{app_width}x{app_height} {int(x)} {int(y)}')


def login():
    try:
        invalidIDLable.pack_forget()
        eventID = enterEventID.get()
        get_data(eventID)
        correctIDLable.pack(pady=12, padx=10)
        frame_eventpicker.pack_forget()
        mainWindow.pack()
        root.state("zoomed")
    except:
        invalidIDLable.pack(pady=12, padx=10)
        enterEventID.delete(0)

def create_button(frame):
    try:
        my_image = customtkinter.CTkImage(dark_image=Image.open(f"D:\Badcrew\specicons\{Players[i].spec}.png"),size=(50, 50))
        buttons[i] = customtkinter.CTkButton(master=frame, image=my_image, text=Players[i].name, text_color="black", font=("Arial", 16, "bold"), anchor ="w", width=290, height=75, fg_color=("red"),hover="False", border_color="Black", border_width=2, command=lambda k=i: button_function(k))
        buttons[i].pack(pady="2", padx="10")
    except:
        pass

tankCount = 0
healerCount = 0
damageCount = 0
def button_function(count):
    global tankCount
    global healerCount
    global damageCount
    color = buttons[count].cget("fg_color")
    if color == "red":
        if Players[count].role == "Tanks":
            tankCount = tankCount   1
            tankCountLabel.configure(text=f"{tankCount}/2")
        elif Players[count].role == "Healers":
            healerCount = healerCount   1
            healerCountLabel.configure(text=f"{healerCount}/4")
        else:
            damageCount = damageCount   1
            damageCountLabel.configure(text=f"{damageCount}/14")

        buttons[count].configure(fg_color=("green"))
        ActiceSpecs.append(Players[count].spec)

    elif color == "green":
        if Players[count].role == "Tanks":
            tankCount = tankCount - 1
            tankCountLabel.configure(text=f"{tankCount}/2")
        elif Players[count].role == "Healers":
            healerCount = healerCount - 1
            healerCountLabel.configure(text=f"{healerCount}/4")
        else:
            damageCount = damageCount - 1
            damageCountLabel.configure(text=f"{damageCount}/14")
        buttons[count].configure(fg_color=("yellow"))
        ActiceSpecs.remove(Players[count].spec)
    else:
        buttons[count].configure(fg_color=("red"))

frame_eventpicker = customtkinter.CTkFrame(master=root)
frame_eventpicker.pack(pady=20, padx=60, fill="both", expand=True)

EventLabel = customtkinter.CTkLabel(master=frame_eventpicker, text="Event")
EventLabel.pack(pady=12, padx=10)
enterEventID = customtkinter.CTkEntry(master=frame_eventpicker, placeholder_text="Enter Event ID", width=150, justify='center')
enterEventID.pack(pady=12, padx=10)

button = customtkinter.CTkButton(master=frame_eventpicker, text="Confirm", command=login, width=150)
button.pack(pady=12, padx=10)

correctIDLable = customtkinter.CTkLabel(master=frame_eventpicker, text="ID Accepted", text_color="green")
invalidIDLable = customtkinter.CTkLabel(master=frame_eventpicker, text="Invalid ID", text_color="red")


mainWindow = customtkinter.CTkFrame(master=root)

tankFrame = customtkinter.CTkFrame(master=mainWindow)
tankLabelFrame = customtkinter.CTkFrame(master=tankFrame, fg_color="#C69B6D")
tankLabelFrame.pack(padx="10", pady="10", anchor="n")
tankLabel = customtkinter.CTkLabel(master=tankLabelFrame, width=300, text="Tanks", text_color="Black", font=("Arial", 20, "bold"))
tankLabel.pack(padx="10", pady="10")
tankCountLabel = customtkinter.CTkLabel(master=tankLabelFrame, width=300, text="0/2", text_color="Black", font=("Arial", 20, "bold"))
tankCountLabel.pack(padx=10, pady=10, anchor="s")
tankFrame.grid(row=0, column=0, padx="2", pady="10", sticky="n")

healerFrame = customtkinter.CTkFrame(master=mainWindow)
healerLabelFrame = customtkinter.CTkFrame(master=healerFrame, fg_color="#33937F")
healerLabelFrame.pack(padx="10", pady="10", anchor="n")
healerLabel = customtkinter.CTkLabel(master=healerLabelFrame, width=300, text="Healers", text_color="Black", font=("Arial", 20, "bold"))
healerLabel.pack(padx="10", pady="10")
healerCountLabel = customtkinter.CTkLabel(master=healerLabelFrame, width=300, text="0/4", text_color="Black", font=("Arial", 20, "bold"))
healerCountLabel.pack(padx=10, pady=10, anchor="s")
healerFrame.grid(row=0, column=1, padx="2", pady="10", sticky="n")

damageFrame = customtkinter.CTkFrame(master=mainWindow)
damageLabelFrame = customtkinter.CTkFrame(master=damageFrame, fg_color="#C41E3A")
damageLabelFrame.pack(pady="10", anchor="n")
damageLabel = customtkinter.CTkLabel(master=damageLabelFrame, width=900, text="Damage Dealers", text_color="Black", font=("Arial", 20, "bold"))
damageLabel.pack(padx="10", pady="10")
damageCountLabel = customtkinter.CTkLabel(master=damageLabelFrame, width=300, text="0/14", text_color="Black", font=("Arial", 20, "bold"))
damageCountLabel.pack(padx=10, pady=10, anchor="s")
damageFrame.grid(row=0, column=2, padx="2", pady="10", sticky="n")

buttons = dict()
for i in range(len(Players)):
    if Players[i].role == "Tanks":
        create_button(tankFrame)
    elif Players[i].role == "Healers":
        create_button(healerFrame)
    else:
        create_button(damageFrame)

root.mainloop()

get_data() updates the "Players" array

Buttons are created based on the information in "Players"(last section before root.mainloop). I can't find a way for "Players" to get updated before the buttons are created.

I want user to be able to put a string in enterEventID which is used by get_data() to edit the "players" to fit with the new ID.

CodePudding user response:

I think your program has a structure that makes it unnecessarily hard to maintain. The usage of global without need is also discouraged. A structure like this could be a good starting point for you.

However, I played around with your code a little bit and it's working now. The relevant change was only to put the update of the player array inside the login function. I am also passing the player element to the create_button function, so as to not access the players array from inside the function, which makes for a better separation of concerns.

import customtkinter
from PIL import Image

ActiceSpecs = []

root = customtkinter.CTk()
root.geometry("500x350")
root.title("Badcrew raiding tool")
app_width = 500
app_height = 350
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x = (screen_width / 2) - (app_width / 2)
y = (screen_height / 2) - (app_height / 2)
root.geometry(f'{app_width}x{app_height} {int(x)} {int(y)}')

players = []

class Player:
    def __init__(self, role) -> None:
        self.spec = 'testspec'
        self.name ='testname'
        self.role = role

def get_data(id):
    global players
    players = [
        Player("Tanks"),
        Player("Healers")
    ]


def login():
    global players
    try:
        invalidIDLable.pack_forget()
        eventID = enterEventID.get()
        get_data(eventID)
        correctIDLable.pack(pady=12, padx=10)
        frame_eventpicker.pack_forget()
        mainWindow.pack()
        root.state("zoomed")

        for i in range(len(players)):
            if players[i].role == "Tanks":
                create_button(tankFrame, players[i])
            elif players[i].role == "Healers":
                create_button(healerFrame, players[i])
            else:
                create_button(damageFrame, players[i])
    except Exception as e:
        print(e)
        invalidIDLable.pack(pady=12, padx=10)
        enterEventID.delete(0, 'end')

def create_button(frame, player):
    try:
        my_image = customtkinter.CTkImage(dark_image=Image.open(f"D:\Badcrew\specicons\{players[i].spec}.png"),size=(50, 50))
        customtkinter.CTkButton(master=frame, text=player.name, text_color="black", font=("Arial", 16, "bold"), anchor ="w", width=290, height=75, fg_color=("red"),hover="False", border_color="Black", border_width=2, command=lambda i: button_function(i)).pack(pady="2", padx="10")
    except:
        print('failed')
        pass

tankCount = 0
healerCount = 0
damageCount = 0
def button_function(count):
    global tankCount
    global healerCount
    global damageCount
    color = buttons[count].cget("fg_color")
    if color == "red":
        if players[count].role == "Tanks":
            tankCount = tankCount   1
            tankCountLabel.configure(text=f"{tankCount}/2")
        elif players[count].role == "Healers":
            healerCount = healerCount   1
            healerCountLabel.configure(text=f"{healerCount}/4")
        else:
            damageCount = damageCount   1
            damageCountLabel.configure(text=f"{damageCount}/14")

        buttons[count].configure(fg_color=("green"))
        ActiceSpecs.append(players[count].spec)

    elif color == "green":
        if players[count].role == "Tanks":
            tankCount = tankCount - 1
            tankCountLabel.configure(text=f"{tankCount}/2")
        elif players[count].role == "Healers":
            healerCount = healerCount - 1
            healerCountLabel.configure(text=f"{healerCount}/4")
        else:
            damageCount = damageCount - 1
            damageCountLabel.configure(text=f"{damageCount}/14")
        buttons[count].configure(fg_color=("yellow"))
        ActiceSpecs.remove(players[count].spec)
    else:
        buttons[count].configure(fg_color=("red"))

frame_eventpicker = customtkinter.CTkFrame(master=root)
frame_eventpicker.pack(pady=20, padx=60, fill="both", expand=True)

EventLabel = customtkinter.CTkLabel(master=frame_eventpicker, text="Event")
EventLabel.pack(pady=12, padx=10)
enterEventID = customtkinter.CTkEntry(master=frame_eventpicker, placeholder_text="Enter Event ID", width=150, justify='center')
enterEventID.pack(pady=12, padx=10)

button = customtkinter.CTkButton(master=frame_eventpicker, text="Confirm", command=login, width=150)
button.pack(pady=12, padx=10)

correctIDLable = customtkinter.CTkLabel(master=frame_eventpicker, text="ID Accepted", text_color="green")
invalidIDLable = customtkinter.CTkLabel(master=frame_eventpicker, text="Invalid ID", text_color="red")


mainWindow = customtkinter.CTkFrame(master=root)

tankFrame = customtkinter.CTkFrame(master=mainWindow)
tankLabelFrame = customtkinter.CTkFrame(master=tankFrame, fg_color="#C69B6D")
tankLabelFrame.pack(padx="10", pady="10", anchor="n")
tankLabel = customtkinter.CTkLabel(master=tankLabelFrame, width=300, text="Tanks", text_color="Black", font=("Arial", 20, "bold"))
tankLabel.pack(padx="10", pady="10")
tankCountLabel = customtkinter.CTkLabel(master=tankLabelFrame, width=300, text="0/2", text_color="Black", font=("Arial", 20, "bold"))
tankCountLabel.pack(padx=10, pady=10, anchor="s")
tankFrame.grid(row=0, column=0, padx="2", pady="10", sticky="n")

healerFrame = customtkinter.CTkFrame(master=mainWindow)
healerLabelFrame = customtkinter.CTkFrame(master=healerFrame, fg_color="#33937F")
healerLabelFrame.pack(padx="10", pady="10", anchor="n")
healerLabel = customtkinter.CTkLabel(master=healerLabelFrame, width=300, text="Healers", text_color="Black", font=("Arial", 20, "bold"))
healerLabel.pack(padx="10", pady="10")
healerCountLabel = customtkinter.CTkLabel(master=healerLabelFrame, width=300, text="0/4", text_color="Black", font=("Arial", 20, "bold"))
healerCountLabel.pack(padx=10, pady=10, anchor="s")
healerFrame.grid(row=0, column=1, padx="2", pady="10", sticky="n")

damageFrame = customtkinter.CTkFrame(master=mainWindow)
damageLabelFrame = customtkinter.CTkFrame(master=damageFrame, fg_color="#C41E3A")
damageLabelFrame.pack(pady="10", anchor="n")
damageLabel = customtkinter.CTkLabel(master=damageLabelFrame, width=900, text="Damage Dealers", text_color="Black", font=("Arial", 20, "bold"))
damageLabel.pack(padx="10", pady="10")
damageCountLabel = customtkinter.CTkLabel(master=damageLabelFrame, width=300, text="0/14", text_color="Black", font=("Arial", 20, "bold"))
damageCountLabel.pack(padx=10, pady=10, anchor="s")
damageFrame.grid(row=0, column=2, padx="2", pady="10", sticky="n")

root.mainloop()
  • Related