1

I'm looking for advice on how to solve my problem. I need a way to save the entries list in my saveInput() method so I can access it later outside the class with a different function. The only solution I have come up with is a global variable but I'm told they are the devil and I should try to avoid them when they are not constant. If anybody could give me a solution I would greatly appreciate it. My code is below, including the CSV file.

from tkinter import font as tkfont  # python 3
import tkinter as tk
import csv


class SampleApp(tk.Tk):

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

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is the start page", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        button1 = tk.Button(self, text="Enter airport details",
                            command=lambda: controller.show_frame("PageOne"))
        button2 = tk.Button(self, text="Enter flight details",
                            command=lambda: controller.show_frame("PageTwo"))
        button3 = tk.Button(self, text="Enter price plan and calculate profit",
                            command=lambda: controller.show_frame("PageThree"))
        button4 = tk.Button(self, text="Clear data",
                            command=lambda: controller.show_frame("PageFour"))
        button1.pack()
        button2.pack()
        button3.pack()
        button4.pack()


class PageOne(tk.Frame):

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

        ukAirportOptionList = [
            "LPL",
            "BOH"
        ]

        foreignAirportList = []

        with open('Airports.csv', 'r') as fd:
            reader = csv.reader(fd)
            for row in reader:
                foreignAirportList.append(row)

        tk.Label(self, text="Airport Details", font=controller.title_font).grid()

        ukAirportTracker = tk.StringVar()
        ukAirportTracker.set("Select the UK Airport")
        tk.OptionMenu(self, ukAirportTracker, *ukAirportOptionList).grid()

        foreignAirportTracker = tk.StringVar()
        foreignAirportTracker.set("Select the Oversea Airport")
        tk.OptionMenu(self, foreignAirportTracker, *[airport[0] for airport in foreignAirportList]).grid()

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"),
                                                self.saveInput(ukAirportTracker, foreignAirportTracker)])
        saveButton.grid(row=3, column=1)

    def saveInput(self, *args):
        enteries = []

        for arg in args:
            enteries.append(arg.get())

        print(enteries)

class PageTwo(tk.Frame):

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

        aircraftTypesList = [['medium narrow body', 8, 2650, 180, 8],
                             ['large narrow body', 7, 5600, 220, 10],
                             ['medium wide body', 5, 4050, 406, 14]]

        label = tk.Label(self, text="Flight Details", font=controller.title_font)
        label.grid()

        aircraftTypeTracker = tk.StringVar()
        aircraftTypeTracker.set("Aircraft Type")
        tk.OptionMenu(self, aircraftTypeTracker, *[aircraft[0] for aircraft in aircraftTypesList]).grid()

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"), self.saveInput(aircraftTypeTracker)])
        saveButton.grid()

    def saveInput(self, *args):
        enteries = []

        for arg in args:
            enteries.append(arg.get())

        print(enteries)


