Styles Performance in XE3

Posted by on in Blogs
As you I hope know, styles in FireMonkey are common FireMonkey objects, working on the level of a single control. The behavior and design of the control is defined by simple objects or graphical primitives (rectangle, ellipse, text), animation, effects and event triggers. But there is still a question. Is it effective to use such a number of objects and instantiate and load them right in the process of application startup? Yes, you’re right.

Thus in the new version of FireMonkey we modified the mechanism of loading/unloading of a style for controls. Now all the processes are dynamic. After the form has been loaded, all the controls are “empty”, i.e. they have no style (as a number of objects) loaded. But at the first call of the control rendering method, the style is loaded into the control. Only visible controls are loaded with the style, rather than all of them. Basically, it’s not amount of the controls. So a FireMonkey 2.0 application is loaded and starts considerably faster.

For example, if we have a TTabControl control with some tabs on the form, the styles are loaded only for an active tab. The same is true for TListBox, when the style is loaded only for visible items. While ListBox is being scrolled, the other items will be filled with the style.

Well, the startup and style loading became faster, sometimes dramatically. One can notice as we work with the application on and on we will have more and more objects, and the time for object processing will increase. In order to remove this situation, we unload the item style, if it becames invisible (we’ve scrolled it off or switched TabControl to a different tab). Thus, the performance of controls has increased. Take a list as an example and say, only visible elements have styles loaded.

During dynamic loading/unloading the style the following methods are called pairwise in class TStyledControl:

procedure ApplyStyle; virtual;
procedure FreeStyle; virtual;

If you want to load some data in objects of a style during runtime, you can use the event OnApplyStyleLookup. This event happens anytime, when the style is loaded into a control. Even if the style is unloaded from it, the repeated loading will cause the method to be called. So the data loading is guaranteed. Otherwise when using the style data via StylesData for invisible control, the data are lost, as the style has not been loaded yet.

The example of correct loading of the data in ListBox:

Item := TListBoxItem.Create(nil);
Item.OnApplyStyleLookup := DoApplyStyleLookupFromFile;
Item.Parent := ListBox1;
procedure TForm1.DoApplyStyleLookup(Sender: TObject);
Item: TListBoxItem;
Item := TListBoxItem(Sender);
Item.StylesData['resolution'] := '1024x768 px'; // set size
Item.StylesData['depth'] := '32 bit';
Item.StylesData['visible'] := true; // set Checkbox value
Item.StylesData['visible'] := TValue.From(DoVisibleChange); // set OnChange value
Item.StylesData['info'] := TValue.From(DoInfoClick); // set OnClick value

In addition, the new version of FireMonkey has a mechanism, allowing the controls to manage the travel across the tree of child elements. The TConrol class now has two interesting methods:

function GetFirstVisibleObjectIndex: Integer; virtual;
function GetLastVisibleObjectIndex: Integer; virtual;

Having overridden these methods, one can manage the tree for the child methods. For example, there is no need to check the entire tree when handling the event from the mouse or draw all the elements, if some of them are not visible. The mechanisms is used in the controls as TListBox, TTreeView. Therefore, the performance of TListBox is always the same for the different number of items, as only visible are processed.


Check out more tips and tricks in this development video: