Jul-19-2025, 08:03 AM
(This post was last modified: Jul-19-2025, 01:10 PM by deanhystad.)
Currently making a financial tracking system, and ran into an issue with accessing 'item_category_optnmenu' and 'delitem_category_lbl' keys in a dictionary.
The widgets work fine, but I'm unable to change any properties (e.g. setting text for the label does nothing directly in the dictionary and raises a KeyError when set later). Where am I going wrong here?
The widgets work fine, but I'm unable to change any properties (e.g. setting text for the label does nothing directly in the dictionary and raises a KeyError when set later). Where am I going wrong here?
# Import modules
import tkinter as tk
from tkinter import ttk
from tkinter import font
from PIL import ImageTk,Image
show_widgets(export_screen_widgets, widget_options)
# Create widgets
def make_widgets(widget_dict):
for name, place_args in widget_dict.items():
suffix = name.split('_')[-1]
factory = _factories.get(suffix, lambda p, n: tk.Label(p, text=n))
w = factory(root, name)
if name not in widget_options:
widget_options[name] = {}
opts = widget_options[name]
if suffix == "txt":
w.config(
width=opts.get("width", 20),
height=opts.get("height", 3),
bg=opts.get("bg", "#ffffff"),
)
if suffix == "btn":
image_obj = opts.get("image_obj")
if image_obj:
w.config(image=image_obj)
w.image_obj = image_obj # prevent garbage collection
if suffix == "canvas":
bg_colour = opts.get("background") or opts.get("bg")
if bg_colour:
w.config(bg=bg_colour)
image_obj = opts.get("image_obj")
if image_obj:
w.create_image(0, 0, image=image_obj, anchor='nw')
w.image_obj = image_obj # hold reference
w.config(width=image_obj.width(), height=image_obj.height())
else:
pass
else:
skip_keys = {"widget", "image_obj", "variable"}
w.config(**{k: v for k, v in opts.items() if k not in skip_keys})
opts["widget"] = w
w.place(**place_args)
# Create tkinter window
root = tk.Tk()
root.wm_attributes('-fullscreen','true')
# Get screen dimensions
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# Set 'background.png' image as window background (Ignore this, just for context)
bg_img_original = Image.open('path\\to\\background.png') # get background image
bg_img_resized = bg_img_original.resize((screen_width,screen_height),Image.Resampling.LANCZOS) # Resize background image to fit screen dimensions
bg_img = ImageTk.PhotoImage(bg_img_resized)
background = tk.Canvas(root,highlightthickness=0,bd=0) # Create canvas widget to display background image
background.place(x=0,y=0,relwidth=1,relheight=1)
background.create_image(0,0,image=bg_img,anchor='nw')
# Widget names and placement args (financial record screen)
record_screen_widgets = {
"item_details_bg_canvas": {"x": 2*(screen_width//3)-10, "y": int(screen_height-5), "anchor": "sw"},
"item_record_bg_canvas": {"x": (screen_width//3), "y": int(screen_height-5), "anchor": "sw"},
"currentyear_lbl": {"x": (screen_width//3)+25, "y": screen_height-(int(44*(screen_width//3) * Image.open('path\\to\\items_record_bg.png').size[1] / Image.open('path\\to\\items_record_bg.png').size[0])//50), "anchor": "sw"},
"consumables_category_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"hires_category_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"misc_category_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"item_category_optnmenu": {"x": int(screen_width-25), "y": 5+(screen_height//4), "anchor": "ne"},
"item_description_txt": {"x": 4*(screen_width//5), "y": (screen_height//3), "anchor": "e"},
"item_quantity_entry": {"x": 0, "y": 0, "anchor": "nw"},
"item_indivcost_entry": {"x": 0, "y": 0, "anchor": "nw"},
"item_totalcost_entry": {"x": 0, "y": 0, "anchor": "nw"},
"item_daterecord_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"item_accrecord_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"item_comments_txt": {"x": 4*(screen_width//5), "y": 4*(screen_height//5), "anchor": "se"}
}
# Widget names and placement args (deleted items screen)
delitems_screen_widgets = {
"delitem_details_bg_canvas": {"x": 2*(screen_width//3)-10, "y": int(screen_height-5), "anchor": "sw"},
"delitem_record_bg_canvas": {"x": (screen_width//3), "y": int(screen_height-5), "anchor": "sw"},
"delitem_category_lbl": {"x": int(screen_width-25), "y": 5+(screen_height//4), "anchor": "ne"},
"delitem_description_txt": {"x": 4*(screen_width//5), "y": (screen_height//3), "anchor": "e"},
"delitem_quantity_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"delitem_indivcost_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"delitem_totalcost_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"delitem_daterecord_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"delitem_accrecord_lbl": {"x": 0, "y": 0, "anchor": "nw"},
"delitem_comments_txt": {"x": 4*(screen_width//5), "y": 4*(screen_height//5), "anchor": "se"}
}
# Dictionary containing widget names and properties
widget_options = {
# Record Screen
"currentyear_lbl": {
"text": "2025",
"bg": "#000a58",
"fg": "#ffffff"
},
"category_view_btns": {
"text": "View Category",
"background": "#000e72",
"activebackground": "#000e72"
},
"consumables_category_lbl": {
"text": "Consumables",
"bg": "#000e72"
},
"hires_category_lbl": {
"text": "Hires",
"bg": "#000e72"
},
"misc_category_lbl": {
"text": "Miscellaneous",
"bg": "#000e72"
},
"item_category_optnmenu": {
"background": "#ffffff"
},
"item_description_txt": {
"background": "#ffffff"
},
"item_quantity_entry": {
"background": "#ffffff"
},
"item_indivcost_entry": {
"background": "#ffffff"
},
"item_totalcost_entry": {
"background": "#ffffff"
},
"item_daterecord_lbl": {
"text": "Date",
"bg": "#000e72"
},
"item_accrecord_lbl": {
"text": "Account",
"bg": "#000e72"
},
"item_comments_txt": {
"background": "#ffffff"
},
# Deleted Items Screen
"delitem_category_lbl": {
"bg": "#000e72",
"fg": "#ffffff",
"text": "Category Name"
},
"delitem_description_txt": {
"background": "#ffffff"
},
"delitem_quantity_lbl": {
"text": "Quantity",
"bg": "#000e72"
},
"delitem_indivcost_lbl": {
"text": "Cost",
"bg": "#000e72"
},
"delitem_totalcost_lbl": {
"text": "Total",
"bg": "#000e72"
},
"delitem_daterecord_lbl": {
"text": "Date",
"bg": "#000e72"
},
"delitem_accrecord_lbl": {
"text": "Account",
"bg": "#000e72"
},
"delitem_comments_txt": {
"background": "#ffffff"
},
# Set more properties to widgets (to show how I tried adding properties to item_category_optnmenu/delitem_category_lbl)
widget_options["item_description_txt"]["width"] = 40
widget_options["item_description_txt"]["height"] = 5
widget_options["item_comments_txt"]["width"] = 40
widget_options["item_comments_txt"]["height"] = 5
widget_options["delitem_description_txt"]["width"] = 40
widget_options["delitem_description_txt"]["height"] = 5
widget_options["delitem_comments_txt"]["width"] = 40
widget_options["delitem_comments_txt"]["height"] = 5
# Widget factories based on suffix
_factories = {
'lbl': lambda p, n: tk.Label(p),
'btn': lambda p, n: tk.Button(p, highlightthickness=0, bd=0),
'canvas': lambda p, n: tk.Canvas(p, highlightthickness=0, bd=0),
'optnmenu': lambda p, n: tk.OptionMenu(p, tk.StringVar(value=""), "Option 1", "Option 2"),
'entry': lambda p, n: tk.Entry(p),
'txt': lambda p, n: tk.Text(p),
'separator':lambda p, n: ttk.Separator(p, orient='vertical')
}
# Call functions to create and hide screen-specific widgets (ignore this, just for context)
make_widgets(profile_screen_widgets)
make_widgets(record_screen_widgets)
make_widgets(export_screen_widgets)
make_widgets(delitems_screen_widgets)
make_widgets(settings_screen_widgets)
hide_widgets(widget_options)
root.mainloop()
deanhystad write Jul-19-2025, 01:10 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