class PageThree(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        tk.Label(self, text="This is page 3", font=controller.title_font).grid(row=0, column=0)

        tk.Label(self, text="Price of Standard Seat").grid(row=1)
        tk.Label(self, text="Price of First Class Seat").grid(row=2)

        e1 = tk.Entry(self)
        e2 = tk.Entry(self)

        e1.grid(row=1, column=1)
        e2.grid(row=2, column=1)

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"), self.saveInput(e1, e2)])

        saveButton.grid(row=3, column=1)

    def saveInput(self, *args):
        enteries = []

        for arg in args:
            enteries.append(arg.get())

        print(enteries)


class PageFour(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 4", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

The csv file:

JFK,John F Kennedy International,5326,5486
ORY,Paris-Orly,629,379
MAD,Adolfo Suarez Madrid-Barajas,1428,1151
AMS,Amsterdam Schiphol,526,489
CAI,Cairo International,3779,3584
  • Please read the questions linked to from [this answer](https://stackoverflow.com/a/7557028/7432) There are a questions asking almost exactly what you are asking. – Bryan Oakley Jul 04 '21 at 03:09

1 Answers1

0

A way to mostly avoid global variables in this case is to make the local variable enteries an instance attribute of some class. In this case I chose the SampleApp "controller" this tkinter app architecture defines. (Note I also changed its name to entries in the modified code below.)

I say that because it's very difficult to not have any.

Disclaimer: I don't quite understand what you want or are planning to put into the enteries list in each Page class of you code, so the results below merely do the same as in your code. I'm also not sure what you mean by "returning variables" because classes are objects and don't return anything per se. They can be containers of data and have methods that return values — but you don't have any examples of that in your question's code. To rectify that I added a Quit button to demonstrate how the data could be retrieved.

Anyway, I made the modifications needed to do that in code below. In addition, I noticed there was a lot of replicated / very similar code in each Page class, so I defined a private base class named _BasePage and derived all the others from it. This allowed me to put the common code in there and is an example of apply the DRY principle which is another benefit of using classes.

from tkinter import font as tkfont  # python 3
import tkinter as tk
import csv


class SampleApp(tk.Tk):

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

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", 
                                      slant="italic")
        self.entries = []  # Accumulated entries.

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name.'''
        frame = self.frames[page_name]
        frame.tkraise()


class _BasePage(tk.Frame):

    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

    def saveInput(self, *string_vars):
        strings = [var.get() for var in string_vars]
        print(f'adding entries: {strings}')
        self.controller.entries.extend(strings)


class StartPage(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        label = tk.Label(self, text="This is the start page", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        tk.Button(self, text="Enter airport details",
                   command=lambda: controller.show_frame("PageOne")).pack()
        tk.Button(self, text="Enter flight details",
                  command=lambda: controller.show_frame("PageTwo")).pack()
        tk.Button(self, text="Enter price plan and calculate profit",
                  command=lambda: controller.show_frame("PageThree")).pack()
        tk.Button(self, text="Clear data",
                  command=lambda: controller.show_frame("PageFour")).pack()
        tk.Button(self, text="Quit",
                  command=self.quit).pack()  # Terminate mainloop().

class PageOne(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        ukAirportOptionList = [
            "LPL",
            "BOH"
        ]

        foreignAirportList = []

        with open('Airports.csv', 'r') as fd:
            reader = csv.reader(fd)
            for row in reader:
                foreignAirportList.append(row)

        tk.Label(self, text="Airport Details", font=controller.title_font).grid()

        ukAirportTracker = tk.StringVar()
        ukAirportTracker.set("Select the UK Airport")
        tk.OptionMenu(self, ukAirportTracker, *ukAirportOptionList).grid()

        foreignAirportTracker = tk.StringVar()
        foreignAirportTracker.set("Select the Oversea Airport")
        tk.OptionMenu(self, foreignAirportTracker,
                      *[airport[0] for airport in foreignAirportList]).grid()

        saveButton = tk.Button(self, text="Save", command=lambda:
                          [controller.show_frame("StartPage"),
                           self.saveInput(ukAirportTracker, foreignAirportTracker)])
        saveButton.grid(row=3, column=1)


class PageTwo(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        aircraftTypesList = [['medium narrow body', 8, 2650, 180, 8],
                             ['large narrow body', 7, 5600, 220, 10],
                             ['medium wide body', 5, 4050, 406, 14]]

        label = tk.Label(self, text="Flight Details", font=controller.title_font)
        label.grid()

        aircraftTypeTracker = tk.StringVar()
        aircraftTypeTracker.set("Aircraft Type")
        tk.OptionMenu(self, aircraftTypeTracker,
                      *[aircraft[0] for aircraft in aircraftTypesList]).grid()

        saveButton = tk.Button(self, text="Save", command=lambda:
                                            [controller.show_frame("StartPage"),
                                             self.saveInput(aircraftTypeTracker)])
        saveButton.grid()


class PageThree(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        tk.Label(self, text="This is page 3",
                 font=controller.title_font).grid(row=0, column=0)

        tk.Label(self, text="Price of Standard Seat").grid(row=1)
        tk.Label(self, text="Price of First Class Seat").grid(row=2)

        e1 = tk.Entry(self)
        e2 = tk.Entry(self)

        e1.grid(row=1, column=1)
        e2.grid(row=2, column=1)

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"),
                                                self.saveInput(e1, e2)])
        saveButton.grid(row=3, column=1)


class PageFour(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        label = tk.Label(self, text="This is page 4", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

    print('Final entries:')
    for entry in app.entries:
        print(f'  {entry}')

martineau
  • 119,623
  • 25
  • 170
  • 301