Posts from October 2012

MonkeyStylern Build 8 - XE3 support

MonkeyStyler Build 8 is now available and includes support for Delphi, C++ Builder and RAD Studio XE3 editions. The new edition comes with two executables, one for XE2 and the other for XE3.

New features include:
‘File/Read Only’ menu item to make files read only within MonkeyStyler. Useful when you are have a style file you are deriving styles from and don’t want to accidentally make changes. (Select the menu item again to turn off the read-only status.
‘File/Open From’ opens a style file from those distributed by Embarcadero (i.e. if does a File/Open with the appropriate directory location pre-loaded. This gives a quick way to open build in styles without trawling through the directory structure. Files are loaded as read-only.
‘File/Open System Style’ (XE3 edition only) opens any of the XE3/FM2 system styles (Win7, Win8, Lion or Lion2x). This gives a quick way to derive style elements from the built in styles. Styles are opened as read-only.

Full changelist
Added: Option to make files read only.
Added: File/Open From… menu item to load from Delphi etc built in files. (Files are opened as read only).
Fixed: PropEditorGrid: Issue with properties that don’t have editors not being editable including booleans.
Part-fixed: Slightly changed the way the Control Viewer works with animations to work better with TSubImage in XE3.
Added: Support for XE3 editions of Delphi, C++ Builder and RAD Studio.
Added (XE3): File/Open System Style menu option to load the Win7, Win8, Lion and Lion2x styles from resources.

ApplyStyle and FreeStyle in FireMonkey

If you’re writing custom controls for FireMonkey you’re probably overriding ApplyStyle with something like this:

procedure TWidget.ApplyStyle;
var 
TTFMXObject;
begin
    inherited
;
    
:= FindStyleResource('text');
    if 
T is TText then
        FText 
:= TText(T);
end

And so you should be. That’s entirely correct practice. You look for a component of the style and cache it for later re-use within your component.

procedure TWidget.SetText(const ValueString);
begin
    
if FText <> nil then
        FText
.Text := Value;
end

But as I was updating MonkeyStyler to run under XE3/FM2 I was getting some really obscure errors from my custom grid cells. The cached components would occasionally be junk, as though they had been free-ed behind my back. The errors always occured in the final cell in a row and I at first assumed there was some really odd off by one bug in FM2.

After much investigation I noticed that ApplyStyle was being called on cells which had long been created. But why would ApplyStyle be called more than once on a component?

It turns out that FM2 is being more conservative with resources and freeing style objects which are no longer needed to save memory. If a component disappears from view the library will call TStyleControl.Disappear which in turn calls the virtual TStyleControl.FreeStyle. I’ll admit I had’t even noticed these methods before.

The correct behaviour for any component which caches style resources in it’s ApplyStyle method is, therefore, to override FreeStyle and release them:

procedure TWidget.FreeStyle;
begin
    inherited
;
    
FText := nil;
end

Once I added that to MonkeyStyler’s custom cells all ran smoothly again.

Enjoy.