13

I'm trying to create a simple UI with Tkinter and I have run into a problem. My code looks like this:

class UIController(tk.Tk):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        self.frames = {}
        for F in (StartPage, BrowsePage, StudentPage):
            frame = F(self, container)
            self.frames[F] = frame
            frame.title("StudyApp")
        self.showFrame(StartPage)
        self.centerWindow()

    def showFrame(self, c):
        frame = self.frames[c]
        frame.tkraise()

    def centerWindow(self):
        w = 300
        h = 350
        sw = self.master.winfo_screenwidth()
        sh = self.master.winfo_screenheight()
        x = (sw - w)/2
        y = (sh - h)/2
        self.master.geometry('%dx%d+%d+%d' % (w, h, x, y))

class StartPage(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.pack()

        self.L1 = Label(self, text="Search by credits:")
        self.L1.place(x=18, y=45)

        self.startYear = Entry(self, bd=2)
        self.startYear.place(x=20, y=70)
        self.startYear.bind("<Return>", View.enter(startYear.get()))

        self.quitButton = Button(self, text="Quit", command=sys.exit)
        self.quitButton.pack(side="bottom", padx=5, pady=5, fill=X)

        self.searchButton = Button(self, text="Search")
        self.searchButton.pack(side="bottom", padx=5, pady=0, fill=X)   

class BrowsePage(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)

class StudentPage(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)

root = tk.Tk()
root.resizable(width=False, height=False)
uicontrol = UIController(root)
root.mainloop()

It gives a TypeError that the constructor takes 2 arguments but 3 were given. What I'm trying to do is have the 3 pages (StartPage, BrowsePage and StudentPage) in the frame 'container', and bring them up as needed with button pushes and such. I don't understand why I'm getting this error.

EDIT:

Added the UIController call.

EDIT2:

Added the page classes StartPage, BrowsePage and StudentPage. The latter two classes are only husks at this point.

jonraem
  • 175
  • 1
  • 1
  • 10
  • Could you show how you call UIController? – Jimmy C Mar 23 '14 at 20:52
  • Just tried out your code (Except for 'FALSE' => 'False'), and I'm getting through the initiation. Try to restart your interpreter, might be old variables bothering you. I get a TclError though: "bad side "TOP": must be top, bottom, left, or right" – Jimmy C Mar 23 '14 at 21:21
  • Yeah, I noticed those too. I'll edit those out and paste the page classes just in case the problem is somewhere in there. – jonraem Mar 23 '14 at 21:27
  • The important debugging information here was not details on each class, nor the methods that don't get called (because the exception happens first), but instead a [complete](https://meta.stackoverflow.com/questions/359146) stack trace - which would point directly at the line where the error occurred, and guide in creating a proper [mre]. – Karl Knechtel Sep 08 '22 at 06:30

2 Answers2

8

I think this is the line that is causing the issue, you cannot pass the self instance to the constructor.

frame = F(self, container)

Can you please check and add more information to the question to understand what you are trying to achieve.

asp
  • 621
  • 8
  • 18
  • 1
    Pretty sure it's actually the `tk.Frame.__init__(self, master)` lines, given the error message. They should be `tk.Frame.__init__(master)`. – naught101 Jan 19 '15 at 05:27
  • 1
    @naught101 no; when calling a base class' methods directly, `self` should be specified explicitly - because we are looking the method up in the base class directly, not via an instance. `master` should receive the value of `container`, i.e., the common `Frame` that will contain either a `UIController`'s widgets or a different page's widgets at different times. – Karl Knechtel Sep 08 '22 at 06:35
-1

You can just add in __init__ one more argument, controller.

This works for me:

def __init__(self, master, controller):
    tk.Frame.__init__(self, master)
khelwood
  • 55,782
  • 14
  • 81
  • 108
  • This avoids the immediate error, but results in forwarding the wrong argument. It makes the `UIController` be the `master` of the other UI pages, which it shouldn't be - they represent separate UI states, not "child" UIs. Despite the naming, the other classes don't need or want a reference to the `UIController`. It should not have passed `self` in the first place. – Karl Knechtel Sep 08 '22 at 06:32