0

I am trying to create a login script for my program. I was able to write a basic script to test out my Login Frame but I now what to be able to access another Frame after I essentially login.

Here is part of my script:

#!/usr/bin/python


from tkinter import *
from tkinter import ttk

import tkinter as tk
import tkinter.messagebox as tm


Large_Font = ("Verdana", 18)
Small_Font = ("Verdana", 12)


class ATM(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.wm_title(self, "ATM Simulator")

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

        #Create Frame Library and use For Loop to switch between frames

        self.frames = {}

        for i in (LogIn, WelcomePage, Checking, Savings, Transfer):

            frame = i(container, self)
            self.frames[i] = frame 
            frame.grid(row= 100, column = 100, sticky= "nsew")

        self.show_frame(LogIn)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

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

        global act_num_entry
        global pin_num_entry

        label = Label(self, text = "Login Using Account and PIN Numbers", font=Small_Font)
        label.pack(pady=50, padx=50)

        act_num_label = Label(self, text="Account Number")
        act_num_entry = Entry(self)

        pin_num_label = Label(self, text="PIN Number")
        pin_num_entry = Entry(self, show="*")

        act_num_label.pack(pady=5, padx=5)
        pin_num_label.pack(pady=5, padx=5)

        act_num_entry.pack(pady=5, padx=5)
        pin_num_entry.pack(pady=5, padx=5)


        logBTN = ttk.Button(self, text="Enter", 
                            command =self.log_check)
        logBTN.pack()

        quitButton = ttk.Button(self, text = "End Transaction", command = quit)
        quitButton.pack()

    def log_check(self):

        #default test pin and account numbers 

        act_num=1234567
        pin_num=1234   

        #This Try/Except handles the non-integer values being entered

        try:
            actNum = int(act_num_entry.get())
            pinNum = int(pin_num_entry.get())
        except:
            tm.showerror("Login Error", "Invalid Entry")
            pass

        if actNum == act_num and pinNum == pin_num:

            #Message Window only used to to prove my log_check function works

            tm.showinfo("ATM Login", "Login Successful")


            '''Insert script to open the WelcomePage(tk.Frame) method'''


        elif actNum != act_num:
            tm.showerror("Login Error", "Invalid Account Number")
        elif pinNum != pin_num:
            tm.showerror("Login Error", "Invalid PIN Number")
        else:
            tm.showerror("Login Error", "Invalid Entry")

class WelcomePage(tk.Frame):

    #Welcome Page Window

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = Label(self, text = "Welcome to the ATM Simulator", font = Large_Font)
        label.pack(pady=100, padx=100)

        checkButton = ttk.Button(self, text = "Checking Account", 
                             command = lambda: controller.show_frame(Checking))
        checkButton.pack()

        saveButton = ttk.Button(self, text = "Savings Account", 
                            command = lambda: controller.show_frame(Savings))
        saveButton.pack()

        transButton = ttk.Button(self, text = "Transfer Funds", 
                            command = lambda: controller.show_frame(Transfer))
        transButton.pack()

        quitButton = ttk.Button(self, text = "End Transaction", command = self.client_exit)
        quitButton.pack()

    def client_exit(self):
        exit()

So I want to call my WelcomePage(tk.Frame) method from inside my if actNum == act_num and pinNum == pin_num: function so I can essentially login to my program. I tried to access the WelcomePage(tk.Frame)using my show_frame function but I was not able to because I understand that the function is apart of the ATM(tk.Tk) class not LogIn(tk.Frame). Is this possible to accomplish the way I want to or am I going to have to write another login script to accomplish this?

pjmorin0001
  • 79
  • 3
  • 10
  • be careful with terminology: `WelcomePage(tk.Frame)` is not a method. `WelcomePage` is a class. You don't "call" classes, you "instantiate" them (ie: you create an instance of them). – Bryan Oakley Nov 19 '15 at 12:39

2 Answers2

1

show_frame is a method on the controller. You simply need to save a reference to the controller, and call it from anywhere. This is the entire purpose of the controller class - to control access to the other windows.

The first step is to modify your classes to save a reference to the controller:

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

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

Now, you can call show_frame wherever you want:

if actNum == act_num and pinNum == pin_num:
    ...
    self.controller.show_frame(WelcomePage)
    ...

For more information on the controller see this answer: https://stackoverflow.com/a/32865334/7432

Community
  • 1
  • 1
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you very much! In my other frames I put 'self.controller = controller' in my classes but I forgot to update the WelcomePage() and my LogIn() class. I did not realize I forgot to mention my controller in those two classes. – pjmorin0001 Nov 19 '15 at 16:24
-1

Inside LogIn use parent to get access to ATM where you have self.frames[WelcomePage]

self.parent.frames[WelcomePage].some_function()

Probably you will have to add in LogIn.__init__ line

self.parent = parent

EDIT:

because LogIn is inside container which is inside ATM you have use

self.parent.master.show_frame(WelcomePage)

Or you can use

self.master.master.show_frame(WelcomePage)

and then you don't need to add self.parent = parent

furas
  • 134,197
  • 12
  • 106
  • 148
  • while technically your answer will work, it's not how the OP code is designed to work. It has a `controller` that is specifically designed to make it possible to open any page from any other page while keeping the two pages loosely coupled. – Bryan Oakley Nov 19 '15 at 12:44
  • Now I see. I didn't I notice this element. – furas Nov 19 '15 at 18:33