Have an amazing solution built in RAD Studio? Let us know. Looking for discounts? Visit our Special Offers page!

FireMonkey Styles for Blinking Button

Author: Eusebio M40205

The problem

appeared when discussing “Scalability of enterprise DBMS-targeted systems” (in English on massive demand in comments) with Dmitriy Kouzmenko, Russian expert in InterBase since its origin. Then this occasional topic called more interest, so now I have to give some light to the this. The initial idea was how to make a user press “backup db” button. Or how to force or even pester him/her into doing this. Quite an appropriate variant is to create “blinking button”.

The ergonomics

Before we start our tour into technical valley of using FireMonkey Styles, let’s speak about some concept. The visual component a-la “blinking button” is not very often to see in user interface, so not being too creative let’s make some analysis.

Usually some traditional interface waits for an action by a user and then repsonds as beginning to execute some task. So it’s quite ok, when the user does something and that’s a trigger for some procedure.

Sometimes the interface needs to notify the user of something. We do use this assynchnotous interaction when doing multi-thread programming. Basically we start child thread and then it indicates (remember? Synchronize) that….

  • mission accomplished

  • mission failed

  • don’t worry, I’m doing something

If first two items are typical to show the results of some hidden operation, then the third type of indication is used to distract the user from sad thought: “oh, no! I’m hanging again!”. But really this is not big deal of informing the user of the excact figures (for example, in %). In most cases operations executed are non-linear, and 75% doesn’t denote we are ¾ ready. Moreover, intuitively we feel the closer to the end the higher risk of failure.

Of course, if you fully control the algorithm you can calculate the %, but it’s not critical. And in some cases it’s good to find better metaphor, especially, with FireMonkey. Look at TProgressBar (C:UsersPublicDocumentsRAD Studio9.0SamplesFireMonkeyControlsDemo). Main bar indicates the status and the “secondary” light is travelling along the (green) bar to relax the user when waiting too long even for next “growth“ of the main status indicator.

Instead of blinking

All the said above is rather trivial. Since long ago we could use from ProgresBar/StatusBar, avi-gif-like animation (deletion in Explorer), animated cursor up (sandglass) to complex multi-thread operation status metaphor (see, for example, multi-thread download indicator progress in FlashGet). But we need not passive, but active or compelling effect from a control.

One should note, that in Windows 7 a taskbar button also allows locating some progress indication in itself (try massive copying in Explorer and watch it). After Embarcadero had released Delphi 2010 we all could do the same, and Andreano Lanusse instructed us how to do this then. But let’s think rather of universal metaphors, or unique ones, because we should do all things in multi-platform manner.

TryIcon provides more “imperative”, and it’s blinking draws attention and calls the user to understand by clicking it, what is hidden behind and what was a reason of the show. But once again, this metaphor is good for Windows, but let’s think of the current and future variety of platforms, supported by FireMonkey.

I believe, the “blinking button” is quite good approach for constant and annoying reminder. The point is how can we do this with little handcoding and according to the spirit of FireMonkey.

Constructing the style

My intention is to make “button-the-pest” with FM Styles, rather than some typical programming. If you’re going to be rather smooth, replay the webinar on styles with Eugene Kryukov. And now “blinking” is a very good test drive for FireMonkey on unexpected landscape.

Add two buttons (TButton) to the main single form of a new FireMonkey HD application. Fist button will be our “blinker”, the other will start the show.

In order to change the button style from “normal and calm” to “nervous and ticking”, pick the patient (Button1) and right-mouse-click on it. In the list in pop-up menu select “Edit Custom Sytle”. Now all the other buttons on the form (Button2 and more) have the style “by default”, while Button1 is visually different. Then we’ll see the style designer.

I’m now showing some part of the designer window, which demonstrates the structure of the button. The designer itself is rather new, but the way of using is very familiar, as we’re going to do this with ObjectInspector.

We can see some “animations” (TAnimation), but it doesn’t mean something will move to and fro. Once I tried to explain the “abstract” functionality of animation in FireMonkey. Now we see TColorAnimation, which will change some colors, and we need only ParentProperty, Start, Stop and Trigger to understand (but “understand” is too much for this). Just to see.

