Skip to content

Quick start guide

Jim McKeeth edited this page May 30, 2022 · 3 revisions

Quick Start Guide 1: Testing the Install

Check out the free eBook and styles bundle with 29 custom styles and 50 pages of content. Download the free eBook and Python styles bundle.


After installing delphifmx library using pip, let's enter the Python REPL to understand a few essential things. Python has a predefined dir() function that lists available names in the local scope. So, before importing anything, let's check the available names using the dir() function.

>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

Now let's import the installed delphifmx module to validate its installation and check for the output of the dir() function:

>>> import delphifmx
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'delphifmx']

In the above output list, we have delphifmx as part of the available names in the local scope. In this case, if we need to use any classes or functions available in the delphifmx module, we should use a dot (.) operator after it. Now let's import everything using * from the delphifmx library and check for the available classes, functions, objects, constants, and so forth.

>>> from delphifmx import *
>>> dir()[0:49]
['Abort', 'Action', 'ActionList', 'AdapterListView', 'AniIndicator', 'AppearanceListView', 'Application', 'Arc', 'ArcDial', 'BaseBindScopeComponent', 'BaseLinkingBindSource', 'BaseObjectBindSource', 'BaseValueRange', 'BasicAction', 'BasicBindComponent', 'BindComponentDelegate', 'BindingsList', 'BitmapTrackBar', 'Bounds', 'Button', 'CalloutPanel', 'CalloutRectangle', 'CameraComponent', 'CaretRectangle', 'CheckBox', 'CheckColumn', 'Circle', 'Collection', 'ColorBox', 'ColorButton', 'ColorComboBox', 'ColorListBox', 'ColorPanel', 'ColorPicker', 'ColorQuad', 'Column', 'ComboBox', 'ComboColorBox', 'ComboEdit', 'ComboEditBase', 'CommonCustomForm', 'Component', 'ContainedAction', 'ContainedActionList', 'ContainedBindComponent', 'Control', 'ControlSize', 'CornerButton', 'CreateComponent']

To avoid an enormous list of names, we checked for the first 50 elements only using dir()[0:49]. Let's check for a few available classes, functions, and objects:

>>> CreateComponent
<built-in function CreateComponent>
>>> Button
<class 'Button'>
>>> Form
<class 'Form'>
>>> Application
<Delphi object of type TApplication at 55BA8E7E6240>

We need to create an object instance for other classes like Button and Form. There are many other classes and functions, but only a single object of Application instance, which is an existing singleton instance, ready for use with the dot (.) operator. It is the source of all GUI applications that we create.

Let's now create a simple GUI application. The code for it is:

from delphifmx import *

Application.Initialize()
Application.Title = "Hello DelphiFMX"
window = Form(Application)
Application.MainForm = window
window.SetProps(Caption = "Welcome")
window.Show()
Application.Run() # This is the GUI interaction main loop
window.Destroy()

Using the above code, we just created an empty GUI app. Please save the above code and run it to see the following output:

image

Let's explore and understand the functionality of the code.

from delphifmx import *

Application.Initialize()
Application.Title = "Hello DelphiFMX"

At first, we imported everything from delphifmx. Then, we initialized the application and set a title for it. Later, we will create the GUI application window using the following code:

window = Form(Application)
Application.MainForm = window
window.SetProps(Caption = "Welcome")

We can refer to all the classes that are part of the import as components. The Form is special and different as it creates the GUI window containing all other components. We instantiated the Form with the Application as the owner parameter in the above code. The Application object will handle the Life cycle of our GUI application. DelphiFMX has the capability to create multiple forms/windows for a single application. Using the line Application.MainForm = window, we’re setting the form with window object as the main window. All the components, including Form, have a method setProps() to set their properties. Here we've set Caption that appears on the title bar of the Form window.

Let's look at the following few lines of the code:

window.Show()
Application.Run() # This is the GUI interaction main loop
window.Destroy()

As we created the application and set its properties, we will show it on the screen using the window.show() code snippet. Application.Run() starts the GUI interaction loop between the GUI and the user of the GUI application. When we close the GUI application, window.Destroy() takes care of not crashing it.

Quick Start Guide 2: Hello, World

