Python Forum
Tkinter & classes
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tkinter & classes
#1
The following code was primarily written by Yoriz. I'm using this code to better understand classes.

In three of the classes tk.Frame is shown in parentheses. 'At first I thought this was inheritance but tk.Frame is not the name of a parent class. Why is tk.Frame in parentheses?

 import tkinter as tk


class Main:
    def __init__(self, root):
        self.root = root
        self.root.geometry("800x800")
        self.create_start_frame()

    def create_start_frame(self):
        self.start_frame = StartFrame(self.root)
        self.start_frame.btn_start.bind(
            '<Button-1>', self.on_start_frame_btn_start)
        self.start_frame.pack()

    def on_start_frame_btn_start(self, event):
        self.start_frame.destroy()
        self.second_menu_frame = SecondMenuFrame(root)
        self.second_menu_frame.btn_option1.bind(
            '<Button-1>', self.on_second_menu_frame_btn_option1)
        self.second_menu_frame.pack()

    def on_second_menu_frame_btn_option1(self, event):
        self.second_menu_frame.destroy()
        self.final_frame = FinalFrame(root)
        self.final_frame.pack()


class StartFrame(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        tk.Label(self, text='StartFrame').pack()
        self.btn_start = tk.Button(
            self, text="Press here to start", bg="red", fg="black", font="Helvitica 30")
        self.btn_start.pack()


class SecondMenuFrame(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        tk.Label(self, text='SecondMenuFrame').pack()
        self.btn_option1 = tk.Button(self, text="Option1", bg="white",
                                     fg="firebrick", relief="groove", font="Helvitica 30")
        self.btn_option1.pack()


class FinalFrame(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        tk.Label(self, text='FinalFrame').pack()
        self.btn_final1 = tk.Button(self, text="finalsel1", bg="white",
                                    fg="firebrick", relief="groove", font="Helvitica 30", )
        self.btn_final1.pack()


if __name__ == "__main__":
    root = tk.Tk()

    main = Main(root)
    root.mainloop()
Reply
#2
If I'm not mistaken tk.Frame is a class in tkinter
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#3
If you ever want to know the type of ab object try:
>>> import tkinter as tk
>>> type(tk.Frame)
<class 'type'>
>>>
class whadayacallit(tk.Frame) inherits class tk method Frame
Reply
#4
What made you think that Frame is not a class? This post, and the post about not making an instance lead me to think you are confused about classes and objects and variables.
Reply
#5
(Feb-12-2021, 02:54 PM)deanhystad Wrote: What made you think that Frame is not a class? This post, and the post about not making an instance lead me to think you are confused about classes and objects and variables.

Deanhystad,

You are right. I am confused about classes. Most of the videos I have watched lead to creating an object(instance) such as a student and storing his/her name, address, GPA, school etc in this student object. Using classes with Tkinter seems very different to me.

I am able to create several menus using 1 class and several class methods. But I thought it would be better programming to use multiple classes. If I use a Tkinter course they usually don't use classes.

If you know of any tkinter books or videos that use classes, please let me know.
Reply
#6
Use classes when they make sense. An object should have an identity. You should be able to describe not only what it does, but what it is in a few short sentences. Just today I answered a question about a shopping application that used a list of buttons and labels to represent a shopping cart. I am lazy, so I will rework that example to use a class for the shopping cart.
import tkinter as tk

root = tk.Tk()
root.title("Super Market")
 
food = {
    "Rice": 0.99,
    "Spaghetti": 0.95,
    "Ice cream": 3.44,
    "Pizza": 7.50,
    "Cheese": 2.10, 
    "Cheddar": 0.45, 
    "Cherry": 0.88, 
    "Banana": 0.40, 
    "Apple": 0.67, 
    "Meat": 7.28, 
    "Fish": 9.72, 
    "Orange": 0.62, 
    "Orange juice": 2.10, 
    "Chocolate": 0.99, 
    "Bread": 0.55}

inventory = tk.Frame(root)
inventory.grid(row=0, column=0)

class ShoppingCart(tk.Frame):
    """I am a list of labels and buttons that represents a shopping
    cart. Items are kept in a dictionary.  Each item associated with
    an item count.  When drawn, I create a label, an add button and
    a subtract button for each item in items.  Pressing the add button
    increases the item count.  Pressing the subtract button decreases
    the item count.  If the item count goes to zero, the item is
    removed from the eictionary.
    """
    def __init__(self, *args, **kvargs):
        super().__init__(*args, **kvargs)
        self.items = {}

    def append(self, item):
        """Add item to cart"""
        self.items[item] = self.items.get(item, 0) + 1
        self.update()

    def remove(self, item):
        """Remove item from cart"""
        if item in self.items:
            self.items[item] -= 1
            if self.items[item] <= 0:
                self.items.pop(item)
        self.update()

    def update(self):
        """Update items display"""
        # Remove all items from display
        for item in self.winfo_children():
            item.grid_forget()
            item.destroy()

        # For each item create a label, an add button and a
        # remove button.
        for r, item in enumerate(self.items):
            text = f'{self.items[item]} x {item}'
            tk.Label(cart, text=text, width=20) \
                .grid(row=r, column=0)
            tk.Button(cart, text=' + ', command=lambda n=item: self.append(n)) \
                .grid(row=r, column=1)
            tk.Button(cart, text=' - ', command=lambda n=item: self.remove(n)) \
                .grid(row=r, column=2)

cart = ShoppingCart(root)
cart.grid(row=0, column=1)
  
for item in food:
    button = tk.Button(inventory, text=item, width=20,  \
            command=lambda n=item: cart.append(n))
    button.pack(side=tk.TOP)

root.mainloop()
If I weren't so lazy I would probably make the class an iterator so I could do something like this:
total = 0
for item, count in cart.items():
    price = food[item]
    subtotal = count * price
    total += subtotal
    print(f'{count:3} {item} @ {price:5.2} = {subtotal:5.2}
ShoppingCart makes a decent class because it is a thing that you can describe. It is a shopping cart. It holds things you want to purchase. You can put things in the cart and take things out of the cart. The interface provides buttons to make this easy.

I have never written code that uses a student object or a employee object. Most of my classes represent something slightly more abstract.
Reply
#7
(Feb-13-2021, 04:32 AM)deanhystad Wrote: Use classes when they make sense. An object should have an identity. You should be able to describe not only what it does, but what it is in a few short sentences. Just today I answered a question about a shopping application that used a list of buttons and labels to represent a shopping cart. I am lazy, so I will rework that example to use a class for the shopping cart.
import tkinter as tk

root = tk.Tk()
root.title("Super Market")
 
food = {
    "Rice": 0.99,
    "Spaghetti": 0.95,
    "Ice cream": 3.44,
    "Pizza": 7.50,
    "Cheese": 2.10, 
    "Cheddar": 0.45, 
    "Cherry": 0.88, 
    "Banana": 0.40, 
    "Apple": 0.67, 
    "Meat": 7.28, 
    "Fish": 9.72, 
    "Orange": 0.62, 
    "Orange juice": 2.10, 
    "Chocolate": 0.99, 
    "Bread": 0.55}

inventory = tk.Frame(root)
inventory.grid(row=0, column=0)

class ShoppingCart(tk.Frame):
    """I am a list of labels and buttons that represents a shopping
    cart. Items are kept in a dictionary.  Each item associated with
    an item count.  When drawn, I create a label, an add button and
    a subtract button for each item in items.  Pressing the add button
    increases the item count.  Pressing the subtract button decreases
    the item count.  If the item count goes to zero, the item is
    removed from the eictionary.
    """
    def __init__(self, *args, **kvargs):
        super().__init__(*args, **kvargs)
        self.items = {}

    def append(self, item):
        """Add item to cart"""
        self.items[item] = self.items.get(item, 0) + 1
        self.update()

    def remove(self, item):
        """Remove item from cart"""
        if item in self.items:
            self.items[item] -= 1
            if self.items[item] <= 0:
                self.items.pop(item)
        self.update()

    def update(self):
        """Update items display"""
        # Remove all items from display
        for item in self.winfo_children():
            item.grid_forget()
            item.destroy()

        # For each item create a label, an add button and a
        # remove button.
        for r, item in enumerate(self.items):
            text = f'{self.items[item]} x {item}'
            tk.Label(cart, text=text, width=20) \
                .grid(row=r, column=0)
            tk.Button(cart, text=' + ', command=lambda n=item: self.append(n)) \
                .grid(row=r, column=1)
            tk.Button(cart, text=' - ', command=lambda n=item: self.remove(n)) \
                .grid(row=r, column=2)

cart = ShoppingCart(root)
cart.grid(row=0, column=1)
  
for item in food:
    button = tk.Button(inventory, text=item, width=20,  \
            command=lambda n=item: cart.append(n))
    button.pack(side=tk.TOP)

root.mainloop()
If I weren't so lazy I would probably make the class an iterator so I could do something like this:
total = 0
for item, count in cart.items():
    price = food[item]
    subtotal = count * price
    total += subtotal
    print(f'{count:3} {item} @ {price:5.2} = {subtotal:5.2}
ShoppingCart makes a decent class because it is a thing that you can describe. It is a shopping cart. It holds things you want to purchase. You can put things in the cart and take things out of the cart. The interface provides buttons to make this easy.

I have never written code that uses a student object or a employee object. Most of my classes represent something slightly more abstract.

Thanks deanhystad for shopping cart. I will be studying it to see how it works.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] Tkinter classes Gupi 8 4,594 May-26-2019, 05:20 PM
Last Post: Gupi
  [Tkinter] How to create multilple tabs in tkinter from different classes Rishav 5 18,252 Jul-11-2018, 11:59 AM
Last Post: CCChris91

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020