Introduction

Hello there, Arsey here, a Python speaker, this is my first blog and I'll guide you to
 build this simple calculator app using Flet. I'm so excited to share this with you
 and here we go.

In today’s digital era, creating cross-platform applications is a necessity. With a
 plethora of frameworks available, selecting the right one can be challenging. One
 such framework is Flet, a Python library that enables developers to effortlessly
 build web, desktop, and mobile apps using Flutter, but for Python.

In this blog, we’ll explore how to create a basic calculator app using Flet,
 illustrating how simple and efficient this framework can be.

WHY FLET?

When I started programming, my goal was to build mobile applications. Without a
 clear guide, I chose Python as my first language. It was fun to learn but as I gained
 more experience, I realized that Python is traditionally not suitable for app
 development, it’s more commonly used for data analysis and related tasks.

Now learning Android development with Kotlin for native development and Dart
with Flutter for cross-platform, my goal comes a step closer thanks to this library
 flet.

This realization was disheartening until I discovered frameworks like Kivy, Tkinter,
 Flet, etc., that allow Python to be used for building apps. Unlike Kivy or Tkinter,
 these frameworks are good but need a lot of customization to develop a good
-looking mobile application that works well for Android and iOS. And that’s where
 flet shines.

Flet is a Python framework inspired by Flutter, a popular UI toolkit by Google. The
results you can achieve with flet are impressive, and I’m excited to share more.

WHAT is flet?

Flet is a python package that allows developers to build user interfaces directly
 using Flutter’s UI toolkit.

Flet’s primary advantage is that it combines Python’s simplicity and Flutter’s rich
UI capabilities, enabling rapid development of cross-platform application without
 requiring extensive front-end experience.

Flet is a batteries-included library, so no need for SDKs and can be easily extended
 with Flutter’s SDK.

Note: It's beneficial to have a basic understanding of some front-end concepts,
 such as the box model, layout structures like Flexbox and Grid, and positioning.
 While you can still follow along without this knowledge, I highly recommend
familiarizing yourself with these concepts.
Now, with that out of the way, let’s dive into building our calculator!


SETTING UP THE ENVIRONMENT

Before diving into coding, ensure you have Python installed on your machine.
 Then, follow these steps to set up your environment for Flet.
   
   1.  Install Flet: You can install Flet using pip. You can just open your terminal or
 command prompt, type in this command, and run it.

pip install flet

Create a new Python file: after a successful install, open up your favorite code
editor like VS-Code, Pycharm, etc.) and create a new Python file, name it
 main.py or what you best prefer. Feeling excited? I bet you are! Let’s first test
 our installation worked with the most beloved phrase in the developer
 community, “Hello World!”

In our Python file, type in this code

import flet as ft

def main(page: ft.Page):
    page.add(ft.Text(value="Hello, World!"))

ft.app(target=main)

Run the code to see if everything works. If you see “Hello, World!” displayed,
 you’re ready to move on to building our calculator.

output












CREATING THE LAYOUT
In this section, we’ll be focusing on the structure of the calculator; here we’ll use
 the column widget to stack our display and buttons. The display will show the
 current input, and the buttons will allow user interaction. That’s odd I never
noticed that UI can mean User Interface to User Interaction.

Now write the code below as follows.

from flet import (
    app, Page, Container, Column, Row,
    TextField, colors, border_radius, ElevatedButton, TextAlign, TextStyle
)


def main(page: Page):
    page.title = "Calculator"
    result = TextField(
        hint_text='0', text_size=20,
        color='white', text_align=TextAlign.RIGHT,
        hint_style=TextStyle(
            color=colors.WHITE, size=20
        ),
        read_only=True
    )

    def button_click(e):
        pass

    button_row0 = Row(
        [
            ElevatedButton(text='C',  on_click=button_click),
            ElevatedButton(text='^',  on_click=button_click),
            ElevatedButton(text='%',  on_click=button_click),
            ElevatedButton(text='/',  on_click=button_click),
        ]
    )
    button_row1 = Row(
        [
            ElevatedButton(text='7',  on_click=button_click),
            ElevatedButton(text='8',  on_click=button_click),
            ElevatedButton(text='9',  on_click=button_click),
            ElevatedButton(text='*',  on_click=button_click),
        ]
    )
    button_row2 = Row(
        [
            ElevatedButton(text='4',  on_click=button_click),
            ElevatedButton(text='5',  on_click=button_click),
            ElevatedButton(text='6',  on_click=button_click),
            ElevatedButton(text='-',  on_click=button_click),
        ]
    )
    button_row3 = Row(
        [
            ElevatedButton(text='1',  on_click=button_click),
            ElevatedButton(text='2',  on_click=button_click),
            ElevatedButton(text='3',  on_click=button_click),
            ElevatedButton(text='+',  on_click=button_click),
        ]
    )
    button_row4 = Row(
        [
            ElevatedButton(text='0',  on_click=button_click),
            ElevatedButton(text='.',  on_click=button_click),
            ElevatedButton(text='=',  on_click=button_click),
        ]
    )
    container = Container(
        width=350, padding=20,
        bgcolor=colors. BLACK,
        content=Column(
            [
                result,
                button_row0, button_row1, button_row2,
                button_row3, button_row4
            ]
        )
    )
    page.add(container)


