Data Bindings are a way of keeping a component’s properties in sync with the underlying data with minimal effort.
A Data Binding associates a property of a component with a single Python expression. This association is defined in a single place - the Properties Panel:
All bound properties for a particular Form are updated whenever:
self.refresh_data_bindings()is called, or
self.init_components(**properties)is called, or
self.itemfor the Form is set.
If you use “Write back”, the values are written back:
- when relevant input events such as
lost_focusare fired by the component
See Two-way Data Bindings below for more details on “Write back”.
To create a Data Binding, click “
+ Add” in the Data Bindings section of the Properties Panel.
You’ll see something like this (assuming
self.item is a dictionary with
address in it):
If you were to choose
'name', then the
text property of this Button would be bound to
With this Data Binding set up, every time
self.refresh_data_bindings() is called, the
text property would get set to
Data Bindings can only access attributes and methods of
self - they cannot access variables in the global scope.
If you want to modify variables in the global scope, you can create methods on
self that return the global variable
you want to use (such methods are often called ‘accessor methods’ or ‘getters’).
As well as properties that relate to UI such as
spacing_above, components have a special property meant
specifically for storing data of any kind -
This can be set to anything - a Data Tables row, a custom dictionary, any Python object. (Remember, in Python “everything is an object.”)
It’s useful for Data Bindings because it’s a way for components to hold data and pass it around.
self.item of a Form changes, all Data Bindings for that Form are updated.
For input components such as
DatePicker, Data Bindings can be two-way.
You need to tick the “Write back” checkbox to set this up:
This means that when a user changes the property, the Python object it’s bound to will be updated as part of the processing of relevant events.
For example, binding the
text property of a
self.item['name'] means that
will be set to whatever the user has entered in the
TextBox, right before the
events are processed.
Write Back does not trigger when
self.refresh_data_bindings() is called, when
self.init_components(**properties) is called
or when the
self.item for the Form is set. It only triggers when events such as
pressed_enter fire on the
To see why Data Bindings save effort, consider an app where the user enters a number
N into a TextBox,
presses a button, and a times table is displayed for that number (
N is 4 in the image):
If you want your times tables to go up to 12 x
N, you can create 12 Labels and bind each of their
1 * self.item['N'] (for the first one) through
12 * self.item['N'] (for the last one).
N, you can bind the
text of the TextBox to
self.item['N'] with ‘Write back’ enabled.
Then to update the Labels, just run
self.refresh_data_bindings() when the Button is clicked.
def button_1_click(self, **event_args): """This method is called when the button is clicked""" self.refresh_data_bindings()
This means your click handler is just one line.
Without Data Bindings, this method would need 12 very similar lines like
self.text_box_3.text = 3 * self.item['N'].
Crucially, the definition of what the Labels mean is kept with the Label, rather than being defined in the Button’s click handler.
On top of that, if you want to have multiple ways of updating the Labels, you don’t have to reproduce the definitions
of what the Labels mean. Let’s say you wanted to make the times tables change when somebody sends an SMS to the app.
Instead of copying all those
self.text_box_3.text = 3 * self.item['N'] lines into the SMS handler, you can
just make it do
self.refresh_data_bindings() and everything will be updated appropriately.
Data Bindings are a function of Forms in the visual designer. If you want to accomplish the same functionality in code, you can use event handlers.
refreshing_data_bindings event handler will be called whenever Data Bindings are refreshed. You can write your own code here, and it will run at the same time as any Data Bindings specified in the designer. For example, the following is equivalent to a Data Binding to a text box:
def form_refreshing_data_bindings(self, **event_args): """This method is called when refreshing_data_bindings is called""" self.text_box_1.text = self.item['my_text']
If you want to write back data when the text box changes, you can do this with its
change event handler:
def text_box_1_change(self, **event_args): """This method is called when the text in this text box is edited""" self.item['my_text'] = self.text_box_1.text