-
Notifications
You must be signed in to change notification settings - Fork 57
Quick start guide
Check out the free eBook and styles bundle with 29 custom styles and 50 pages of content.
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:
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.
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:
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.
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:
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:
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.
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.
Embarcadero Python-Dev Team