if __name__ == '__main__':
    app(target=main)

After running the above code, you’ll see the output of the calculator layout, it
might not look good but that’s okay! We’ll enhance it by adding some spacing,
 radius on the container, and theme to make our calculator look more polished
Output

CODE EXPLANATION

Okay, we have built the layout, right? Well, still I know some of you there didn’t
 understand what we’ve just done here. Just sit, no questions, and let me explain
what the code does.

In the first line, we import our controls. Flet controls are widgets used to lay out
 our application into a meaningful User Interface. But here we have imported. app,
 Page, Container, Column, Row,
TextField, colors, border_radius, ElevatedButton, TextAlign, TextStyle. 

Even though some of them are not entire widgets, like app, colors,
 border_radius, TextAlign,
and TextStyle. These are classes and methods
 that provide us with extra functionalities of our application, for example
The app, allows us to launch our app in a standalone mode targeting to the main
 instance of our application.* colors* allow us to style our controls that support the
 color and bgcolor attribute without us struggling to define their names and
 border_radius allows us to curve the corners of our containers.

We now give the title to our page, with the page.title attribute, the title on the
 title bar of our app. 

In lines 9-16 is the result control with its required attributes, though it has many,
 we are gonna use these ones for this project, as you can see we have add a place
 holder of 0, giving it a size of 20, color to white, align text to right, and the read
-only to true so we don’t allow external of soft keyboards to work directly in it.

Line 18 we defined our event handler, button_click this is where we will apply the
 logic to function our application, eventually making it a working calculator, but for
 now I just used a pass statement as a placeholder.

From lines 21 – 59, we defined our rows using the Row Widget, the row widget is
a control that displays its children in a horizontal array or layout from left to right,
similar to the linear layout in Android development, or inline elements in CSS the
 row controls works in the same way as them, it lays out controls in a horizontal
axis or linearly.

Then the ElevatedButton_will represent buttons on the calculator’s UI, but notice we
have given it the text and _onclick attributes, the text defines the data that will be
 displayed on the results when clicked using the onclick attribute that will call for
 the function button_click to handle events accordingly.

We have the container, the container is a control that will allow us to decorate a
 control with background color, spacing, applying borders and border radius, and
position it with padding, margin, and alignment.

A container follows the box-model concept like the one for CSS as in the figure
 below,

The column control, like the Row control, this one displays its children in a vertical
array or layout from top to bottom, this will allow us to vertically lay our buttons
 in the right order.

Now after defining our UI elements, we need to display them to our application
and then call it. We do that by using the page.add() method which allows us to
 add and build our UI logically.

Then we have to call our app in the stand-alone mode, and that’s what lines 74-75
 accomplished.

Adding functionality

Update your button click function to match this code below.

def button_click(e):
        if e.control.text == "=":
            try:
                result.value = str(eval(result.value))
            except Exception:
                result.value = "Error"
        elif e.control.text == "C":
            result.value = ""
        # elif e.control.text == "^":
        # logic for powers
        # pass
        else:
            result.value += e.control.text
        result.update()Clearing the display: when the user clicks the ‘C’ button,
 the calculator’s input is cleared. The result is set to an empty string (“”),
 and the display is reset to 0. This effectively clears the display making the calculator ready for a new input.
 Talk but a fresh number meal.Clearing the display: when the user clicks the ‘C’ button, 
the calculator’s input is cleared. The result is set to an empty string (“”), 
and the display is reset to 0. This effectively clears the display making the 
calculator ready for a new input. Talk but a fresh number meal.

CODE EXPLANATION

Okay, what does this code do under the hood; the button_click function
 is designed to handle various button click events within our calculator app.
Save to apply our current changes then run the calculator and see the results.
Here is a breakdown of how the code works

 1 . Retrieving the button text: when a button is clicked, the function retrieves the
      button’s text (e.g., ‘1’, ‘2’, ‘+’, ‘-‘, ‘C’, ‘=’) through the e.control.text. this tells
     the functions which button the user has interacted with

