Hector
Hector

Reputation: 285

How to make the definition of Combo box Classes in Tkinter to create a simple calculation

I have a problem trying to create a simple calculation with combo box in tkinter using Classes. For me this is quite tricky, and difficult to understand it! Hope you can help me with this.

Thanks in advance.

Héctor.

Here is my code:

from Tkinter import *
import ttk
from ttk import Combobox

root= Tk()
root.minsize(550,450)
root.maxsize(560,460)
root.title('myAPP')

class Calculation:
    def __init__(self, parent):
        self.parent = parent
        self.Value1()
        self.Value2()
        self.Result()

        Label(self.parent,text='Num 1').grid(column=2, row=5,sticky=W,pady=3)
        Label(self.parent,text='Num 2').grid(column=2, row=6,sticky=W,pady=3)
        Label(self.parent,text='result').grid(column=9,row=9,sticky=W,pady=3)

        self.msg =Label(self.parent,text='Sum of 2 number')
        self.msg.grid(row=3,column=1,columnspan=2)

        self.Button =Button(text='Calculate',width=8,command =self.Result)
        self.Button.grid(row=9,column=2,padx=2,pady=3)

    def Value1(self):
        self.field1 = StringVar()
        self.field1 = ttk.Combobox(self.parent, textvariable= self.field1)
        self.field1['values'] = ('5', '6', '7')
        self.field1.grid(column=3, row=5)

    def Value2(self):
        self.field2 = StringVar()
        self.field2 = ttk.Combobox(self.parent, textvariable=self.field2)
        self.field2['values'] = ('1', '2', '3')
        self.field2.grid(column=3, row=6)

    def Result(self):
        self.entry = StringVar()
        self.entry = ttk.Entry(self.parent, textvariable = self.entry)
        #self.entry = field1 + field2 ----> Here is the problem I have!
        self.entry.grid(column=3, row=9)

#End Code
if __name__ == '__main__':
    app = Calculation (root) 
    root.mainloop()

Upvotes: 0

Views: 3207

Answers (3)

falsetru
falsetru

Reputation: 369494

from Tkinter import *
import ttk

root= Tk()
root.minsize(550,450)
root.maxsize(560,460)
root.title('myAPP')

class Calculation:
    def __init__(self, parent):
        self.parent = parent
        self.Value1()
        self.Value2()
        self.Result()

        Label(self.parent,text='Num 1').grid(column=2, row=5, sticky=W, pady=3)
        Label(self.parent,text='Num 2').grid(column=2, row=6, sticky=W, pady=3)
        Label(self.parent,text='result').grid(column=9,row=9, sticky=W, pady=3)

        self.msg = Label(self.parent,text='Sum of 2 number')
        self.msg.grid(row=3,column=1,columnspan=2)

    def Value1(self):
        self.field1_value = StringVar()
        self.field1_value.trace('w', self.Calc)
        self.field1 = ttk.Combobox(self.parent, textvariable=self.field1_value)
        self.field1['values'] = ('5', '6', '7')
        self.field1.grid(column=3, row=5)

    def Value2(self):
        self.field2_value = StringVar()
        self.field2_value.trace('w', self.Calc)
        self.field2 = ttk.Combobox(self.parent, textvariable=self.field2_value)
        self.field2['values'] = ('1', '2', '3')
        self.field2.grid(column=3, row=6)

    def Result(self):
        self.entry = StringVar()
        self.entry = ttk.Entry(self.parent, textvariable=self.entry)
        self.entry.grid(column=3, row=9)

    def Calc(self, *args):
        self.entry.delete(0, END)
        try:
            value = int(self.field1.get()) + int(self.field2.get())
        except ValueError:
            self.entry.insert(0, 'Input numbers.')
        else:
            self.entry.insert(0, str(value))

if __name__ == '__main__':
    app = Calculation(root) 
    root.mainloop()

I splitted Result method into two methods: Result, Calc

  • Result(): make a entry widget that will display the sum. This is called only once (when Calculation object is created.)
  • Calc(): Calculate the sum and display it. This is called when 'Calculate' button is clicked.

EDIT - Removed button. - Attach textvariable (field1_value, field2_value) to comboboxes. - When variables change (= comboxbox value change) call Calc() using StringVar.trace

Upvotes: 1

FabienAndre
FabienAndre

Reputation: 4623

Your interface code will be splitted in two parts: a description of your widgets wich will be run at initialisation and the dynamic behavior of your application.

You already have the description of your GUI. For the behavior, defining a command on the button is a good start, but this code will not look like your Result method (which create an entry). In this method (named a callback), you will manipulate your already existing object : read the value of the comboxboxes, set the new value of the entry... For example (adapted from falsetru's answer):

self.button  = Button(... , command=self.calcultate)

def calculate(self):
    self.entry.delete(0, END)
    value = int(self.field1.get()) + int(self.field2.get())
    self.entry.insert(0, str(value))

There are other way to define the behavior of you application, for instance, you can associate variables to widgets with values (entries, comboboxes...) and trigger an action as soon as this variables are modified:

self.number1 = IntVar()
self.field1 = ttk.Combobox(self.parent, textvariable=self.number1)


self.number1.trace("w", self.calculate) 

(Note that I have choose to use an IntVar to avoid the need of int() parse of the previous solution).

To avoid errors when the user enter non number in the combobox, you could either catch exception when you read values, or use a validation command to forbid non-digit input.

def ensure_digit(candidate_string):
    return candidate_string.isdigit()

self.field1.config(validate = "key", validatecommand =(self.field1.register(ensure_digit),  "%S"))

Upvotes: 0

martineau
martineau

Reputation: 123531

I think this does what you're trying to accomplish:

from Tkinter import *
import ttk
from ttk import Combobox

class Calculation(object):
    def __init__(self, parent):
        self.parent = parent
        self.create_widgets()

    def create_widgets(self):
        self.msg = Label(self.parent, text='Sum of 2 numbers:')
        self.msg.grid(row=3, column=1, columnspan=2)

        Label(self.parent, text='Num 1').grid(row=5, column=2, sticky=W, pady=3)
        self.number1 = IntVar()
        self.widget1 = ttk.Combobox(self.parent, textvariable=self.number1)
        self.widget1['values'] = '5', '6', '7'
        self.widget1.grid(row=5, column=3)

        Label(self.parent, text='Num 2').grid(row=6, column=2, sticky=W, pady=3)
        self.number2 = IntVar()
        self.widget2 = ttk.Combobox(self.parent, textvariable=self.number2)
        self.widget2['values'] = '1', '2', '3'
        self.widget2.grid(row=6, column=3)

        self.button = Button(text='Calculate', command=self.calculate_result)
        self.button.grid(row=9, column=2, padx=2, pady=3)
        self.result = StringVar()
        self.widget3 = ttk.Entry(self.parent, textvariable=self.result)
        self.widget3.grid(row=9, column=3)
        Label(self.parent, text='result').grid(row=9, column=9, sticky=W, pady=3)

    def calculate_result(self):
        self.result.set(self.number1.get() + self.number2.get())

if __name__ == '__main__':
    root= Tk()
    root.minsize(550, 450)
    root.maxsize(560, 460)
    root.title('myAPP')
    app = Calculation(root)
    root.mainloop()

I also highly recommend that you read and start following the recommendations in PEP 8 -- Style Guide for Python Code especially in regards to naming of entities in your code. In addition, I think if you were more consistent in the ordering of keyword arguments and spacing of them that it would be a great improvement in your coding style. It's good to establish doing things properly early on, so that they'll become habits you won't even have to think about doing later.

Upvotes: 0

Related Questions