This one was driving me up the wall – I’m working on (or rather trying to work on) a FireMonkey application, one form in which loads a tree view dynamically. Since each node concerns a certain sort of data object, I wrote a small custom descendant of TTreeViewItem to add a property of the relevant type and a couple of helper methods. So far so good. After that I did a bit of refactoring, separating out the descendant into a custom base class and two child classes, and adding bits and bobs. Following this I reran the program… and found the tree view text had disappeared. Argh!!! Progressively commenting out the new code got me nowhere, until tracing back my step of splitting out the custom descendant into three got me the answer – the now-grandchildren of TTreeViewItem were style-less!
If you check out the FMX source, you’ll see that the default style lookup for an object is its class name, minus the leading ‘T’ and with a ‘style’ prefix. This can be customised if you wish – in the form designer, it’s the StyleLookup property that gets set when you choose ‘Custom Style’ from the designer’s popup menu. If you customise it with the name of a style element that is not part of the active style (e.g., you used the ‘Custom Style’ command in the designer, only to delete the generated style book afterwards), then the default lookup based on the class name is used; and if that doesn’t name a valid style element, then the default style lookup for the parent class is used. If that still results in failure, then the control is just left style-less, and therefore empty at runtime unless the appearance is hardcoded (which is bad form for a FMX control). In my view, if you’re going to start walking up the class hierarchy for a valid style lookup, then you might as well continue to walk until you find one. In fact, more strongly, it surely breaks basic OOP principles for the act of merely splitting out a base class from a class to have the effect of altering (and in this case, breaking) its behaviour.
Regardless, my next step was to assign the StyleLookup property to ‘treeviewitemstyle’ in my custom base class’ constructor. This fixed the original problem of text not appearing… but caused a new issue of check boxes showing even though the tree view’s ShowCheckboxes property remained False! Tracing into the code, I found assigning the StyleLookup property causes a control to actually load its style right there and then; in my custom class’ case, this meant the style was being loaded before the control’s parentage had been established, which was undoubtedly too early (while the default value of the ShowCheckboxes property is False, the default visibility of the check box element of a tree view item style is True). Nonetheless, the fix was easy: assign not the StyleLookup property, but the FStyleLookup protected field:
type TMyNodeBase = class(TTreeViewItem) public constructor Create(const AOwner: TComponent; const AData: TDataObject); reintroduce; end; TMyRedNode = class(TMyNodeBase) //... end; TMyBlueNode = class(TMyNodeBase) //... end; constructor TMyNodeBase.Create(const AOwner: TComponent; const AData: TDataObject); begin inherited Create(AOwner); FStyleLookup := 'treeviewitemstyle'; //prevent descendants being style-less FData := AData; end;