2  . Clearing the display: when the user clicks the ‘C’ button, the calculator’s input is
       cleared. The result is set to an empty string (“”), and the display is reset to 0.
      This effectively clears the display making the calculator ready for a new input.
      Talk but a fresh number meal.

3 . Evaluating expressions: if the user clicks the “=” button, the calculator needs to
     evaluate the current mathematical expression, here we used the 
str() and

     eval() functions, and the function houses the eval() function so that
     the result is directly converted into a string and theeval() function will
     compute the result of the expression, then displayed as a string to our
     calculator’s display. Or else if the expression is invalid, an exception is caught,
      and the “Error” message will be displayed instead

4  . For the rest of the buttons like numbers and operators: the function
      will append the button’s text to the display (which is initially “0” or when cleared),
       it replaces “0” with the button value, otherwise it adds button value to the end of
      the display.

5  . After processing the button click, the page is updated  via page.update()
 method call to refresh the UI and show the updated input or result on the
 calculator's display. So every time you click the button and see the value on the
 display or a result, this is what the page.update() does. 

NOTE: The eval() function is a quick way to evaluate expression but it can be
 risky with un-trusted input because it executes/evaluates any Python code. In a
 more secure app, you’d use a safer method for evaluating mathematical
 expressions.

Exercise: test your knowledge, of how would you handle the exponent ‘^’
 expression so that if the user clicks the exponent button it returns the required
output. For example, if the user inputs 2^2 the output will be 4, 5^5=25, and
 3^4=81. You get the idea. 

Let me know how you approached to this problem in the comments, okay, all
done, let’s continue 

Improving our UI

Previously the user interface did not look that catchy and awesome, so let’s
improve it, and update the buttons to match the following code.

button_row0 = Row(
    [
        ElevatedButton(text='C', expand=1, on_click=button_click,
                       bgcolor=colors.RED_ACCENT, color=colors.WHITE),
        ElevatedButton(text='^', expand=1, on_click=button_click,
                       bgcolor=colors.BLUE_ACCENT_100,
                       color=colors.RED_900
                       ),
        ElevatedButton(text='%', expand=1, on_click=button_click,
                       bgcolor=colors.BLUE_ACCENT_100,
                       color=colors.RED_900
                       ),
        ElevatedButton(text='/', expand=1, on_click=button_click,
                       bgcolor=colors.BLUE_ACCENT_100,
                       color=colors.RED_900
                       ),
    ]
)
button_row1 = Row(
    [
        ElevatedButton(text='7', expand=1, on_click=button_click),
        ElevatedButton(text='8', expand=1, on_click=button_click),
        ElevatedButton(text='9', expand=1, on_click=button_click),
        ElevatedButton(text='*', expand=1, on_click=button_click,
                       bgcolor=colors.BLUE_ACCENT_100,
                       color=colors.RED_900
                       ),
    ]
)
button_row2 = Row(
    [
        ElevatedButton(text='4', expand=1, on_click=button_click),
        ElevatedButton(text='5', expand=1, on_click=button_click),
        ElevatedButton(text='6', expand=1, on_click=button_click),
        ElevatedButton(text='-', expand=1, on_click=button_click, 
                       bgcolor=colors.BLUE_ACCENT_100
                       ),
    ]
)
button_row3 = Row(
    [
        ElevatedButton(text='1', expand=1, on_click=button_click),
        ElevatedButton(text='2', expand=1, on_click=button_click),
        ElevatedButton(text='3', expand=1, on_click=button_click),
        ElevatedButton(text='+', expand=1, on_click=button_click, 
                       bgcolor=colors.BLUE_ACCENT_100,
                       color=colors.RED_900),
    ]
)
button_row4 = Row(
    [
        ElevatedButton(text='0', expand=1, on_click=button_click),
        ElevatedButton(text='.', expand=1, on_click=button_click),
        ElevatedButton(
            text='=', expand=2, on_click=button_click,
            bgcolor=colors.GREEN_ACCENT, color=colors.AMBER
        ),
    ]
)

What have we changed exactly, hmm!

For the buttons, we could have used the width attribute but that won’t work as we
 want it would break the UI, feel free to test it. 
But we have this expand attribute which allows only a Boolean and an int data
 type value.

For the normal buttons like the operators, numbers, and the clear button
 we expanded them to 1, and for the equals button, we expanded it by 2.

Now what does the expand attribute do, the expand attribute allows a control to
 fill the available space in a given container.