When a user drives a cursor across the button, this switches the animation on. The color doesn’t change instantly, and no place to guess how long it will take place. Look at Duration property. And for “blinking” effect we need to loop the color changing (Loop property), set AutoReverse to true and, may be, make the colors brighter.

As simple as that

The first TColorAnimation is fired by the trigger “IsMouseOver=true” (see the corresponding property in ObjectInspector). The second one – by “IsMouseOver=false”. We’ll do them that way: when the cursor is over, the button will stop blinking. I’ll set Start and Stop properties to Lawngreen. If you hate spring grass, feel free not to follow me at this point.

Then let’s align the second animation, which is more important. When the cursor leaves the button (sluggish and indecisive user) without pressing it, the button should continue blinking. That’s the core of all the buzz. Set the Start property to #FFEFEFEF (copy it from Stop property), and change Stop property to the most aggressive color (Red, for example). Then, please, loop and auto-reverse the animation by the Loop and AutoReverse properties (no surprise? Ok, who’s said he needed huge documentation to start using FireMonkey?)

Now we can press Apply and Close button in the style designer, then save and run the project. You’ll see the form with two buttons, if you let your mouse cursor walk on Button1, it will first become green, and then start showing the alarm.

Technological prototype

Let’s see C:UsersPublicDocumentsRAD Studio9.0SamplesFireMonkeyControlsDemo. This time we’re not going to analyze “the ergonomics”, but “the source code”. TProgressBar is not blinking, but we can see “self-inducing” animation without triggering (as some external activity by a user).
Now we know, the similar visual component exists (=we can also do the same). There are no principle technological obstacles, so it’s time to act:

  • in the form select Button1, right-click, and then “Edit Custom Style…”

  • open the Button1Style1 structure as shown below

  • find in the tool palette TColorAnimation component

  • pick it, drag it, drop it on the appropriate TRectangle

You needn’t follow this particular red line exactly when dragging. You’re free use different path.

After adding the third animation to the custom button sytle the structure will be as shown:

Then for your convinience, please, find the set of properties of this new-born third animation:

Comment 1. What format is preferable for you personally? Youtube videos or rich texts with screen-shots? Please, post your choice in comments.

Comment 2. The very old-school drag-n-dropping method was demonstrated only to make the demo maximally reproducible. I’ve already done this 3 times faster by copy-pasting the form text (right click in the form, View As Text, as for style-making this is more productive).

We are now one step to target. We need to be able to start “blinking”. But first repeat the theory:

  • animation is very natural when used in styles, but the most common is color animation;

  • style even for simple component can contain many objects-animations, applied to different graphical primitives inside the style structure;

  • we recommend to use many animations not simultaneously, but in sequence; timelining them with different triggers (MouseOver=true, MouseOver=false) not to interfere;

  • animation effects are fired by some trigger, so even “self-inducing” animation is controlled by this mechanism.

This very paragraph might be the only non-trivial idea in this post. We’re selecting the new animation and setting their trigger as IsVisible=true. When pressing Button2 we react as

procedure TForm1.Button2Click(Sender: TObject); begin Button1.StartTriggerAnimation(Button1, ‘IsVisible=true’); end;

Comment 3. Please, don’t try the obvious, but ineffectual property Enabled. It won’t work. It works only for animation effects, created and aligned in the designer for FM forms, not styles. For styling  FireMonkey comonents we should use triggers.

Done now calm

Let’s summarize. We replaced our “by default” style of Button1 and created our custom one. It was automatically set in property StyleLookup of the button. If you want to cancel our custome style and back up the “default” one, it’s easy:  Button1.StyleLookup := ”. The created custome style is stored in the form text (look at fmx-file or “View as Text”). In the form you can find the new style in component  StyleBook1 : TStyleBook (added automatically as we had made some new).

I’ve, of course and as usual,  tested the application on MacOS. The colors are brighter, and we’ve already explained this phenomeon. But the animation happened to be more smooth, with no sudden delays, and chaning due to triggers were seamless. Next time, I’ll make the recording from my Mac directly.

Project BlinkingButton.zip.

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.
Start Free Trial   Upgrade Today

   Free Delphi Community Edition   Free C++Builder Community Edition

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.