0

I want to create a UX with tkinter. One of the windows of this UX ("Window1") is supposed to have 3 columns of widgets. While the middle column is distinct to the others, the left and right columns have the same layout, only provides different information. To make it more reusable I thought its good to create a class for the columns ("Column").

"Column" shall contain a button, which displays a icon instead of text. The first problem I have is, that the icon isn't displayed when the button is created within "Column". Though, it works when created in "Window1". I already found a similar question to mine (Use an image-button defined inside an object with TKinter), where the solution is to add a "self." to save the opened image. This, however, does not solve my problem.

Defining "Column" like "Window1" obviously works, but than I cannot place the entry and the text field side-by-side in the columns.

How do I need to adjust my code so that I can still use the classes I've created?

Or am I on the completely wrong way?

I use python3, VS Code and Windows.

I've reduced my code as far as I thought it still makes sense. Please tell me if there is more or different information needed :)

Thanks already
Sebastian

import tkinter as tk
from tkinter import ttk

"""define basics"""
class app(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)

        self.state('zoomed') #open app in an expanded window
        #distribute 3 columns evenly
        for i in range(3):
            self.grid_columnconfigure(i, weight=1)

        #create a frame where more windows can be stacked if needed
        containerFrame = tk.Frame(self)
        containerFrame.grid()
        self.frames = {}

        #create window to place widgets
        frame = Window1(parent=containerFrame, window = self)
        self.frames["window1"] = frame #store frame in dict
        frame.grid(row=0, column=0, sticky="n") #place frame on the app window

"""define the window"""
class Window1(tk.Frame):

    def __init__(self, parent, window):
        tk.Frame.__init__(self, parent)  # create working frame

        columnLeft = Column(window) # create left column
        columnLeft.frame.grid(row=0, column=0) # place frame of left column
        columnLeft.place() # place widgets of the column

        columnRight = Column(window) # create left column
        columnRight.frame.grid(row=0, column=2) # place frame of left column
        columnRight.place() # place widgets of the column

        # this button is displayed with an icon
        self.iconDetail1 = (tk.PhotoImage(file=r"icons/detail.png")).subsample(10, 10)
        self.button1 = ttk.Button(window, image=self.iconDetail1, command=lambda: print("Yes"))
        self.button1.grid(row=0, column=1)


"""define the columns"""
class Column():

    def __init__(self, root):
        self.frame = tk.Frame()  # create frame for placing widgets
        for i in range(3): # main column consists of 3 sub columns
            self.frame.grid_columnconfigure(i, weight=1)

        """define widgets"""
        #this button is placed right, but without an icon
        self.iconFolder2 = (tk.PhotoImage(file=r"icons/folder.png")).subsample(4, 4) #get image
        self.button2 = ttk.Button(self.frame, image=self.iconFolder2, command=lambda: print("no....")) #create button
        self.text = tk.Label(self.frame, text= "show text received from button")
    
    def place(self): #method to place widgets independently from creating an instance
        self.button2.grid(row=0, column=0, sticky=tk.W)
        self.text.grid(row=0, column=2, sticky=tk.E)

if __name__ == "__main__":
    app = app()
    app.mainloop()

enter image description here

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
53B45T14N
  • 3
  • 2
  • 1
    It is because `collumnLeft` and `collumnRight` are local variables which are garbage collected. Try changing them to instance variables, `self.collumnLeft` and `self.collumnRight`. – acw1668 Aug 23 '23 at 11:52
  • Wow, that was super fast, thanks a lot! But now I am a bit confused, as stuff like labels can be for example placed within the same method without making them to instance variables. Do you know why it's possible to handle some stuff fully and others not? – 53B45T14N Aug 23 '23 at 12:14
  • Because their parents have reference to them, so they are not garbage collected. – acw1668 Aug 23 '23 at 12:16
  • 1
    It's a **column** - not a "collumn" - one "l" is **QUITE** enough ! – marc_s Aug 24 '23 at 04:17
  • @acw1668 Thanks you. As these are just comments, I can't close the question, right? I don't even find where I can vote your comment as useful. – 53B45T14N Aug 30 '23 at 09:56

1 Answers1

0

Since columnLeft and columnRight are local variables inside Window1.__init__(), they will be garbage collected after exiting the function. The images created inside them will also be garbage collected.

Change them to instance variables self.columnLeft and self.columnRight.

acw1668
  • 40,144
  • 5
  • 22
  • 34