So the buttons with expand 1 will have an equal size of width and for the equals
 button it will expand 2, or in simple terms span two buttons or will equal two
 buttons in width.

Notice that we have added colors and background colors to some of our buttons
 to make them stand out from the numbers buttons.  
Understand, great.

In the container add these attributes, just after the padding attribute to make it
 look more appealing and user friendly.

border_radius=border_radius.all(20),

Now, you have a fully functional calculator built with Flet! Feel free to customize it
to your liking or add more features. You can even package it as a standalone APK,
 AAB to launch on Google Play Store or Apple App Store

Here is the full code,

from flet import (
    app, Page, Container, Column, Row,
    TextField, colors, border_radius, ElevatedButton, TextAlign, TextStyle
)
from flet_core import ThemeMode


def main(page: Page):
    page.title = "Calculator"
    page.theme_mode = ThemeMode.DARK
    page.horizontal_alignment = page.vertical_alignment = 'center'
    result = TextField(
        hint_text='0', text_size=20,
        color='white', text_align=TextAlign.RIGHT,
        hint_style=TextStyle(
            color=colors.WHITE, size=20
        ),
        read_only=True
    )

    def button_click(e):
        if e.control.text == "=":
            try:
                result.value = str(eval(result.value))
            except Exception:
                result.value = "Error"
        elif e.control.text == "C":
            result.value = ""
        # elif e.control.text == "^":
        # logic for powers
        # pass
        else:
            result.value += e.control.text
        result.update()

    button_row0 = Row(
        [
            ElevatedButton(text='C', expand=1, on_click=button_click,
                           bgcolor=colors.RED_ACCENT, color=colors.WHITE),
            ElevatedButton(text='^', expand=1, on_click=button_click,
                           bgcolor=colors.BLUE_ACCENT_100,
                           color=colors.RED_900
                           ),
            ElevatedButton(text='%', expand=1, on_click=button_click,
                           bgcolor=colors.BLUE_ACCENT_100,
                           color=colors.RED_900
                           ),
            ElevatedButton(text='/', expand=1, on_click=button_click,
                           bgcolor=colors.BLUE_ACCENT_100,
                           color=colors.RED_900
                           ),
        ]
    )
    button_row1 = Row(
        [
            ElevatedButton(text='7', expand=1, on_click=button_click),
            ElevatedButton(text='8', expand=1, on_click=button_click),
            ElevatedButton(text='9', expand=1, on_click=button_click),
            ElevatedButton(text='*', expand=1, on_click=button_click,
                           bgcolor=colors.BLUE_ACCENT_100,
                           color=colors.RED_900
                           ),
        ]
    )
    button_row2 = Row(
        [
            ElevatedButton(text='4', expand=1, on_click=button_click),
            ElevatedButton(text='5', expand=1, on_click=button_click),
            ElevatedButton(text='6', expand=1, on_click=button_click),
            ElevatedButton(text='-', expand=1, on_click=button_click, 
                           bgcolor=colors.BLUE_ACCENT_100
                           ),
        ]
    )
    button_row3 = Row(
        [
            ElevatedButton(text='1', expand=1, on_click=button_click),
            ElevatedButton(text='2', expand=1, on_click=button_click),
            ElevatedButton(text='3', expand=1, on_click=button_click),
            ElevatedButton(text='+', expand=1, on_click=button_click, 
                           bgcolor=colors.BLUE_ACCENT_100,
                           color=colors.RED_900),
        ]
    )
    button_row4 = Row(
        [
            ElevatedButton(text='0', expand=1, on_click=button_click),
            ElevatedButton(text='.', expand=1, on_click=button_click),
            ElevatedButton(
                text='=', expand=2, on_click=button_click,
                bgcolor=colors.GREEN_ACCENT, color=colors.AMBER
            ),
        ]
    )
    container = Container(
        width=350, padding=20,
        bgcolor=colors.BLACK, border_radius=border_radius.all(20),
        content=Column(
            [
                result,
                button_row0, button_row1, button_row2,
                button_row3, button_row4
            ]
        )
    )
    page.add(container)


if __name__ == '__main__':
    app(target=main)

Conclusion

Building this calculator has been a fun experience for me and a learning
 experience for you, and I hope you enjoyed it too.

Let me know what kind of project you’d like to build using this framework or any
 other like PyQt, Kivy, or Tkinter. I’d be glad to make a tutorial on it. Or even web
 design and development tutorials, also are allowed.

Feel free to ask questions, I’ll do my best to answer them.
If you've read this far, thank you—I appreciate it!