0

I'm learning OOP and am making a calculator. I have classes for the main program (the parent program), buttons, and entries.

Main program:

class Program(tk.Tk): 

    def __init__(self, title, size): 
        super().__init__()
        self.title(title)
        self.geometry(f"{size[0]}x{size[1]}")

        # Program elements split into widget type
        self.entries = Entries(self) 
        self.output = Output(self)
        self.buttons = Buttons(self)

Entries:

class Entries(ttk.Frame):
    
    def __init__(self, parent): 
        super().__init__(parent) 
        self.place(x = 0, y = 0) 

        # Calling widget generator and placer functions
        self.entryGen() 
        self.entryPlacer()
    
    def entryGen(self): # Create entry widgets
        self.firstTerm = ttk.Entry(self) 
        self.commonDifference = ttk.Entry(self)
        self.numberOfTerms = ttk.Entry(self)
    
    def entryPlacer(self): # Place entry widgets
        self.firstTerm.pack()
        self.commonDifference.pack()
        self.numberOfTerms.pack()

Buttons:

class Buttons(ttk.Frame):

    def __init__(self, parent):
        super().__init__(parent)
        self.place(x = 0, y = 0)

        self.buttonGen()
        self.buttonPlacer()

    def buttonGen(self):
        self.clear = ttk.Button(self, text = "Clear", command = lambda: self.clear)
        self.calculate = ttk.Button(self, text = "Calculate", command = lambda: self.calculate)
    
    def buttonPlacer(self):
        self.clear.pack()
        self.calculate.pack()
    
    def clear(self):
        pass

    def calculate(self):
        entries = Entries()
        try:
            print(entries.firstTerm.get() + entries.commonDifference.get() + entries.numberOfTerms.get()) # Just some test code to see if it works, which it doesnt
        except:
            pass

I expect that when I create a reference to the Entries() class in my Buttons() class, I can access the variables I made in the Entries() class. This is not the case and I can't figure out why. I have looked at similar fixes and none seem to work.

acw1668
  • 40,144
  • 5
  • 22
  • 34
tomasv
  • 27
  • 4
  • You need to define the variables in `__init__`. They are not defined without calling the functions. – Guy May 31 '23 at 10:27
  • @Guy OP runs those other methods in init, it should be alright... but the code they showed uses Entries() while the init there takes a parent - so it should break even before that print – h4z3 May 31 '23 at 10:32
  • @tomasv 1. You do Entries() but the init in that class says you need to pass a parent - the code should therefore crash before the print line. If it doesn't crash, then it suggests you're running different code that you showed us. 2. Remove the try and bare except - you're hiding the error. Let the error crash your app and just show us what it says. – h4z3 May 31 '23 at 10:34

2 Answers2

0

Your Buttons class won't have direct access to your Entries class unless you pass the entries instance (or at least an entries instance) to it at __init__

What it does have access to, however, is the Program class via parent

The approach I've taken in the past is as follows:

class Buttons(ttk.Frame):

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

This way, your child class Buttons can access Entries' instance attributes through their shared parent class via the instance entries created at Program.__init__().

You could update the Entries class __init__ in a similar way so that it too can access attributes from parent

I also tend to take the approach outlined in this answer by creating a dictionary of "shared" variables within my root application class

JRiggles
  • 4,847
  • 1
  • 12
  • 27
0

There are few issues in your code:

  • you should not create another instance of Entries inside Buttons.calculate(). Suggest to pass the instance to Buttons when it is created;

  • the function self.calculate() is not called actually in the expression command=lambda: self.calculate. Use command=self.calculate instead. Same issue for command=lambda: self.clear;

  • if the three inputs are numbers, you need to convert them to numbers before doing the calculation.

Updated code:

import tkinter as tk
from tkinter import ttk

class Program(tk.Tk):

    def __init__(self, title, size):
        super().__init__()
        self.title(title)
        self.geometry(f"{size[0]}x{size[1]}")

        # Program elements split into widget type
        self.entries = Entries(self)
        self.output = Output(self)
        self.buttons = Buttons(self, self.entries) ### pass self.entries to class Buttons

class Entries(ttk.Frame):

    def __init__(self, parent):
        super().__init__(parent)
        self.place(x = 0, y = 0)

        # Calling widget generator and placer functions
        self.entryGen()
        self.entryPlacer()

    def entryGen(self): # Create entry widgets
        self.firstTerm = ttk.Entry(self)
        self.commonDifference = ttk.Entry(self)
        self.numberOfTerms = ttk.Entry(self)

    def entryPlacer(self): # Place entry widgets
        self.firstTerm.pack()
        self.commonDifference.pack()
        self.numberOfTerms.pack()

class Buttons(ttk.Frame):

    def __init__(self, parent, entries): ### added argument entries
        super().__init__(parent)
        self.place(x = 200, y = 0)

        self.entries = entries  ### save the passed entries
        self.buttonGen()
        self.buttonPlacer()

    def buttonGen(self):
        self.clear = ttk.Button(self, text = "Clear", command = self.clear) ### remove lambda
        self.calculate = ttk.Button(self, text = "Calculate", command = self.calculate) ### remove lambda

    def buttonPlacer(self):
        self.clear.pack()
        self.calculate.pack()

    def clear(self):
        pass

    def calculate(self):
        try:
            ### convert inputs to numbers before calculation
            print(float(self.entries.firstTerm.get()) + float(self.entries.commonDifference.get()) + float(self.entries.numberOfTerms.get()))
        except Exception as ex:
            ### better show the execption
            print(ex)
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • Thanks for the help, it works great! I'm confused how it doesn't automatically fill the variables when you type self.entries.firstTerm, almost as it doesn't exist, but regardless it works. – tomasv May 31 '23 at 22:16