Thursday, July 26, 2012

MatrixPanel, a new JavaFX UI control. Second part

Hi again! 

In this second post of this two part series I'll show you how easy is to bring to 'live' the MatrixPanel control, once we learnt in the first post how to create one and insert text or image content. Those of you who still haven't read it, please do it before, here.

So let's talk about applying animation effects to the contents in the MatrixPanel control, starting with our first sample (in low quality to minimize size, sorry):

To make the animation effect we use the MatrixPanelBuilder builder class like this:

private final MatrixPanel animatedPanelDemo = 
          MatrixPanelBuilder.create()
                            .ledWidth(140).ledHeight(26)
                            .prefWidth(580.0).prefHeight(580.0)
                            .frameDesign(FrameDesign.DARK_GLOSSY)
                            .contents(new Content[] {
                                new ContentBuilder().create()
                                    .color(MatrixColor.RED)
                                    .type(Type.TEXT)
                                    .origin(0, 5)
                                    .area(0, 0, 140, 26)
                                    .txtContent("MatrixPanel ROCKS!!    ")
                                    .font(MatrixFont.FF_10x16)
                                    .fontGap(Gap.DOUBLE)
                                    .align(Align.RIGHT)
                                    .effect(Effect.SCROLL_LEFT)
                                    .lapse(120)
                                    .postEffect(PostEffect.PAUSE)
                                    .pause(2000)
                                    .order(RotationOrder.SINGLE)
                                    .clear(true)
                                    .build()
                            })
                            .build();

The main option to add visual effects is effect, which take the type of animation for the content. For now these are available:
  • NONE
  • SCROLL_LEFT, SCROLL_RIGHT, SCROLL_DOWN, SCROLL_UP
  • MIRROR
  • BLINK, BLINK_10, BLINK_4
  • SPRAY
The scrolling effects are intended for wider texts than its visible area. When scrolling to the left the text should be aligned to the right, and viceversa.

The other effects, on the contrary, should be used when all the content is visible. The mirror effect starts scrolling from the center of the content one half to the left, the other to the right. The blinking effects make the content blink indefinetely, ten or four times, respectively. And the spray effect makes the content appear switching LEDs on randomly.

With the lapse option, you set the time lapse,  in milliseconds, for each frame of the animation effect. Here it's a little code snippet I use to animate each content with its own time-lapse. Note that parameter in handle method now is in nanoseconds.

      for (final Content content : contents) {
            ...
            new AnimationTimer() {
                private long lastUpdate=0l;
              
                @Override public void handle(long now) {

                    if (now > lastUpdate + content.getLapse()*1000000){
 
                        /*
                        *  display the visible area in its current step position
                        */
 
                        ... 
                   
                        lastUpdate = now;
                    }
                }  
            }.start();
      }
There is a lower limit to time lapse, due to several factors such  as CPU load and speed, RAM, size of content to display,... To get lapses as 20 ms, as I wrote in the first part of this post, I had to remove the css styling and the shadow effects.

You may have noticed the use of the JavaFX AnimationTimer class. There`s a very good post by Michael Heinrichs here explaining its use. Although it's not the most used animation class of JavaFX, its suits pretty well here to perform just one single step between the time-lapse you set and to control the speed of the effect.

After all the steps of the animation effect have been done, the effect ends, and you should decide what to do next. For that, the option postEffect allows you to choose between:
  • STOP
  • PAUSE
  • REPEAT
With the PostEffect.STOP option the content remains in the last position with no further animation effect, while with PAUSE and REPEAT the effect starts again. In the first case, you must set a pause in milliseconds, while in the second, there is no pause.

Here comes in handy the JavaFX PauseTransition class. You set the Duration of the pause, and while the transition hasn't finished a boolean avoids any step to happen (see the snippet below, in the outer if). When the pause time is reached the handle method resets the boolean and the effect starts again:

      
        for (final Content content : contents) {
            ...
            new AnimationTimer() {
                private long lastUpdate=0l;
                private boolean bPauseEffect=false;
              
                @Override public void handle(long now) {

                    if (now > lastUpdate + content.getLapse()*1000000
                        && !bPauseEffect){

                        ... 

                        /*
                        *  at the end of the effect
                        */

                        if(content.getPostEffect().equals(PostEffect.REPEAT) || 
                           content.getPostEffect().equals(PostEffect.PAUSE)){
                           
                           PauseTransition t=new PauseTransition();
                           bPauseEffect=true;
                           t.setDuration(Duration.millis(content.getPause()));
                           t.setOnFinished(new EventHandler() {
                                @Override public void handle(ActionEvent event) {
                                      bPauseEffect=false;
                                }   
                           });                                        
                           t.playFromStart(); 
                        }                   
                        lastUpdate = now;
                    }
                }  
            }.start();
      }

Let's add some video here to show you all this stuff. Let's use a MIRROR effect combined with a pause of 3 seconds to start again:


Finally, the last option to build the matrixPanel is order. The default option is set to RotationOrder.SINGLE, for just one single content displayed in its area. But if you want to use the same area to show alternatively two different contents or apply two different effects two the same content, use RotationOrder.FIRST  as parameter for order option in the first content, and RotationOrder.SECOND for the second. You may consider setting the option clear to true in order to clean the screen before the next content is displayed. 

Here we have another video, with the same image, but two different effects, SPRAY and BLINK_4.



Well, this is pretty much what you need to know to create a MatrixPanel control and use it in a JavaFX scene.

For those of you willing to use it or, even more, use the code to add more effects, more fonts, more possibilities, ...

...I'm really glad to tell you that now this control has been included in the JFXtras Project, so you can find the source code bundled with all their cool stuff, sure you already know by now.

I want to express my sincere gratitude to the JFXtras TEAM for letting me in.This final video is a small tribute to you all, specially to Gerrit. By the way, I'm taking as image his logo for the JFXtras Ensemble application installer:


Well, and that's all for now! Hope you like the control. Any comment or suggestion is always welcome! Please, remind it's work in progress...

No comments:

Post a Comment