K Lucey
K Lucey

Reputation: 11

Passing An Argument to a TkInter frame

I'm a teacher and every week I grade students' participation score. Since I teach computers, I thought I'd create a program to handle that logic for me. I plan on using TkInter to create a start screen with the 4 periods of the day, and depending on the period, it would pull up that class. But I'm trying to use the same class for all 4 periods, since the code is exactly the same.

Here's my code:

class part(tk.Tk):
    #Creates a class for the GUI

    def __init__(self, *args, **kwargs):
        #Initialization function of partGUI
        tk.Tk.__init__(self, *args, **kwargs)

        tk.Tk.iconbitmap(self, default="") #default icon in an .ico file
        tk.Tk.wm_title(self, "Lucey's Participation Program") #title

        window = tk.Frame(self)
        window.pack(side="top", fill="both", expand=True)
        window.grid_rowconfigure(0, weight=1)
        window.grid_columnconfigure(0, weight=1)

        self.frames= {}



        for F in (StartPage, ClassPart, SettingsPage):
            frame = F(window, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, window):
        #Allows Program to switch windows/pages/frames
        frame = self.frames[window]
        frame.tkraise()

class StartPage(tk.Frame):
# Home Screen for Program
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        title = tk.Label(self, text="Participation Scores", font=LARGE_FONT)
        title.pack(pady=10, padx=10)

        btnPeriod1 = tk.Button(self, text="1st Period", fg="red",
                               command=lambda: controller.show_frame(ClassPart(controller, 1)))
        btnPeriod1.pack()


class ClassPart(tk.Frame):
# Screen showing students, participation buttons & their scores/Hogwarts houses    

    def __init__(self, parent, controller, period):
        tk.Frame.__init__(self, parent)

But this throws an error:

Traceback (most recent call last):
  File "/home/klucey/Documents/partvers2.py", line 307, in <module>
    window = part()
  File "/home/klucey/Documents/partvers2.py", line 40, in __init__
    frame = F(window, self)
TypeError: __init__() missing 1 required positional argument: 'period'

Any help to a beginner/intermediate would be greatly appreciated!

Upvotes: 0

Views: 898

Answers (1)

jasonharper
jasonharper

Reputation: 9587

This boilerplate code that you (and everybody else on SO, it seems) are using to handle a multi-page Tkinter app is simply not suitable for handing multiple pages of the same class. You'd have to put multiple occurrences of ClassPart in the page list, and somehow arrange for them to be given a different period parameter when constructed - but this breaks the .show_frame() method, as you no longer have a unique identifier to select the page to be shown.

Here's what I would suggest instead, given that you have a fixed set of pages (this wouldn't work so well with dynamically-generated pages):

  • Get rid of the period parameter in your class (so that its constructor is compatible with the other pages).
  • Create a subclass of it for each period:

    class ClassPart1(ClassPart):
        period = 1
    class ClassPart2(ClassPart):
        period = 2
    

    ... and so on. Refer to self.period in the base class to access this value.

  • Change the initial page creation loop to for F in (StartPage, ClassPart1, ClassPart2, ClassPart3, ClassPart4, SettingsPage):. Use ClassPart1, etc. as the identifier to pass to .show_frame().

Upvotes: 1

Related Questions