Mobile applications have become increasingly popular today, where technology plays a significant role in our lives. One such application is a unit converter app, which allows users to convert different units of measurement quickly and easily. If you’re interested in learning how to create a unit converter app for Android using Delphi For Python tools, then you’re in the right place. This tutorial will cover creating the UI, writing conversion logic, and packaging the app for Android devices. The result is a fully functional app that users can share. So let’s get started!
Table of Contents
Why Create a Unit Conversion App?
A unit conversion app can be a helpful tool for a wide range of day-to-day tasks that require converting between different units of measurement. For example, when cooking, a recipe may call for certain ingredients in metric units, but the user may be more familiar with using imperial units. In this case, a unit conversion app can quickly convert the measurements to the preferred unit system, ensuring the recipe is prepared accurately.
So, unit conversion apps make it easy to convert between different units of measurement. Instead of manually calculating conversions, users can simply input a value and select the desired unit of measurement. Moreover, unit conversion apps help ensure accuracy by eliminating the potential for human error in manual calculations.
A dedicated app can save time and increase efficiency for tasks involving frequent unit conversions, such as engineering or scientific calculations. Also, by creating your own unit conversion app, you can tailor it to your specific needs and preferences, including which units to include, the user interface, and any additional features
Why Create Python GUI Using Delphi For Python?
Delphi for Python is a package that allows Python developers to use Delphi components and libraries to create GUI applications. With Delphi for Python, Python developers can leverage the power of Delphi VCL and FMX frameworks to create native Windows applications or cross-platform applications, respectively. The package also includes Delphi4PythonExporter, which can export Python modules to Delphi DLLs.
PythonFMXBuilder is another tool that can be used to create cross-platform GUI applications using Python and Delphi FMX. It allows developers to build and deploy Python GUI applications to Windows, macOS, iOS, and Android platforms.
How to Create a Unit Converter Desktop App?
Before we start with the tutorial, let’s look at its prerequisites.
What Are the Requirements to Complete this Task?
The latest version of Python, PythonFMXBuilder, Delphi4PythonExporter, Delph CE, and any text editor or IDE (PyScripter is recommended) that supports Python are required for this tutorial.
We’ve got you covered if you don’t have these installed on your device. We recommend checking out this article, “Powerful Python GUI Project Setup” which will help you get started.
You can grab the code for this tutorial from our Git repository at: https://github.com/Embarcadero/PythonBlogExamples/tree/main/Unit_Conversion_App
How to Create a Form in Delphi?
Open Delphi CE and go create a blank application (File > New > Multi-Device Application > Blank Application > Ok
). This will open a new project for you with a blank form. We have named our project UnitConversionApp
.
To understand what each section of the above Delphi IDE means/represents, please go through the free eBook bundle we have developed. This eBook explains the ideology around Delphi Python EcoSystem, all Python GUI offerings, and much more.
Let’s start by giving our form a name. Right-click on the form and click on QuickEdit
. Here we will name our form Main
and display the title as Unit Conversion App
.
Next, let’s resize our form. Head to the object inspector, and in the properties tab, search for ClientHeight
and ClientWidth
. We will set them as 480
and 306
, respectively.
We will also rename the source file of our main form to MainForm.pas
to make it easy to keep track of.
This form will be the primary interface for our Unit Converter application, where users will choose the units to convert. We’ll add a label that greets users with the app’s title to make it more like a main screen. To do this, navigate to the standard palette and locate the TLabel
component. Afterward, simply drag and drop the component onto the form.
Now, let’s change the text style to display the title. We can easily do this using TextSettings
. So, select the Tlabel and head over to the Object Inspector
on the bottom-left corner of your screen. Here in the search bar, search for TextSettings
. Select Font
under it and click on the ...
to see options allowing you to change the label font, size, and style according to your needs.
Now rename the label’s text by right-clicking on that label and selecting Quick Edit
. It is good practice to follow an intuitive naming convention to name your components to make them easier to track. Here, we named our label as Title
with the text “Unit Conversion App.
”
We can change the form’s background color by navigating to the Object Inspector and selecting the form’s fill
property.
Finally, we need to add a few buttons that will help us navigate to other forms where we will be converting our Units. So head on over to the Palette and add a few TButton
components.
As you can see, we have added four buttons to our form named Length
, Temperature
, Time
, and Weight
. These buttons will help us navigate to different forms that will help us convert the relevant units.
Next, let’s change the font size and style of this button text to make the button text more prominent. Here we have to use the font style as Segoe UI and increase the size to 16pt. We also increased the size of the buttons and aligned the text to the Center
, the same as the Title
label above, so that the text appears symmetric.
Here is what our final MainForm
looks like:
Now that we’ve created our main screen, let’s add four new forms to help us with the unit conversions. To create our next form, right-click on UnitConversionApp.exe
and select Add New > Multi-Device Form
.
This will create our new form. We will rename this form as Length
and the source file as LengthForm.pas
.
Next, resize the form to the same specifications as our MainForm
to maintain consistency. Let’s also add a few labels and buttons to our form and make it more visually appealing.
Here is what our form looks like:
As you can see, we have also added a small Status
label indicated by the hyphen right above the Back and Convert buttons. We have also changed its color using TextSettings to help us display error messages based on wrong user inputs.
Now that our LengthForm
has the basic visual components let’s add a few components that will allow us to convert our lengths based on user input. Start by navigating to the Palette and searching for the TComboBox
component. We will add this to the form for the user to select the conversion unit. In addition to this, we will add a label under the Value
label to indicate the result of the conversion.
Finally, let’s add a TEdit
component that will help the user write the unit’s value to be converted. Here is what our final LengthForm
looks like:
Now that we know how to create a unit form, we can create similar forms for Temperature
, Time
, and Weights
. Here is what our final forms look like:
Now that our forms are ready, we need to add procedures to ensure our buttons work. So open up each form by double-clicking on the .fmx
file of each form.
Next, double-click each button to construct the Click
methods in the .pas
files of our forms.
To ensure that the methods are not lost when we export our forms in Python, add at least a single comment (//
)to each of the Click
methods.
How to Export this Delphi Project as a Python Script?
Now that our forms are ready, we can export our project as a Python script. Navigate to Tools > Export To Python > Export Current Entire Project
.
Next, give your application a title, select the Application Main Form as the MainForm
, and, finally, select the directory of choice. Click on Export to generate your files.
Because we have 5 forms for this project, Delphi will generate 6 Python scripts i.e., MainForm.py
, LengthForm.py
, TimeForm.py
, TemperatureForm.py
, WeightForm.py
, and UnitConversionApp.py
in your chosen directory. The form Python files contain the classes for the individual forms, and the UnitConversionApp
is used to launch our Delphi app.
Along with the Python files for each form, Delphi generates a .pyfmx
file for each .py
file in the same directory. These files contain all the form’s visual information.
Let’s take a look at the contents of UnitConversionApp.py
, which will run our application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from delphifmx import * from MainForm import Main def main(): Application.Initialize() Application.Title = 'UnitConversionApp' Application.MainForm = Main(Application) Application.MainForm.Show() Application.Run() Application.MainForm.Destroy() if __name__ == '__main__': main() |
Next, let’s take a look at MainForm.py
that will show us our main screen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import os from delphifmx import * class Main(Form): def __init__(self, owner): self.Title = None self.TemperatureFromButton = None self.LengthFormButton = None self.WeightFromButton = None self.TimeFormButton = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "MainForm.pyfmx")) def TemperatureFromButtonClick(self, Sender): pass def LengthFormButtonClick(self, Sender): pass def WeightFromButtonClick(self, Sender): pass def TimeFormButtonClick(self, Sender): pass |
Here are the contents for the rest of the forms.
LengthForm.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import os from delphifmx import * class Length(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "LengthForm.pyfmx")) def ConvertClick(self, Sender): pass def BackButtonClick(self, Sender): pass |
TemperatureForm.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import os from delphifmx import * class Temperature(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "TemperatueForm.pyfmx")) def ConvertClick(self, Sender): pass def BackButtonClick(self, Sender): pass |
TimeForm.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import os from delphifmx import * class Time(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "TimeForm.pyfmx")) def ConvertClick(self, Sender): pass def BackButtonClick(self, Sender): pass |
And finally WeightForm.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import os from delphifmx import * class Weight(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "WeightForm.pyfmx")) def ConvertClick(self, Sender): pass def BackButtonClick(self, Sender): pass |
How to Add Functionality to the App?
Now that our forms are ready, we can add functionality to our App.
For our MainForm
the only thing we need to do is link the relevant button to each of the forms. To do this, let’s import the conversion forms into our MainForm.py
:
1 2 3 4 5 6 |
# Additional imports from LengthForm import Length from TemperatueForm import Temperature from TimeForm import Time from WeightForm import Weight |
Next, navigate to the Click function for each form, create an instance of the form and assign it to a variable. We then display the new form using the show()
method. For example, let’s navigate to TemperatureFromButtonClick
, create an instance of TemperatureForm
, and assign it to a new variable self.TempForm
. We then use show()
to display our form. Here is what our TemperatureFromButtonClick
looks like:
1 2 3 4 |
def TemperatureFromButtonClick(self, Sender): self.TempForm = Temperature(self) self.TempForm.Show() |
We can replicate this for the other buttons. Here is what our final MainForm.py
file looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import os from delphifmx import * # Additional imports from LengthForm import Length from TemperatueForm import Temperature from TimeForm import Time from WeightForm import Weight class Main(Form): def __init__(self, owner): self.Title = None self.TemperatureFromButton = None self.LengthFormButton = None self.WeightFromButton = None self.TimeFormButton = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "MainForm.pyfmx")) def TemperatureFromButtonClick(self, Sender): self.TempForm = Temperature(self) self.TempForm.Show() def LengthFormButtonClick(self, Sender): self.LengthForm = Length(self) self.LengthForm.Show() def WeightFromButtonClick(self, Sender): self.WeightForm = Weight(self) self.WeightForm.Show() def TimeFormButtonClick(self, Sender): self.TimeForm = Time(self) self.TimeForm.Show() |
Now, let’s move our LengthForm
. First, let’s start by defining a dictionary in the __init__
function that stores the length conversions for each unit.
1 2 3 4 5 6 7 8 9 10 11 12 |
# Dictionary that gives us the relationship between units self.data = { "meter":{"meter":1, "kilometer":1/1000, "centimeter":100, "millimeter":1000, "yard":1.094, "foot":3.281, "inch":39.37, "mile":1/1609}, "kilometer":{"meter":1000, "kilometer":1, "centimeter":100000, "millimeter":1000000, "yard":1094, "foot":3281, "inch":39370, "mile":1.609}, "centimeter":{"meter":1/100, "kilometer":1/100000, "centimeter":1, "millimeter":10, "yard":1/91.44, "foot":1/30.48, "inch":1/2.54, "mile":1/160900}, "millimeter":{"meter":1/1000, "kilometer":1/1000000, "centimeter":1/10, "millimeter":1, "yard":1/914.4, "foot":1/304.8, "inch":1/25.4, "mile":1/1609000}, "yard":{"meter":1/1.094, "kilometer":1/1094, "centimeter":91.44, "millimeter":914.4, "yard":1, "foot":3, "inch":36, "mile":1/1760}, "foot":{"meter":1/3.281, "kilometer":1/3281, "centimeter":30.48, "millimeter":304.8, "yard":1/3, "foot":1, "inch":12, "mile":1/5280}, "inch":{"meter":1/39.37, "kilometer":1/39370, "centimeter":2.54, "millimeter":25.4, "yard":1/36, "foot":1/12, "inch":1, "mile":1/63360}, "mile":{"meter":1609, "kilometer":1.609, "centimeter":160900, "millimeter":1609000, "yard":1760, "foot":5280, "inch":63360, "mile":1} } |
Here we have defined the dictionary such that to convert from meter to kilometer, we use the meter key to get the nested dictionary and then access the kilometer conversion using that dictionary. Here we get the number 1/1000
, so multiplying any user value with this number will yield our converted result.
Next, let’s iterate over the dictionary and populate the combo boxes in our form.
1 2 3 4 5 |
# Load the currencies in key values of the self.data dictionary into the FromCurrency and ToCurrency combo boxes for key in self.data.keys(): self.FromUnit.Items.append(key) self.ToUnit.Items.append(key) |
Finally, we initialize the Status
label empty using the .Text
property of the labels. Here is what our final __init__
function looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "LengthForm.pyfmx")) # Addtional initializations # Dictionary that gives us the relationship between units self.data = { "meter":{"meter":1, "kilometer":1/1000, "centimeter":100, "millimeter":1000, "yard":1.094, "foot":3.281, "inch":39.37, "mile":1/1609}, "kilometer":{"meter":1000, "kilometer":1, "centimeter":100000, "millimeter":1000000, "yard":1094, "foot":3281, "inch":39370, "mile":1.609}, "centimeter":{"meter":1/100, "kilometer":1/100000, "centimeter":1, "millimeter":10, "yard":1/91.44, "foot":1/30.48, "inch":1/2.54, "mile":1/160900}, "millimeter":{"meter":1/1000, "kilometer":1/1000000, "centimeter":1/10, "millimeter":1, "yard":1/914.4, "foot":1/304.8, "inch":1/25.4, "mile":1/1609000}, "yard":{"meter":1/1.094, "kilometer":1/1094, "centimeter":91.44, "millimeter":914.4, "yard":1, "foot":3, "inch":36, "mile":1/1760}, "foot":{"meter":1/3.281, "kilometer":1/3281, "centimeter":30.48, "millimeter":304.8, "yard":1/3, "foot":1, "inch":12, "mile":1/5280}, "inch":{"meter":1/39.37, "kilometer":1/39370, "centimeter":2.54, "millimeter":25.4, "yard":1/36, "foot":1/12, "inch":1, "mile":1/63360}, "mile":{"meter":1609, "kilometer":1.609, "centimeter":160900, "millimeter":1609000, "yard":1760, "foot":5280, "inch":63360, "mile":1} } # Load the currencies in key values of the self.data dictionary into the FromCurrency and ToCurrency combo boxes for key in self.data.keys(): self.FromUnit.Items.append(key) self.ToUnit.Items.append(key) self.Status.Text = "" |
Next, let’s redefine the Back button to open up our new form. So in the BackButtonClick
method, use the show()
method to open up the MainForm
and then we will use the .Destroy()
method to destroy the current form, then .
Here is what our BackButtonClick
method looks like:
1 2 3 4 |
def BackButtonClick(self, Sender): Application.MainForm.Show() self.Destroy() |
Finally, lets define our ConvertClick
function that will make our conversion happen. First, start by checking whether the user has selected values in both combo boxes and added a value to be converted. Next, use the .Text
property to get the given
and to
units from the form. We also get the amountGiven
by the user in the edit box, and finally calculate the amount by simply multiplying the amountGiven
with the conversion rate from the dictionary:
1 2 3 4 5 6 |
if self.FromUnit.Selected!=None and self.ToUnit.Selected!=None and self.FromValue.Text!="": # Checking is all required fields filles given = self.FromUnit.Selected.Text to = self.ToUnit.Selected.Text amountGiven = int(self.FromValue.Text) amountCalculated = self.data[given][to] * amountGiven |
But before we can display our value, we add a check to ensure that the calculated value does not exceed 8 characters. If it does, we then convert it into scientific notation. We then reset the Status
and display our converted value on the label.
1 2 3 4 5 6 7 8 9 10 |
if self.FromUnit.Selected!=None and self.ToUnit.Selected!=None and self.FromValue.Text!="": # Checking is all required fields filles given = self.FromUnit.Selected.Text to = self.ToUnit.Selected.Text amountGiven = int(self.FromValue.Text) amountCalculated = self.data[given][to] * amountGiven if len(str(amountCalculated)) > 8: # If the value is longer than 8 digits then use scientific notation amountCalculated = '{:.3e}'.format(amountCalculated) self.ToValue.Text = amountCalculated self.Status.Text = "" # Reset status since conversion was successful (incase there was an alert earlier) |
Finally, if the user fails to fill in any required details we will display an error in the Status
label. Here is what our final ConvertClick
function looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def ConvertClick(self, Sender): if self.FromUnit.Selected!=None and self.ToUnit.Selected!=None and self.FromValue.Text!="": # Checking is all required fields filles given = self.FromUnit.Selected.Text to = self.ToUnit.Selected.Text amountGiven = int(self.FromValue.Text) amountCalculated = self.data[given][to] * amountGiven if len(str(amountCalculated)) > 8: # If the value is longer than 8 digits then use scientific notation amountCalculated = '{:.3e}'.format(amountCalculated) self.ToValue.Text = amountCalculated self.Status.Text = "" # Reset status since conversion was successful (incase there was an alert earlier) else: self.Status.Text = "Please fill all relevant inputs!" |
Following is the final LengthForm.py
file code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import os from delphifmx import * class Length(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "LengthForm.pyfmx")) # Addtional initializations # Dictionary that gives us the relationship between units self.data = { "meter":{"meter":1, "kilometer":1/1000, "centimeter":100, "millimeter":1000, "yard":1.094, "foot":3.281, "inch":39.37, "mile":1/1609}, "kilometer":{"meter":1000, "kilometer":1, "centimeter":100000, "millimeter":1000000, "yard":1094, "foot":3281, "inch":39370, "mile":1.609}, "centimeter":{"meter":1/100, "kilometer":1/100000, "centimeter":1, "millimeter":10, "yard":1/91.44, "foot":1/30.48, "inch":1/2.54, "mile":1/160900}, "millimeter":{"meter":1/1000, "kilometer":1/1000000, "centimeter":1/10, "millimeter":1, "yard":1/914.4, "foot":1/304.8, "inch":1/25.4, "mile":1/1609000}, "yard":{"meter":1/1.094, "kilometer":1/1094, "centimeter":91.44, "millimeter":914.4, "yard":1, "foot":3, "inch":36, "mile":1/1760}, "foot":{"meter":1/3.281, "kilometer":1/3281, "centimeter":30.48, "millimeter":304.8, "yard":1/3, "foot":1, "inch":12, "mile":1/5280}, "inch":{"meter":1/39.37, "kilometer":1/39370, "centimeter":2.54, "millimeter":25.4, "yard":1/36, "foot":1/12, "inch":1, "mile":1/63360}, "mile":{"meter":1609, "kilometer":1.609, "centimeter":160900, "millimeter":1609000, "yard":1760, "foot":5280, "inch":63360, "mile":1} } # Load the currencies in key values of the self.data dictionary into the FromCurrency and ToCurrency combo boxes for key in self.data.keys(): self.FromUnit.Items.append(key) self.ToUnit.Items.append(key) self.Status.Text = "" def ConvertClick(self, Sender): if self.FromUnit.Selected!=None and self.ToUnit.Selected!=None and self.FromValue.Text!="": # Checking is all required fields filles given = self.FromUnit.Selected.Text to = self.ToUnit.Selected.Text amountGiven = int(self.FromValue.Text) amountCalculated = self.data[given][to] * amountGiven if len(str(amountCalculated)) > 8: # If the value is longer than 8 digits then use scientific notation amountCalculated = '{:.3e}'.format(amountCalculated) self.ToValue.Text = amountCalculated self.Status.Text = "" # Reset status since conversion was successful (incase there was an alert earlier) else: self.Status.Text = "Please fill all relevant inputs!" def BackButtonClick(self, Sender): Application.MainForm.Show() self.Destroy() |
We can follow the same process to add functionalities to our WeightForm
, and TimeForm
. Here is that our final WeightForm.py
looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
import os from delphifmx import * class Weight(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "WeightForm.pyfmx")) # Addtional initializations # Dictionary that gives us the relationship between units self.data = { "kilogram":{"kilogram":1, "gram":1000, "milligram":1000000, "metric ton":1/1000, "pound":2.205, "ounce":35.274}, "gram":{"kilogram":1/1000, "gram":1, "milligram":1000, "metric ton":1/1000000, "pound":1/453.6, "ounce":1/28.35}, "milligram":{"kilogram":1/1000000, "gram":1/1000, "milligram":1, "metric ton":1/1000000000, "pound":1/453600, "ounce":1/28350}, "metric ton":{"kilogram":1000, "gram":1000000, "milligram":1000000000, "metric ton":1, "pound":2205, "ounce":35270}, "pound":{"kilogram":1/2.205, "gram":453.6, "milligram":453600, "metric ton":2205, "pound":1, "ounce":16}, "ounce":{"kilogram":1/35.274, "gram":28.35, "milligram":28350, "metric ton":1/35270, "pound":1/16, "ounce":1} } # Load the currencies in key values of the self.data dictionary into the FromCurrency and ToCurrency combo boxes for key in self.data.keys(): self.FromUnit.Items.append(key) self.ToUnit.Items.append(key) self.Status.Text = "" def ConvertClick(self, Sender): if self.FromUnit.Selected!=None and self.ToUnit.Selected!=None and self.FromValue.Text!="": # Checking is all required fields filles given = self.FromUnit.Selected.Text to = self.ToUnit.Selected.Text amountGiven = int(self.FromValue.Text) amountCalculated = self.data[given][to] * amountGiven if len(str(amountCalculated)) > 8: # If the value is longer than 8 digits then use scientific notation amountCalculated = '{:.3e}'.format(amountCalculated) self.ToValue.Text = amountCalculated self.Status.Text = "" # Reset status since conversion was successful (incase there was an alert earlier) else: self.Status.Text = "Please fill all relevant inputs!" def BackButtonClick(self, Sender): Application.MainForm.Show() self.Destroy() |
And here is what our final TimeForm.py
looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import os from delphifmx import * class Time(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "TimeForm.pyfmx")) # Addtional initializations # Dictionary that gives us the relationship between units self.data = { "second":{"second":1, "millisecond":1000, "minute":1/60, "hour":1/3600, "day":1/86400, "week":1/6084800, "month":1/2628000, "year":1/31540000}, "millisecond":{"second":1/1000, "millisecond":1, "minute":1/60000, "hour":1/3600000, "day":1/86400000, "week":1/6084800000, "month":1/2628000000, "year":1/31540000000}, "minute":{"second":60, "millisecond":60000, "minute":1, "hour":1/60, "day":1/1440, "week":1/10080, "month":1/43800, "year":1/525600}, "hour":{"second":3600, "millisecond":3600000, "minute":60, "hour":1, "day":1/24, "week":1/168, "month":1/730, "year":1/8760}, "day":{"second":86400, "millisecond":86400000, "minute":1440, "hour":24, "day":1, "week":1/7, "month":1/30.417, "year":1/365}, "week":{"second":604800, "millisecond":604800000, "minute":10080, "hour":168, "day":7, "week":1, "month":1/4.345, "year":1/52.143}, "month":{"second":2628000, "millisecond":2628000000, "minute":43800, "hour":730, "day":30.417, "week":4.345, "month":1, "year":1/12}, "year":{"second":31540000, "millisecond":31540000000, "minute":525600, "hour":8760, "day":365, "week":52.143, "month":12, "year":1} } # Load the currencies in key values of the self.data dictionary into the FromCurrency and ToCurrency combo boxes for key in self.data.keys(): self.FromUnit.Items.append(key) self.ToUnit.Items.append(key) self.Status.Text = "" def ConvertClick(self, Sender): if self.FromUnit.Selected!=None and self.ToUnit.Selected!=None and self.FromValue.Text!="": # Checking is all required fields filles given = self.FromUnit.Selected.Text to = self.ToUnit.Selected.Text amountGiven = int(self.FromValue.Text) amountCalculated = self.data[given][to] * amountGiven if len(str(amountCalculated)) > 8: # If the value is longer than 8 digits then use scientific notation amountCalculated = '{:.3e}'.format(amountCalculated) self.ToValue.Text = amountCalculated self.Status.Text = "" # Reset status since conversion was successful (incase there was an alert earlier) else: self.Status.Text = "Please fill all relevant inputs!" def BackButtonClick(self, Sender): Application.MainForm.Show() self.Destroy() |
However, it is important to note that unlike our other forms, the temperature conversions require us to use formulae that involve operations other than division and multiplication. So let’s make changes to our TemperatureForm.py
.
What Changes Have to be Made in the Temperature Form?
Start by opening TemperatureForm.py
and define the __init__
functions and BackClick
button like our other forms.
Next, we will need to redefine our dictionary to store our functions. So navigate to the __init__
function and create a lambda
function for each unit conversion.
1 2 3 4 5 6 |
self.data = { "celsius":{"celsius":lambda a: a, "kelvin":lambda a: a+273.15, "fahrenheit":lambda a: a*(9/5)+32}, "kelvin":{"celsius":lambda a: a-273.15, "kelvin":lambda a: a, "fahrenheit":lambda a: (a-273.15)*(9/5)+32}, "fahrenheit":{"celsius":lambda a: (a-32)*(5/9), "kelvin":lambda a: (a-32)*(5/9)+273.15, "fahrenheit":lambda a: a} } |
Let’s take a look at an example, to convert from Celsius to Kelvin, we need to multiply our Celsius value by 9/5
then add 32
to it. We thus create a lambda
function that takes in a single value and converts it into Celsius as lambda a: a * (9.5) + 32
. We can replicate the same for other conversions. Therefore, to convert a value, we will use the dictionary to get the relevant function and then pass in the value to be converted. For example, self.data["celsius"
]["fahrenheit"
](5
) will convert 5
degree Celsius to Fahrenheit.
Next, we will change the ConvertClick
function to pass values to the lambda
functions to calculate the relevant amounts. Here is what our final TemperatureForm.py
looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import os from delphifmx import * class Temperature(Form): def __init__(self, owner): self.FromValue = None self.UnitFromLabel = None self.ValueFromLabel = None self.Title = None self.FromLabel = None self.ToLabel = None self.Convert = None self.FromUnit = None self.ToUnit = None self.ToValue = None self.UnitToLabel = None self.ValueToLabel = None self.BackButton = None self.Status = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "TemperatueForm.pyfmx")) # Addtional initializations # Dictionary that gives us the relationship between units using lamda functions self.data = { "celsius":{"celsius":lambda a: a, "kelvin":lambda a: a+273.15, "fahrenheit":lambda a: a*(9/5)+32}, "kelvin":{"celsius":lambda a: a-273.15, "kelvin":lambda a: a, "fahrenheit":lambda a: (a-273.15)*(9/5)+32}, "fahrenheit":{"celsius":lambda a: (a-32)*(5/9), "kelvin":lambda a: (a-32)*(5/9)+273.15, "fahrenheit":lambda a: a} } # Load the currencies in key values of the self.data dictionary into the FromCurrency and ToCurrency combo boxes for key in self.data.keys(): self.FromUnit.Items.append(key) self.ToUnit.Items.append(key) self.Status.Text = "" def ConvertClick(self, Sender): if self.FromUnit.Selected!=None and self.ToUnit.Selected!=None and self.FromValue.Text!="": given = self.FromUnit.Selected.Text to = self.ToUnit.Selected.Text amountGiven = int(self.FromValue.Text) amountCalculated = self.data[given][to](amountGiven) # using the lambda if len(str(amountCalculated)) > 8: # if the value is longer than 8 digits then use scientific notation amountCalculated = '{:.3e}'.format(amountCalculated) self.ToValue.Text = amountCalculated self.Status.Text = "" # reset status since conversion was successful (incase there was an alert earlier) else: self.Status.Text = "Please fill all relevant inputs!" def BackButtonClick(self, Sender): Application.MainForm.Show() self.Destroy() |
What Results Does Testing This Desktop App Give?
Now that code is ready, we can run our app by executing UnitConversionApp.py
. Here is what MainForm
looks like:
We can even navigate to the different forms by clicking each button. Here is what our LengthForm
looks like:
Here is what our TimeForm
:
Here is our TemperatureForm
:
And finally here is what our WeightForm
looks like:
How To Turn This Into an Android App?
Now that our Unit Conversion App is running, let’s convert this into an Android application.
So, open up FMXBuilder and click on Project > New project
on the toolbar. Enter the name of the project that you want to build here. Here we define our project as UnitConversionApp
.
Next, add your Python and .pyfmx
files by right-clicking on the App and selecting Add file.
Before we can add our UnitConversionApp.py
file, we need to change some code to allow us to run our project in Android. Let’s create a new file named UnitConversionApp_Android.py
and paste the contents of UnitConversionApp.py
.
Next, open up the UnitConversionApp_Android.py
file and start making some important changes. First off, Android applications are initialized automatically by Delphi applications. Because the program will be initialized automatically, we don’t need to initialize it or set a title manually. The Application.MainForm
doesn’t need to be initialized either but just needs a variable. Lastly, like initialization, we don’t need to launch or destroy the program because Android handles both tasks.
Here is what our UnitConversionApp_Android.py
file looks like:
1 2 3 4 5 6 7 8 9 10 11 12 |
from delphifmx import * from MainForm import Main def main(): Application.MainForm = Main(Application) Application.MainForm.Show() if __name__ == '__main__': main() |
Save the file with the code changes you’ve just made. Now, right-click on
file and set it to the main file.
_Android.pyUnitConversionApp
PythonFMX Builder for Android can generate an android application package file (.apk
) or install the app directly onto your Android device. To directly install the app onto your mobile device, you’ll first need to connect your Android phone to your device and enable USB debugging on your phone. Afterward, simply click on the reload button located in the top right corner. If your device is properly connected, it will appear in the drop-down menu.
Finally, select your device and click on Run Project
:
This will install the app directly on your Android phone and run it.
Does the Android App Work As We Expect?
Upon opening the app on your Android device, you will see the main menu:
Now, if we select the length option, we will be taken to the LengthForm
where we can select our desired units and do successful conversions:
We can even check whether the resultant conversion is given in scientific notation when required.
Let’s also check that if we had not filled in the required details and pressed the Convert
button, do we get an error:
We can even check that our TemperatureForm
, TimeForm
, and WeightForm
work as expected:
Are You Ready To Create Your Own Unit Converter App?
Congratulations on completing this tutorial on creating an Android unit converter app using Python GUI! We hope this tutorial has given you insights into how Python can be used to develop mobile apps and simplify the creation of graphical user interfaces. With the help of Delphi for Python Exporter and PythonFMXBuilder, you can easily deploy Python scripts on Android devices and create visually appealing UIs in Delphi. The Delphi Community Edition is a great tool with a streamlined IDE, code editor, integrated debugger, and hundreds of visual components.
What Are Some FAQs Related to this Tutorial?
What is Embarcadero?
Embarcadero technologies are created for the best-skilled programmers worldwide who build and support the most important applications. Because we are the developer champion and can help them create scalable, secure enterprise apps more quickly than with any other solution on the market, our clients select Embarcadero. Ninety of the Fortune 100 and a vibrant community of more than three million customers worldwide have relied on Embarcadero’s award-winning products for more than 30 years.
What GUI library is used to create the app’s user interface?
The app’s user interface is created using the delphifmx library and other tools such as Delphi CE, PythonFMXBuilder, and Delphi4PythonExporter.
Is it possible to create an Android app using Python?
Yes, it is possible to create an Android app using Python.
Do I need any prior programming experience to follow this tutorial?
While some programming experience would be helpful, this tutorial is designed to be beginner-friendly and walks you through the process step-by-step.