Home > database >  How can I create a class and object for a tkinter widget in Python?
How can I create a class and object for a tkinter widget in Python?

Time:11-25

thanks for reading:

OBJECTIVE:
I am practicing using OOP, and wanted to create a class with class variables for a label widget I'm creating with tkinter. This way I can create many labels and don't need to specify the same font, font size, colors, etc, for each one.

PROBLEM:
I am unable to figure out how I can call a class instance when it needs to also reference the tkinter method. (Alternatively, should I even be trying to include the tkinter reference when creating a class?)

Here's an example of what I have:

import tkinter as tk
class ui_Labels:
    "This class sets the baseline characteristics for the widgets, including font, font size, and colors"
    #If I understand correctly, below are called class attributes#
    tkLabel = tk.Label
    rootRef = uiRoot
    varFont = "Calibri"
    fontSize = 14
    varFG = "f2f2f2"
    varBG = "#3b3b3b"
    
    #Constructor
    def __init__(self, name, varText):
        self.name = name
        self.varText = varText

# CLASS OBJECTS
sectionHeader = ui_Labels("Section Header","Magic XML Iterator")

# Attempt to call the instance (not sure if that's the correct phrasing
tk.Label(sectionHeader)

When to call the sectionHeader object as a tk.Label, I get the AttributeError message: "ui_Labels' object has no attribute 'tk'.

It looks like the message is saying that I need to reference the tk method in the class, but I wasn't sure how best to do so.

TL;DR Question:
Does anyone have a suggestion on the best way write a class or its associated object(s) for the purpose of making tkinter Widget templates?

Thank you!

Best,
Chris

CodePudding user response:

You don't want a Label to be a class attribute. Instead, you need to define the Label in __init__. You also need to pass the root/parent as an argument in __init__ so that you can use it to create the label. You can't have it as an attribute as it is not necessarily the same every time, and hasn't been defined in your code regardless.

Essentially what you want is a custom widget that you can create, grid/pack and interract with as a normal widget, but with some custom parameters. A more correct example of how to create a custom widget as a class, using your code, is:

import tkinter as tk

# Your class
class ui_Labels():
    '''This class sets the baseline characteristics 
    for the widgets, including font, font size, and colors
    '''

    # Attributes
    varFont = "Calibri"
    fontSize = 14
    varFG = "#F2F2F2"
    varBG = "#3b3b3b"
    
    # Constructor
    def __init__(self, parent, name, varText):
        self.parent  = parent
        self.name = name
        self.varText = varText

        self.label = tk.Label(
            parent, 
            text = varText, 
            fg = self.varFG, 
            bg = self.varBG, 
            font = (self.varFont, self.fontSize)
            )

    # Allows you to grid as you would normally
    # Can subsitute pack() here or have both class methods
    def grid(self, **kwargs):
        self.label.grid(kwargs)


# Main GUI
root = tk.Tk()

# Create an instance of your class
sectionHeader = ui_Labels(root, "Section Header","Magic XML Iterator")
sectionHeader.grid(row=1, column=2)

root.mainloop()

CodePudding user response:

I would suggest you to go through some tutorials on Python OOP.

Below is an example of creating a custom label class based on your code:

import tkinter as tk

# custom label class inherited from tk.Label
class ui_Label(tk.Label):
    '''
    This class sets the baseline characteristics for the widget,
    including font, font size and colors
    '''

    # class attributes
    varFont = "Calibri"
    fontSize = 14
    varFG = "#f2f2f2"
    varBG = "#3b3b3b"

    # Constructor: added parent argument
    def __init__(self, parent, name, varText):
        kwargs = {
            'text': varText,
            'font': (self.varFont, self.fontSize),
            'fg': self.varFG,
            'bg': self.varBG,
        }
        # need to call constructor of inherited class
        super().__init__(parent, **kwargs)
        # I don't know what the purpose of 'name' is
        # so just use an instance variable to save it
        self.name = name

root = tk.Tk()

# create instance of custom label
sectionHeader = ui_Label(root, "Section Header", "Magic XML Iterator")
sectionHeader.pack()

root.mainloop()
  • Related