user2132792
user2132792

Reputation: 5

Can not get Objects to work in tkinter

I have been having trouble converting cli apps to gui apps with tkinter. The main issue seems to be wrong usage of objects (?). I am posting a simple example, so that you could see what I am doing wrong, in general? Usually I get error getting the float values, before even the gui will launch.

Here is the code example:

#import modules
#
from tkinter import *
from tkinter import ttk
import csv


class rectangle:
    '''A rectangle'''

    def __init__(self, w, h):
        self.width = w
        self.height = h

    def getWidth(self):
        return self.width

    def getHeight(self):
        return self.height

def area_calculator(rectangle):
    '''Function to calculate the area of a rectangle.'''

    side1 = float(rectangle.getWidth())
    side2 = float(rectangle.getHeight())

    area = side1*side2
    return area


root = Tk()
root.title("Area Calculator")

mainframe = ttk.Frame(root, padding="6")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)



width = ttk.Entry(mainframe, width=7)
width.grid(column=1, row=1)
height = ttk.Entry(mainframe, width=7)
height.grid(column=1, row=2)



ttk.Label(mainframe, text="Side 1").grid(column=2, row=1, sticky=W)
ttk.Label(mainframe, text="Side 2").grid(column=2, row=2, sticky=W)


myrectangle = rectangle(width, height)



myButton = ttk.Button(mainframe, text="CalcArea",command = area_calculator(myrectangle))
myButton.grid(column=1, row=6, sticky=W)
ttk.Label(mainframe, textvariable=area).grid(column=2, row=6, sticky=(W, E))



for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=2)

root.mainloop()

Upvotes: 0

Views: 55

Answers (1)

Kevin
Kevin

Reputation: 76194

Problem 1:

side1 = float(rectangle.getWidth())
side2 = float(rectangle.getHeight())

When you created rectangle, you provided two Entry objects as its width and height values. so rectangle.getWidth() returns an Entry object, and float(rectangle.getWidth()) tries to convert that Entry object into a float. It would make more sense to construct the rectangle object using numerical values instead of Entries. However, if you do this, it will be necessary to create the rectangle inside the function, since if you create it before mainloop, the user won't have a chance to enter anything into the text box first.

def area_calculator():
    '''Function to calculate the area of a rectangle.'''
    rect = rectangle(float(width.get()), float(height.get()))

    side1 = rect.getWidth()
    side2 = rect.getHeight()

    area = side1*side2
    return area

Problem 2:

myButton = ttk.Button(mainframe, text="CalcArea",command = area_calculator(myrectangle))

When you specify the command for a widget, you have two choices:

  • provide a function name, with no parentheses and no arguments.
  • provide a function name with parentheses and arguments, preceded by a lambda.

If you have parentheses but no lambda, the function will be called early. It will execute right away, instead of when the user clicks the button.

If you were still using a form of area_calculator that took arguments, you'd have to do it like:

myButton = ttk.Button(mainframe, text="CalcArea",command = lambda: area_calculator(myrectangle))

... But we changed area_calculator in the previous section so that it takes no arguments. So you can just write the name.

myButton = ttk.Button(mainframe, text="CalcArea",command = area_calculator)

Problem 3:

ttk.Label(mainframe, textvariable=area).grid(column=2, row=6, sticky=(W, E))

You specify a textvariable of area here, but no such value exists. Yes, there's an area in area_calculator, but that function hasn't executed yet, and even if it had, the variable wouldn't be accessible outside the function. Instead, create a StringVar, use that as the textvariable, and set it within area_calculator.

def area_calculator():
    '''Function to calculate the area of a rectangle.'''
    rect = rectangle(float(width.get()), float(height.get()))

    side1 = rect.getWidth()
    side2 = rect.getHeight()

    area = side1*side2
    area_var.set(area)

#later, while creating widgets...
myButton = ttk.Button(mainframe, text="CalcArea",command = area_calculator)
myButton.grid(column=1, row=6, sticky=W)
area_var = StringVar()
ttk.Label(mainframe, textvariable=area_var).grid(column=2, row=6, sticky=(W, E))

Once you repair these problems, you should be able to calculate area successfully.

enter image description here

Upvotes: 2

Related Questions