We discussed the most basic ideas about the delphifmx library in the first, simplest quick start. We created an empty GUI application without displaying anything on the Form/GUI window. Also, we did not use an object-oriented approach to create the GUI application. So let's expand on those ideas, and develop an object-oriented version displaying a text message. First, let's look at the code. You might be able to guess what the below code does if you understood the basics from the first guide.

from delphifmx import *

class GUIApp(Form):
    def __init__(self, owner):
        self.SetProps(Caption = "Welcome")
        self.lblHello = Label(self)
        self.lblHello.SetProps(
            Parent=self,
            Text="DelphiFMX4Python")

def main():
    Application.Initialize()
    Application.Title = "Hello DelphiFMX"
    app = GUIApp(Application)
    Application.MainForm = app
    app.Show()
    Application.Run()
    app.Destroy()

main()

As you save the above code in a Python file and run it, you'll get the following GUI window with a text message as follows:

image

In the main function, let’s look at the following line of code:

app = GUIApp(Application)

Instead of instantiating the Form directly, we instantiate a class - GUIApp that extends the Form class. Let's investigate the code in the GUIApp class:

class GUIApp(Form):
    def __init__(self, owner):
        self.SetProps(Caption = "Welcome")
        self.lblHello = Label(self)
        self.lblHello.SetProps(
            Parent=self,
            Text="DelphiFMX4Python")

As we instantiated the GUIApp using app = GUIApp(Application), the owner argument was assigned with the Application object. After that, Form uses the owner in its initialization and creates an empty Form/GUI window. This owner variable can have any other name as it's just a placeholder of the Application object. In the first line of the GUIApp initialization, we've set the Caption property of the Form. Then we instantiated the Label component/class with the instance/object of the Form as its parameter using the self.lblHello = Label(self) code snippet. We use Label to display any single-line text messages. Every component along with Form will have a parent and is set using the Parent property. The parent holds the child component in it. In our code, we're setting Label's parent as Form using Parent=self. So now the Form object (app) holds the Label object (lblHello). Next, the text of the Label is set using its Text property. So the Form/GUI window gets populated by a text message:- DelphiFMX4Python. We used all the default positions and sizes of the Form and Label and didn't handle any events in this guide. However, we will implement them and introduce some new components in the following advanced quick start guide.

Quick Start Guide 3: TODO Task App

Here we will create a TODO task application to understand some components of GUI applications.

Let's take a look at the code to achieve that:

from delphifmx import *

class TodoApp(Form):
    def __init__(self, Owner):
        self.Caption = "A TODO GUI Application"
        self.SetBounds(100, 100, 700, 500)
        
        self.task_lbl = Label(self)
        self.task_lbl.SetProps(Parent=self, Text="Enter your TODO task")
        self.task_lbl.SetBounds(10, 10, 150, 25)

        self.task_text_box = Edit(self)
        self.task_text_box.SetProps(Parent=self)
        self.task_text_box.SetBounds(10, 30, 250, 20)

        self.add_task_btn = Button(self)
        self.add_task_btn.Parent = self
        self.add_task_btn.SetBounds(150, 75, 100, 30)
        self.add_task_btn.Text = "Add Task"
        self.add_task_btn.OnClick = self.__add_task_on_click

        self.del_task_btn = Button(self)
        self.del_task_btn.SetProps(Parent=self, Text="Delete Task")
        self.del_task_btn.SetBounds(150, 120, 100, 30)
        self.del_task_btn.OnClick = self.__del_task_on_click

        self.list_of_tasks = ListBox(self)
        self.list_of_tasks.Parent = self
        self.list_of_tasks.SetBounds(300, 50, 300, 350)

        def __add_task_on_click(self, Sender):
            self.list_of_tasks.Items.Add(self.task_text_box.Text)
            self.task_text_box.Text = ""

        def __del_task_on_click(self, Sender):
            self.list_of_tasks.Items.Delete(0)

def main():
    Application.Initialize()
    Application.Title = "TODO App"
    app = TodoApp(Application)
    Application.MainForm = app
    app.Show()
    Application.Run()
    app.Destroy()

main()

As you save and run the above code on Windows, you should get the following GUI as a result:

image

In the above "Hello, World" guide, we ran the code on Linux. We ran the current TODO Task app guide on Windows and you can see the app’s look and feel are adapted to Windows-style apps. Let's get to the details of what our code does behind the scenes. First, take a look at the main() function:

def main():
    Application.Initialize()
    Application.Title = "TODO App"
    app = TodoApp(Application)
    Application.MainForm = app
    app.Show()
    Application.Run()
    app.Destroy()

main()

Above, we instantiated the TodoApp class with Application as the Owner. As we instantiate the GUI using app = TodoApp(Application), the following code runs:

class TodoApp(Form):
    def __init__(self, Owner):
        self.Caption = "A TODO GUI Application"
        self.SetBounds(100, 100, 700, 500)

We inherit the Form class from the delphifmx library to create our GUI. In DelphiFMX, all the GUIs are treated as forms. The name of the GUI pop-up window is set using the Caption property/attribute. The line self.SetBounds(100, 100, 700, 500) is used to set:

  • the GUI window's origin position comparable to screen's origin position = (100, 100);
  • width of the GUI window = 700 pixels; and
  • height of the GUI window = 500 pixels.

The upper-left corner of the screen is treated as the (0, 0) coordinate, with the left side as positive width and down as positive height. We can visualize it as shown below:

image

Let's look at the following few lines of code:

        self.task_lbl = Label(self)
        self.task_lbl.SetProps(Parent=self, Text="Enter your TODO task")
        self.task_lbl.SetBounds(10, 10, 150, 25)

        self.task_text_box = Edit(self)
        self.task_text_box.SetProps(Parent=self)
        self.task_text_box.SetBounds(10, 30, 250, 20)

The first three lines of code above will create the text - "Enter your TODO task" that you see on the GUI app. It does so by instantiating the Label class of the delphifmx library. Every component (Label here) has a SetProps() method to set its properties. Every component will have a scope that is set using its Parent property/attribute, which is set to self here. The Text property sets the string of the text label. Similar to the Form/GUI app, every component needs to be placed inside the Form/GUI using the SetBounds() method. For components, the top-left corner of their parent (GUI window here) is considered as the origin - (0, 0). The next 3 lines of code create the edit box using the Edit class. We can also set the properties/attributes directly without using the SetProps() method, like we did here using the code self.task_text_box.Parent = self. With the Form/GUI window as the parent of the Edit box, we can visualize its position and size as shown in the below figure. The height of the Edit box is automatically set to the default value.

image

Let's look at the next few lines of code:

        self.add_task_btn = Button(self)
        self.add_task_btn.Parent = self
        self.add_task_btn.SetBounds(150, 75, 100, 30)
        self.add_task_btn.Text = "Add Task"
        self.add_task_btn.OnClick = self.__add_task_on_click

        self.del_task_btn = Button(self)
        self.del_task_btn.SetProps(Parent=self, Text="Delete Task")
        self.del_task_btn.SetBounds(150, 120, 100, 30)
        self.del_task_btn.OnClick = self.__del_task_on_click

The above lines of code create two buttons, Add Task and Delete Task, using the Button instance of the delphifmx package. For the buttons, one extra thing you'll find is an event handling using self.add_task_btn.OnClick = self.__add_task_on_click and self.del_task_btn.OnClick = self.__del_task_on_click for Add Task and Delete Task buttons, respectively. We will look at this in just a while.

Let's look at the next few lines of code:

        self.list_of_tasks = ListBox(self)
        self.list_of_tasks.Parent = self
        self.list_of_tasks.SetBounds(300, 50, 300, 350)

In the above lines of code, we created a list box using the ListBox instance. Let's now look at the event-handling methods for the Add Task and Delete Task buttons:

        def __add_task_on_click(self, Sender):
            self.list_of_tasks.Items.Add(self.task_text_box.Text)
            self.task_text_box.Text = ""
            
        def __del_task_on_click(self, Sender):
            self.list_of_tasks.Items.Delete(0)

For all the events along with OnClick, the Form automatically sends a single argument (Sender here, but this can be any name). We can add a task to the list box by typing anything into the text box and pressing the Add Task button. DelphiFMX library-based GUIs support tab controls too, where you can also navigate from one component to another using the tab key. So you can press Tab on the keyboard, and when the Add Task button gets highlighted, you can press Enter/Return to fire its event. We add text from the text box to the list box using the Add() method under Items under ListBox instance. We delete the earlier added events on a first-come, first-serve basis by pressing the Delete Task button.


Check out the free eBook and styles bundle with 29 custom styles and 50 pages of content. Download the free eBook and Python styles bundle.