How to create a calculator using Python

It can be a great way to create a calculator using Python and the Tkinter module to familiarize yourself with the basics of Python and GUI programming. Tkinter is a built-in Python library that provides a simple and easy-to-use interface for creating graphical user interfaces. It is widely used in a variety of applications, from small desktop programs to large enterprise systems. With its powerful set of widgets, tkinter makes it easy to create interactive and visually appealing applications.

In this project, we will be creating a basic calculator that can perform basic arithmetic operations such as addition, subtraction, multiplication, and division. We will be using Python as the programming language and tkinter as the GUI library. The calculator will have a simple layout with buttons for numbers and operations, and a display area for the result.

We will start by creating the basic structure of the calculator, including the window and layout, and then move on to implementing the functionality of the buttons. Along the way, we will learn how to use tkinter’s widgets, such as buttons and labels, and how to handle events, such as button clicks. By the end of this project, you will have a solid understanding of how to create a calculator using Python and tkinter, and will have the skills to create more complex applications in the future.

The video

The structure

import tkinter as tk

class Calculator(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Calculator")
        self.geometry("480x620")
        self.result = tk.Entry(self, font=("Arial", 36))
        self.result.grid(row=0, column=0, columnspan=4, padx=10,
                         pady=10, ipadx=40, ipady=20, sticky=tk.W+tk.E)
        self.result.config(justify=tk.LEFT)
        self.grid_columnconfigure(0, weight=1)

        button_frame = tk.Frame(self)
        button_frame.grid(row=1, column=0, columnspan=4, padx=10, pady=10)

In the following we will be explaining the structure code line by line:

def __init__(self):

The “__init__” method is a special method in Python classes, also known as a constructor. It is used to initialize the attributes of an object when it is first created. The self parameter refers to the object itself and is used to access and modify the object’s attributes. The method is called automatically when a new object is created from the class.

super().__init__()

The super() function is used to call a method from the parent class. In this case, super().__init__() is calling the __init__ method of the parent class. This can be used to ensure that the initialization code in the parent class is executed before any additional initialization code in the child class. It is important to note that super() only works if the class being defined is a subclass of another class.

self.result = tk.Entry(self, font=("Arial", 36))

This code is creating a new Tkinter Entry widget and storing it in an attribute called result on the current object (self). The Entry widget is used to create a single-line text input field where the user can enter text. The font parameter is being set to a tuple of (“Arial”, 36) which is specifying the font and size of the text in the entry field. This widget is typically used to get input from the user, like displaying a calculator.

self.result.grid(row=0, column=0, columnspan=4, padx=10,
                         pady=10, ipadx=40, ipady=20, sticky=tk.W+tk.E)
      

This code is using the grid method to place the self.result widget, which is a tkinter Entry widget, within a grid layout in the parent widget. The row and column parameters specify the position of the widget within the grid, with row=0 and column=0 placing the widget at the top-left corner of the grid.

The columnspan parameter is set to 4, which means the widget will span across 4 columns in the grid. This allows the widget to take up more space horizontally.

The padx and pady parameters specify the amount of padding, in pixels, to add to the widget on the x and y axis respectively. This can be used to add space between the widget and other widgets in the grid.

The ipadx and ipady parameters specify the internal padding, in pixels, to add to the widget on the x and y axis respectively. This can be used to add space within the widget.

The sticky parameter is set to tk.W+tk.E which means the widget will be stretched to fill the entire width of the cell it is assigned to and “stick” to the west and east sides of the cell. As per [1], it forces the button to stick to the sides of its assigned columns and rows if configured for those directions.

It is important to note that in Tkinter, sticky parameter uses constants such as tk.N, tk.W, tk.E, tk.S or a combination of them as a string, as per [2]. And the grid’s row and column index usually starts with 0 as per [3].Regenerate response

self.result.config(justify=tk.RIGHT)
self.grid_columnconfigure(0, weight=1)

This code is using the grid_columnconfigure method to set the weight of column 0 within the parent widget’s grid layout. The weight parameter is used to specify how much a column or row should grow when the parent widget is resized. When the weight of a column is set to 1, it means that the column will take up any additional space that is available when the parent widget is resized. This can be useful for making sure that certain widgets or columns take up more or less space when the parent widget is resized, depending on their importance or function.

It is important to note that when multiple columns have the same weight value, the available space is divided among them proportionally. And it is also important to configure the weight for every column and row that is used in the grid layout, otherwise, the widgets will not be resized with the parent widget.

button_frame = tk.Frame(self)

This code creates a new tkinter Frame widget and assigns it to the variable button_frame. A Frame widget is a container widget that can be used to group other widgets together. It can be used to organize other widgets in a specific layout and can also be used as a base for creating more complex widgets. The self parameter passed in the Frame constructor indicates that the button_frame is a child of the current widget, which should be the parent widget of the button_frame. The Frame widget can be used to group buttons or other widgets in a specific layout.

button_frame.grid(row=1, column=0, columnspan=4, padx=10, pady=10)

This code uses the grid method to place the button_frame widget within the parent widget’s grid layout. The row and column parameters specify the position of the widget within the grid, with row=1 and column=0 placing the widget at the second row and first column of the grid. The columnspan parameter is set to 4, which means the widget will span across 4 columns in the grid. This allows the button_frame widget to take up more space horizontally. The padx and pady parameters specify the amount of padding, in pixels, to add to the widget on the x and y axis respectively. This can be used to add space between the widget and other widgets in the grid.

This code ensures that the button_frame widget is placed in the second row, first column of the parent widget’s grid layout and will span across 4 columns with a padding of 10 pixels on both x and y axis.Regenerate respo

The buttons

self.create_button("1", button_frame, 0, 0, lambda: self.add_number(1))
self.create_button("2", button_frame, 0, 1, lambda: self.add_number(2))
self.create_button("3", button_frame, 0, 2, lambda: self.add_number(3))
self.create_button("4", button_frame, 1, 0, lambda: self.add_number(4))
self.create_button("5", button_frame, 1, 1, lambda: self.add_number(5))
self.create_button("6", button_frame, 1, 2, lambda: self.add_number(6))
self.create_button("7", button_frame, 2, 0, lambda: self.add_number(7))
self.create_button("8", button_frame, 2, 1, lambda: self.add_number(8))
self.create_button("9", button_frame, 2, 2, lambda: self.add_number(9))
self.create_button("0", button_frame, 3, 1, lambda: self.add_number(0))
self.create_button("+", button_frame, 0, 3,
                           lambda: self.add_operation("+"))
self.create_button("-", button_frame, 1, 3,
                           lambda: self.add_operation("-"))
self.create_button("*", button_frame, 2, 3,
                           lambda: self.add_operation("*"))
self.create_button("/", button_frame, 3, 3,
                           lambda: self.add_operation("/"))
self.create_button("=", button_frame, 3, 2, self.calculate)
self.create_button("C", button_frame, 3, 0, self.clear)

In the following we will be explaining the buttons code:

self.create_button("1", button_frame, 0, 0, lambda: self.add_number(1))

This code is calling the create_button function which we previously defined, and passing the following parameters:

  • “1” as the text of the button
  • button_frame as the frame in which the button will be placed
  • 0 as the row parameter of the button’s position within the frame’s grid layout
  • 0 as the column parameter of the button’s position within the frame’s grid layout
  • a lambda function lambda: self.add_number(1) as the command to be executed when the button is pressed.

The button that is created will have the text “1” displayed on it. When the button is pressed, the lambda function lambda: self.add_number(1) will be executed. This function will call the add_number method with the parameter 1, which is used to add the number 1 to some kind of display or input field. The button is positioned in the grid layout at the first row, first column of the button_frame with a padding of 10 pixels on both x and y axis.

self.create_button("+", button_frame, 0, 3, lambda: self.add_operation("+"))

This code is calling the create_button function and passing the following parameters:

  • “+” as the text of the button
  • button_frame as the frame in which the button will be placed
  • 0 as the row parameter of the button’s position within the frame’s grid layout
  • 3 as the column parameter of the button’s position within the frame’s grid layout
  • a lambda function lambda: self.add_operation("+") as the command to be executed when the button is pressed.

The button that is created will have the text “+” displayed on it. When the button is pressed, the lambda function lambda: self.add_operation("+") will be executed. This function will call the add_operation method with the parameter “+”, which is used to add the operation “+” to some kind of display or input field. The button is positioned in the grid layout at the first row, fourth column of the button_frame with a padding of 10 pixels on both x and y axis.

The functionality

def create_button(self, text, frame, row, column, command, bg="white"):
    button = tk.Button(frame, text=text, command=command,
                       font=("Arial", 18), width=5, height=3)
    if text == "=":
        button.config(bg="green")

    button.grid(row=row, column=column, padx=10, pady=10)

def add_number(self, number):
    current = self.result.get()
    current += str(number)
    self.result.delete(0, tk.END)
    self.result.insert(0, current)

def add_operation(self, operator):
    current = self.result.get()
    current += operator
    self.result.delete(0, tk.END)
    self.result.insert(0, current)

def calculate(self):
    current = self.result.get()
    self.result.delete(0, tk.END)
    self.result.insert(0, eval(current))

def clear(self):
    self.result.delete(0, tk.END)

In the following we will be explaining the functions line by line:

def create_button(self, text, frame, row, column, command):
        button = tk.Button(frame, text=text, command=command,
                           font=("Arial", 18), width=5, height=3)
        button.grid(row=row, column=column, padx=10, pady=10)

This code defines a function create_button which creates a new tkinter Button widget with given text and frame, assigns it to the variable button, and also positions it within the grid layout of the frame, with the given row and column parameters. This function is designed to create a button with a given text, which when pressed will execute the command passed to it. The font, width, and height are also set to specific values.

The bg parameter of the function is set to “white” by default, but if the text passed to the function is equal to “=”, then the background color of the button is changed to “green” using the config method.

Finally, the button is positioned in the grid layout using the grid method, with the given row, column, padx and pady parameters. This function allows for a consistent creation of buttons with specific properties, which can be called multiple times and placed in different frames, positions, with different commands.

def add_number(self, number):
        current = self.result.get()
        current += str(number)
        self.result.delete(0, tk.END)
        self.result.insert(0, current)

This function add_number takes in a parameter number and performs the following steps:

  1. It retrieves the current text in the self.result widget by calling the get() method on it.
  2. It concatenates the passed number parameter to the current text, converting the number to a string before concatenation.
  3. It deletes the current text in the self.result widget by calling the delete(0, tk.END) method on it.
  4. Finally, it inserts the updated text back into the self.result widget by calling the insert(0, current) method on it.

In delete(0, tk.END), the first argument, 0, specifies the start index of the text that should be deleted and the second argument, tk.END, specifies the end index of the text that should be deleted. Together, these arguments effectively delete all the text in the “result” element.

In insert(0, current), the first argument, 0, specifies the index position where the text should be inserted, in this case the text will be inserted at the beginning of the “result” element. The second argument “current” is the text that will be inserted into the “result” element.

This function is used to update the text displayed in the self.result widget with the numbers pressed on the button. The self.result.get() method retrieves the current text displayed in the widget, the self.result.delete(0, tk.END) method deletes the current text, and the self.result.insert(0, current) method updates the text in the widget.

def add_operation(self, operator):
        current = self.result.get()
        current += operator
        self.result.delete(0, tk.END)
        self.result.insert(0, current)

This code defines a method called “add_operation” in the class “Calculator”. It takes in a single parameter, “operator”. The method retrieves the current value stored in the “result” attribute, which is a Tkinter Entry widget and concatenates the “operator” parameter to it. Then, it deletes the current value displayed in the “result” widget and inserts the new value, which is the original value plus the “operator” parameter. This method is used to add mathematical operator like “+”,”-“,”*”,”/” to a running calculation. When the button with the operator is pressed, it calls this method and updates the result Entry widget with the operator.

def calculate(self):
        current = self.result.get()
        self.result.delete(0, tk.END)
        self.result.insert(0, eval(current))

This code defines a method called “calculate” in the class “Calculator”. The method retrieves the current value stored in the “result” attribute, which is a Tkinter Entry widget and passed it to the built-in python function “eval()”.

The eval function evaluates a string as a python expression, so in this case, it will perform the mathematical operation stored in the Entry widget and return the result of the operation. Then, it deletes the current value displayed in the “result” widget and inserts the new value, which is the result of the calculation. This method is used to perform the final calculation of the mathematical expression when the user press the “=” button.

It’s important to note that using eval() is generally not recommended as it can be dangerous when used with untrusted user input. It is always better to use safer ways to evaluate mathematical expressions like ast.literal_eval() or implementing a custom parser.

def clear(self):
        self.result.delete(0, tk.END)

This code defines a method called “clear” in the class “Calculator”. The method is used to clear the content of the Tkinter Entry widget. The method calls the delete method on the “result” attribute which is a Tkinter Entry widget, it takes two arguments, the first is the index of the first character to delete, and the second is the index of the last character to delete, with this method call “0, tk.END” it will delete all the characters in the widget, effectively clearing it. This method is used when the user press the “C” button to clear the Entry widget and start a new calculation.

The code

import tkinter as tk


class Calculator(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Calculator")
        self.geometry("480x620")
        self.result = tk.Entry(self, font=("Arial", 36))
        self.result.grid(row=0, column=0, columnspan=4, padx=10,
                         pady=10, ipadx=40, ipady=20, sticky=tk.W+tk.E)
        self.result.config(justify=tk.LEFT)
        self.grid_columnconfigure(0, weight=1)

        button_frame = tk.Frame(self)
        button_frame.grid(row=1, column=0, columnspan=4, padx=10, pady=10)

        self.create_button("1", button_frame, 0, 0, lambda: self.add_number(1))
        self.create_button("2", button_frame, 0, 1, lambda: self.add_number(2))
        self.create_button("3", button_frame, 0, 2, lambda: self.add_number(3))
        self.create_button("4", button_frame, 1, 0, lambda: self.add_number(4))
        self.create_button("5", button_frame, 1, 1, lambda: self.add_number(5))
        self.create_button("6", button_frame, 1, 2, lambda: self.add_number(6))
        self.create_button("7", button_frame, 2, 0, lambda: self.add_number(7))
        self.create_button("8", button_frame, 2, 1, lambda: self.add_number(8))
        self.create_button("9", button_frame, 2, 2, lambda: self.add_number(9))
        self.create_button("0", button_frame, 3, 1, lambda: self.add_number(0))
        self.create_button("+", button_frame, 0, 3,
                           lambda: self.add_operation("+"))
        self.create_button("-", button_frame, 1, 3,
                           lambda: self.add_operation("-"))
        self.create_button("*", button_frame, 2, 3,
                           lambda: self.add_operation("*"))
        self.create_button("/", button_frame, 3, 3,
                           lambda: self.add_operation("/"))
        self.create_button("=", button_frame, 3, 2, self.calculate, bg="green")
        self.create_button("C", button_frame, 3, 0, self.clear)

    def create_button(self, text, frame, row, column, command, bg="white"):
        button = tk.Button(frame, text=text, command=command,
                           font=("Arial", 18), width=5, height=3)
        button.config(bg=bg)
        button.grid(row=row, column=column, padx=10, pady=10)

    def add_number(self, number):
        current = self.result.get()
        current += str(number)
        self.result.delete(0, tk.END)
        self.result.insert(0, current)

    def add_operation(self, operator):
        current = self.result.get()
        current += operator
        self.result.delete(0, tk.END)
        self.result.insert(0, current)

    def calculate(self):
        current = self.result.get()
        self.result.delete(0, tk.END)
        self.result.insert(0, eval(current))

    def clear(self):
        self.result.delete(0, tk.END)


if __name__ == "__main__":
    calculator = Calculator()
    calculator.mainloop()

The above code is a Python program that creates a simple calculator GUI using the tkinter library. The program creates a custom class called “Calculator” that inherits from the tkinter class “Tk”, which provides the basic structure for creating a GUI application.

In the “init” method of the “Calculator” class, the program sets the title and size of the calculator window, creates a “result” Entry widget to display the results of calculations, and sets the layout of the widgets using the “grid” method. The “result” widget is configured to have left-justified text and to expand to fill the available space in the grid.

The program then creates a frame called “button_frame” to hold the calculator buttons, and adds it to the grid. The program then uses a method called “create_button” to create the number and operator buttons, and adds them to the “button_frame” with the “grid” method.

The program uses lambda functions as the command for the number buttons, which call the “add_number” method and pass the number as an argument. The operator buttons call the “add_operation” method, which appends the operator to the current value of the “result” widget. The “=” button calls the “calculate” method, which evaluates the current value of the “result” widget as a Python expression and replaces the current value with the result. The “C” button calls the “clear” method, which clears the “result” widget.

Finally, the program creates an instance of the “Calculator” class and starts the main event loop with the “mainloop” method. This allows the program to respond to user input and update the GUI as needed.

if __name__ == "__main__":
    calculator = Calculator()
    calculator.mainloop()

This code is the entry point of the program. It checks if the current script is the main script that is being run. If it is, it creates an instance of the “Calculator” class and assigns it to the variable “calculator”. Then it calls the “mainloop” method on this instance, which is a method of the Tkinter library that starts the event loop of the program, allowing the user to interact with the graphical elements of the calculator, like buttons and the entry widget. The event loop runs until the user closes the window or until the program is closed by some other means.

The conclusion

In conclusion, the tutorial provides a clear and detailed explanation of how to create a calculator using Python. It covers the basics of how to set up the calculator and includes step-by-step instructions for performing various mathematical operations, such as addition, subtraction, multiplication, and division. The code examples provided in the tutorial are easy to understand and can be easily adapted to suit your specific needs. Overall, the tutorial is a great resource for anyone who is new to Python programming and wants to learn how to create a basic calculator.

Was this helpful?
[4]