0

I have been trying to call the function showframe which takes two aurgument. When i call it from Button command in HomePage it shows an error. TypeError: showframe() missing 1 required positional argument: 'frame_name'. I can't understand why? As I called by class name so it should automatically get self, then frame_name will get the SignIn class. But thats not happening.

class Culpture(Frame):
    def __init__(self, root):
        Frame.__init__(self, root)
        fhome = HomePage(root)
        fsignin = SignIn(root)
        self.showframe(fhome)
        fhome.grid(row=0, column=0, sticky='nsew')
        fsignin.grid(row=0, column=0, sticky='nsew')
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

    def showframe(self, frame_name):
        frame_name.tkraise()
class HomePage(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        Label(self, text="Homepage").grid()
        Button(self, text='SignIn', command=lambda: Culpture.showframe(SignIn), width=20).grid()

If I do this way,

Button(self, text='SignIn', command=lambda: Culpture.showframe(parent, SignIn), width=20).grid()

then it shows another error message.TypeError: tkraise() missing 1 required positional argument: 'self' So I tried to look some question I got one which is close to my solutionPython/Tkinter Event Argument Issue but not same. If I try another way Button(self, text='SignIn', command=lambda: Culpture.showframe(parent, SignIn(parent)), width=20).grid() then it shows no error but button does not open the new frame.

class SignIn(Frame):
def __init__(self, parent):
    Frame.__init__(self, parent)
    Label(self, text="SignIn").grid()
    Button(self, text='Submit', width=20).grid()

So it would be really helpfull if any of you can help me out.

Abdullah Al Mubin
  • 123
  • 1
  • 2
  • 10

2 Answers2

1

Somewhere in your code you need to create an instance of Culpture. You need to use that instance to call show_frame. When you do that, the instance will be automatically passed as the self parameter, and the argument you pass will be frame_name.

culpture = Culpture(root)
...
culpsure.show_frame(fsignin)

You didn't show where you create the instance of Culpture so it's hard to be any more specific than that.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Here showframe doesn't get reference of 'fsingin'. `class HomePage(Frame): def __init__(self, parent): f1 = Culpture(parent) Frame.__init__(self, parent) Label(self, text="Homepage").grid() Button(self, text='SignIn', command=lambda: f1.showframe(fsignin), width=20).grid()` – Abdullah Al Mubin Apr 20 '18 at 01:44
1

You are doing things the wrong way. Ideally, you are supposed to make different classes for different pages which will make the code less messy.

So, make a different class for SignIn and a different one for home.

Following is written in python3:

import tkinter as tk
from tkinter import *

class Culpture(tk.Tk):
    def __init__(self,*args,**kwargs):
    tk.Tk.__init__(self,*args,**kwargs)

    F1=tk.Frame(self)
    F1.pack(side="top",fill="both",expand=True)

    F1.grid_rowconfigure(0,weight=1)
    F1.grid_columnconfigure(0,weight=1)

    self.frames={}

    for F in (Home,SignIn):                                       # Looping between the pages: Home, SignIn (if they are interconnected through buttons)
        frame=F(F1,self)                                          # If they are all not interconnected, make different loops for different sets all containg the same element Home

        self.frames[F]=frame
        frame.grid(row=0,column=0,sticky="nsew")


    self.show_frame(Home)

    def show_frame(self,cont):

    frame=self.frames[cont]
    frame.tkraise()

class Home(tk.Frame):                                                   # Home page

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

    label=Label(self,text="Home",foreground="blue")
    label.pack(pady=10,padx=10)

    signB=Button(self,text="SignIn",command=lambda:controller.show_frame(SignIn),foreground="snow", background="blue")

    signB.pack()
    #trajectory.tkinter.tix.balloon



class SignIn(tk.Frame):                                                # SignIn

    def __init__(self,parent,controller):
    tk.Frame.__init__(self,parent)
    label=Label(self,text="Enter datails",foreground="red")
    label.pack(pady=10,padx=10)

    home=Button(self,text="Home",command=lambda:controller.show_frame(Home),foreground="snow", background="red")
    home.pack()


root=Culpture()

root.mainloop()

Let me know, if this does not work. Also,to add more pages:

If they are interconnected- add the names of the classes to the same loop.

If they are connected to some page in common- make a new lop, with the names.

Eshita Shukla
  • 791
  • 1
  • 8
  • 30
  • 1
    `import tkinter as tk` & `from tkinter import *`... why? – Reblochon Masque Apr 19 '18 at 06:33
  • In some very rare cases, when the program is very large, you may need it for organisation. It's not mandatory at all. I just do it for most of my programs to avoid errors (unless it lags..). – Eshita Shukla Apr 19 '18 at 09:29
  • This code works. But I can't understand why I have to inherit Tk() class in Culpture instead of Frame class? Though I use a dictionary for frame class why I passed frames class in showframe `self.show_frame(Home)` instead of dictionary name? – Abdullah Al Mubin Apr 20 '18 at 01:32
  • @AbdullahAlMubin: you don't have to inherit from the `Tk` class. You can inherit from `Frame` instead. It's just that you have to have an instance of `Tk` somewhere, and since this is the "main" frame, there's no need to create a frame and then place it in an empty window. – Bryan Oakley Apr 20 '18 at 02:26
  • @EshitaShukla Can you explain though using a dictionary for frame class why I passed `Home` class in showframe `self.show_frame(Home)` instead of dictionary name `self.show_frame(frames[Home])` ? – Abdullah Al Mubin Apr 20 '18 at 04:28
  • See, show_frame has to take an argument , process that argument and then, show it. Now, it has to iterate. Thus, you could use a a list or a dictionary. If a list is used, Then, you have to use an integer index, and it will becometidious. Therefor, I used a dictionary. – Eshita Shukla Apr 21 '18 at 05:17