Automating a Windows Application¶
In some cases, we can automate Windows applications through element properties, as an alternative to computer vision.
This can be a useful alternative when we don't want to worry about resolution issues. We can simply interact with the application structure through the attributes of elements and windows.
This tutorial will guide you through the process of creating a simple automation that interacts with the elements of a Windows application.
Creating a New Project¶
The first step is to create a project for a desktop automation, you can follow the same steps defined in the previous section.
See how to create a Desktop Bot project.
Target Application and Spy Tools¶
For this simple example, we are going to use the standard Windows notepad.
To help us inspect this application, we are going to use the Accessibility Insights for Windows spy tool.
See more details about the spy tools usage.
Interacting with the Application¶
Connecting¶
With the project open, let's insert the first step in the bot.py
file, which is to establish the connection with the target application.
from botcity.core import DesktopBot, Backend
...
def main():
bot = DesktopBot()
# Application path
app_path = "notepad.exe"
# Launching the app
bot.execute(app_path)
# Connecting to the application using 'path' selector
bot.connect_to_app(backend=Backend.UIA, path=app_path)
...
With the application open, we can use the spy tool to see some information about the elements.
Finding Windows and Elements¶
With the app connected, we can now use the reference from the main window and collect the element referring to the text editor, for example.
from botcity.core import DesktopBot, Backend
...
def main():
bot = DesktopBot()
# Application path
app_path = "notepad.exe"
# Launching the app
bot.execute(app_path)
# Connecting to the application using 'path' selector
bot.connect_to_app(backend=Backend.UIA, path=app_path)
# Getting the notepad main window context using 'title_re' selector
main_window = bot.find_app_window(title_re="Untitled - Notepad")
# Getting the edit text area using the element 'title'
# We were able to view this property through the spy tool
edit = bot.find_app_element(from_parent_window=main_window, title="Text Editor")
...
Note that we used the title
property that we got from the spy tool. You can basically use any information that appears to filter a certain element.
Tip
Another way to inspect the application's control elements is to use
the print_control_identifiers
method. After opening the dialog box and
assigning it to a variable, the print_control_identifiers
method should print all
available controls. See more details about this
here.
Performing Actions¶
With the element found, we can perform the operations. As this element is of type Edit
, we can insert a text content.
from botcity.core import DesktopBot, Backend
...
def main():
bot = DesktopBot()
# Application path
app_path = "notepad.exe"
# Launching the app
bot.execute(app_path)
# Connecting to the application using 'path' selector
bot.connect_to_app(backend=Backend.UIA, path=app_path)
# Getting the notepad main window context using 'title_re' selector
main_window = bot.find_app_window(title_re="Untitled - Notepad")
# Getting the edit text area using the element 'title'
# We were able to view this property through the spy tool
edit = bot.find_app_element(from_parent_window=main_window, title="Text Editor")
# Typing some text
edit.type_keys("Hello! Welcome to BotCity!", with_spaces=True)
...
Info
See more details about the methods available for each different type of element at this link.
Running the Bot¶
Just the code above would be enough for us to start notepad and insert a text content.
We have established a connection with the application and are performing operations in the context of a specific element.
Running the code, the final result will look like this:
Accessing other elements in Notepad¶
With the same approach as above, using the control_type
and title
property, let's access other notepad elements.
Accesing menu_select
¶
We'll start by accessing the Page Setup option from the File menu, through the menu_select
method.
# Acessing option Page Setup of File Menu
main_window.menu_select("File -> Page Setup")
...
Using select
to choose an option on the box of selection¶
We will interact with the Size element, as we see below:
To select the paper size, let's map the control_type
and title
of the size
element, thats we can select them via the select
method.
This time we will use another approach to get the property of the element, the print_control_identifiers
, as we see below:
# Priting the control identifiers from the "Page Setup" window.
main_window.print_control_identifiers()
...
Where we can see the title
and control_type
of element, which will be used below, as parameters of find_app_element
method.
# Finding element to select page size
size = bot.find_app_element(from_parent_window=main_window, control_type="ComboBox",
title="Size:")
# Selecting page type
size.select("A5")
...
Using invoke
to choose an the radio button¶
Here, we will use invoke
to select the Landscape radio button.
Still using controls identifiers.
Let's get the title
and control_type
of the Landscape element to find it below:
# Finding element to select radio button "Landscape"
orientation = bot.find_app_element(from_parent_window=main_window,
control_type="RadioButton", title="Landscape")
# Method `click` is an alias of `invoke`
orientation.invoke()
# Finding element to click on button "OK"
btn_ok = bot.find_app_element(from_parent_window=main_window, title="OK")
# Clicking on button
btn_ok.click()
...
Info
In this case, it was not possible to use the methods click
, and click_input
to select
the radio button, because they only have control over elements with property
control_type="Button"
.
Info
invoke
uses the so called InvokePattern
that represents a default action for the
control. When using Application(backend="uia"), the click
method is an alias of
invoke
, where the InvokePattern action brings the window to the foreground, allowing
interaction with the element.
After the above actions, the page configuration looked like this:
Using type_keys
and click
to save the notepad in the file explorer.¶
To finish, we will access the save as option in the file menu.
# Acessing Menu Save As
main_window.menu_select("File -> Save As...")
...
This action will open the file explorer window, as we see below:
Thus, we will define a name for the file, in this case it will be tutorial.txt
, and we will click on the save button, through the click
method.
# Finding element to type the name of file
file_name = bot.find_app_element(from_parent_window=main_window, class_name="Edit",
title="File name:")
# Typing the file name
file_name.type_keys("tutorial.txt")
# Finding element to clicks on button save
btn_save = bot.find_app_element(from_parent_window=main_window, class_name="Button",
title="Save")
# Clicking on button save
btn_save.click()
...
Complete Code¶
from botcity.core import DesktopBot, Backend
...
def main():
bot = DesktopBot()
# Application path
app_path = "notepad.exe"
# Launching the app
bot.execute(app_path)
# Connecting to the application using 'path' selector
bot.connect_to_app(backend=Backend.UIA, path=app_path)
# Getting the notepad main window context using 'title_re' selector
main_window = bot.find_app_window(title_re="Untitled - Notepad")
# Getting the edit text area using the element 'title'
# We were able to view this property through the spy tool
edit = bot.find_app_element(from_parent_window=main_window, title="Text Editor")
# Typing some text
edit.type_keys("Hello! Welcome to BotCity!", with_spaces=True)
# Acessing option Page Setup of File Menu
main_window.menu_select("File -> Page Setup")
# Finding element to select page size
size = bot.find_app_element(from_parent_window=main_window, class_name="ComboBox",
title="Size:")
# Selecting page type
size.select("A5")
# Finding element to select radio button "Landscape"
orientation = bot.find_app_element(from_parent_window=main_window,
control_type="RadioButton", title="Landscape")
# Method click() is an alias of invoke()
orientation.invoke()
# Finding element to click on button "OK"
btn_ok = bot.find_app_element(from_parent_window=main_window, title="OK")
# Clicking on button
btn_ok.click()
# Acessing option Save As of file Menu
main_window.menu_select("File -> Save As...")
# Finding element to type the name of file
name_file = bot.find_app_element(from_parent_window=main_window, class_name="Edit",
title="File name:")
# Typing the file name
name_file.type_keys("tutorial.txt")
# Finding element to clicks on button save
btn_save = bot.find_app_element(from_parent_window=main_window, class_name="Button",
title="Save")
# Clicking on button save
btn_save.click()
...
Important
Some applications may be more difficult to inspect and find information about elements.
Use the spy tools as a reference to determine if this is the best alternative for your automation.
Conclusion¶
Under this tutorial you learned:
-
How to use a spy tool to inspect a Windows application.
-
How to connect to an application and view its attributes and properties.
-
How to interact with an element that has been found.