So I created a garbled mess of code for a GUI that displays items (tarot cards) in a window in rows and columns. However, after creating more than four items, the items shift to the right leaving a large black empty space, beyond that I want the buttons for draw card and quit to be on the sides of the title, and make the entire thing generally just look a bit cleaner. If anyone could shed some light or provide suggestions I would really appreciate it. Thank you.
Window resizing issue
Ideal layout
Also please note, I am brand new to Tkinter, I apologize in advance
def draw_one_card_command():
card = draw_card()
if card:
card_name = f"Card: {card}"
card_meaning = f"Meaning: {CARD_MEANINGS.get(card.name, 'Meaning not available')}"
try:
img = Image.open(CARD_IMAGES[card.name])
if card.reversed:
img = img.rotate(180)
img = img.resize((100, 175))
img = ImageTk.PhotoImage(img)
card_label = ttk.Label(cards_frame.interior, text=card_name + "\n" + card_meaning, image=img, compound="top")
card_label.image = img
cards_frame.cards.append(card_label)
row = len(cards_frame.cards) // 5
column = len(cards_frame.cards) % 5
card_label.grid(row=row, column=column, padx=5, pady=5, sticky="nsew")
except FileNotFoundError:
card_label = ttk.Label(cards_frame.interior, text=card_name + "\n" + card_meaning)
card_label.grid(sticky="w", padx=5, pady=5)
def on_configure(event):
cards_frame.canvas.configure(scrollregion=cards_frame.canvas.bbox("all"))
def on_title_configure(event):
title_label.place(relx=0.5, rely=0.5, anchor=CENTER)
root = Tk()
root.title("PyTarot")
root.geometry("800x600")
# Define custom styles
root.tk_setPalette(background="black", foreground="purple")
root.style = ttk.Style(root)
root.style.configure("TFrame", background="black") # Set frame background color to black
root.style.configure("TLabel", foreground="purple") # Set label text color to purple
root.style.configure("TButton", foreground="purple") # Set button text color to purple
frm = ttk.Frame(root, padding=10)
frm.grid(sticky="ew")
title_label = ttk.Label(frm, text="~ ~ ~ PyTarot ~ ~ ~", font=("Helvetica", 16, "bold"))
title_label.grid(column=0, row=0, columnspan=2, pady=10, sticky="ew")
draw_button = ttk.Button(frm, text="Draw a Card", command=draw_one_card_command)
draw_button.grid(column=0, row=1, padx=10, pady=10, sticky="ew")
quit_button = ttk.Button(frm, text="Quit", command=root.destroy)
quit_button.grid(column=1, row=1, padx=10, pady=10, sticky="ew")
cards_frame = Frame(root, bg="black")
cards_frame.grid(row=1, column=0, padx=10, pady=5, sticky="nsew")
cards_frame.grid_rowconfigure(0, weight=1)
cards_frame.grid_columnconfigure(0, weight=1)
cards_frame.canvas = Canvas(cards_frame, bg="black", highlightthickness=0)
cards_frame.canvas.grid(row=0, column=0, sticky="nsew")
cards_frame.scrollbar = ttk.Scrollbar(cards_frame, orient="vertical", command=cards_frame.canvas.yview)
cards_frame.scrollbar.grid(row=0, column=1, sticky="ns")
cards_frame.canvas.configure(yscrollcommand=cards_frame.scrollbar.set)
cards_frame.interior = Frame(cards_frame, bg="black")
cards_frame.canvas.create_window((0, 0), window=cards_frame.interior, anchor="nw")
cards_frame.interior.bind("<Configure>", on_configure)
cards_frame.cards = []
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
root.bind("<Configure>", on_title_configure)
root.mainloop()
Tried resizing with
root.geometry("800x600")
Tried altering row = len(cards_frame.cards) // 5
and column = len(cards_frame.cards) % 5
But the blank space persists regardless
Tried editing different variables within:
draw_button = ttk.Button(frm, text="Draw a Card", command=draw_one_card_command) draw_button.grid(column=0, row=1, padx=10, pady=10, sticky="ew")
and
quit_button = ttk.Button(frm, text="Quit", command=root.destroy) quit_button.grid(column=1, row=1, padx=10, pady=10, sticky="ew")
not much changed, and what did change was not what I intended
Suggest to use Text
widget for showing those tarot cards, then you don't need to calculate the row and column values because of wrapping feature of Text
widget.
For the buttons and label alignment issue in the top frame, you can use .pack()
on the two frames frm
and cards_frame
and don't need to bind <Configure>
event on the root window to move the title_label
.
Below is the modified code:
def draw_one_card_command():
card = draw_card()
if card:
card_name = f"Card: {card}"
card_meaning = f"Meaning: {CARD_MEANINGS.get(card.name, 'Meaning not available')}"
try:
img = Image.open(CARD_IMAGES[card.name])
if card.reversed:
img = img.rotate(180)
img = img.resize((100, 175))
img = ImageTk.PhotoImage(img)
card_label = ttk.Label(cards_frame.container, text=card_name + "\n" + card_meaning, image=img, compound="top")
card_label.image = img
except FileNotFoundError:
card_label = ttk.Label(cards_frame.container, text=card_name + "\n" + card_meaning)
### insert the card into the text widget
cards_frame.container.window_create("end", window=card_label, padx=5, pady=5)
cards_frame.cards.append(card_label)
root = Tk()
root.title("PyTarot")
root.geometry("800x600")
# Define custom styles
root.tk_setPalette(background="black", foreground="purple")
root.style = ttk.Style(root)
root.style.configure("TFrame", background="black") # Set frame background color to black
root.style.configure("TLabel", foreground="purple") # Set label text color to purple
root.style.configure("TButton", foreground="purple") # Set button text color to purple
frm = ttk.Frame(root, padding=10)
frm.pack() ### use pack() to pack the frame at the top side
draw_button = ttk.Button(frm, text="Draw a Card", command=draw_one_card_command)
draw_button.grid(column=0, row=0, padx=10, pady=10, sticky="ew")
title_label = ttk.Label(frm, text="~ ~ ~ PyTarot ~ ~ ~", font=("Helvetica", 16, "bold"))
title_label.grid(column=1, row=0, pady=10, sticky="ew")
quit_button = ttk.Button(frm, text="Quit", command=root.destroy)
quit_button.grid(column=2, row=0, padx=10, pady=10, sticky="ew")
cards_frame = Frame(root, bg="black")
cards_frame.pack(fill="both", expand=1) ### used pack()
### use Text widget for showing the cards
cards_frame.container = Text(cards_frame, width=1, height=1, bd=0)
cards_frame.container.pack(side="left", fill="both", expand=1)
cards_frame.scrollbar = ttk.Scrollbar(cards_frame, orient="vertical", command=cards_frame.container.yview)
cards_frame.scrollbar.pack(side="right", fill="y")
cards_frame.cards = []
root.mainloop()