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...

Thursday, July 19, 2012

MatrixPanel, a new JavaFX UI control. First part

Hi, this is my first JavaFX post, so don't be too cruel on me, please!

In this two part series post, I'd like to share with you the work I've been doing on a new JavaFX 2.x control, in close collaboration with Gerrit Grunwald (@hansolo_, http://www.harmonic-code.org/). 

In fact, the control is based in his awesome well-known Gauge's collection, which recently he has upgraded from Swing to JavaFX 2.x. 

It is a mix of a Linear gauge and an extension on his DotMatrixSegment control which, as you may know, are available at the JFXtras project.

So let me introduce you the brand new MatrixPanel control.

For those anxious to find out what is this about, if the name isn't quite self-explanatory, here you have a pic:

As you can see, the control is based on a rectangular matrix of Circles (JavaFX nodes), each one acting as a LED, so the control is a digital version of those LED displays you can find everywhere nowadays.

So its main features are:
  • Create any size of matrix (width and height)
  • Monochromatic or color (3 tones of R, G & B) panel
  • Display both text (several dotted fonts) or images (in BMP format)
  • Creation of several areas within the panel to display independent content in each one of them
  • Animation effects of the content of each area. Adjustable speed, and pause time between next effect is displayed.
  • Rotation of contents in the same area.
To go in full detail with all the properties involved in the creation of a MatrixPanel control, let's have a look at the code to build it, using the proper builder class,  MatrixPanelBuilder:

   private final MatrixPanel panelDemo = 
          MatrixPanelBuilder.create()
                            .ledWidth(140)
                            .ledHeight(40)
                            .prefWidth(760.0)
                            .prefHeight(760.0)
                            .frameDesign(Gauge.FrameDesign.DARK_GLOSSY)
                            .frameVisible(true)
                            .contents(new Content[] {
                                new ContentBuilder().create()
                                    .color(Content.MatrixColor.RED)
                                    .type(Content.Type.TEXT)
                                    .origin(0, 10)
                                    .area(0, 0, 140, 40)
                                    .txtContent("MATRIXPANEL")
                                    .font(Content.MatrixFont.FF_10x16)
                                    .fontGap(Content.Gap.DOUBLE)
                                    .align(Content.Align.CENTER)
                                    .effect(Content.Effect.NONE)
                                    .postEffect(Content.PostEffect.STOP)
                                    .order(Content.RotationOrder.SINGLE)
                                    .build()
                            })
                            .build();
And you can load it in a JavaFX scene simply by:

public void start(Stage primaryStage) {
        primaryStage.setTitle("MatrixPanel Demo");

        StackPane root = new StackPane();
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);
        root.getChildren().add(panelDemo);
        primaryStage.setScene(new Scene(root, 800, 600));
        primaryStage.centerOnScreen();
        primaryStage.show();
    }

Basically, first you have to set the number of LED columns  (ledWidth) and rows (ledHeigth) and the size of the control in the scene. In order to keep the LEDs shape as circles, one dimension (prefWidth or prefHeight) will be recalculated, so you don't need to worry, and just set the maximum space available within the scene for the control. Then you can select the frame design (DARK_GLOSSY or GLOSSY_METAL, for now), or simply hide it.


And now we deal with the contents to display. You can add as many contents as you want, creating each one by its builder class ContentBuilder.


First you choose the color: RED, GREEN, BLUE or RGB, and then you set the content type: IMAGE or TEXT

For text content, these are the four colors available:
For bmp images, three tones of each color are considered, so the bmp rawdata is filtered accordingly. Let's load this 32x32 bmp:
in four areas to show you the four possibilities of coloring:
The image is loaded with the option bmpName, which requieres the bmp name of the image if it is locally stored in resources, or a full external path and its name, otherwise.

For those of you disappointed with the poor performance of the LEDs matrix style, let me tell you that first I used css styling for each circle, with gradients and inner shadows. But there were serious CPU issues loading the panel and applying animation effects. So following Gerrit's advice I removed css styling and provided the same effects by code. Although there were some improvements, the best solution was to remove any effect, and just leave a simple filling of each circle with the proper color. Anyway, as the size of the LEDs decrease, the difficult to appreciate any lack of shadowing effect increase.

You may have noticed that the former matrixpanels contained four areas, so let's talk about origin and area options. An area is defined by its left-top and right-bottom LED coordinates. You shouldn't overlap differents areas. The origin is the left-top LED coordinate where the content will start being displayed. By LED coordenate I mean number of LEDs from the left and the top, instead of pixels.


For text content, by using the option txtContent you set the string of text. It will be displayed in one line. If it's wider than the visible area, you should use a scrolling effect to visualice it completely, as we'll see in the second part of this post. 

Then you have to choose a font. For now there is a bunch of proportional dotted fonts, with the usual ASCII range of printable characteres (A to Z, a to z, 0 to 9, +, -, *, /, \,...) available.  The next matrixpanel shows their name, which stands for width and height of each character:

The fontGap option allows to insert a column of 0 (NONE), 1 (SIMPLE) or 2 (DOUBLE) leds between each character. And the align option allows LEFT, CENTER or RIGHT justification for the text in its area.

To end this first part of the post, let me just finish with effect option set to NONEpostEffect option set to STOP and order option set to SINGLE. This means the content will be static, no further action will be done after been displayed and no other content will supply it.

The next post will be dedicated to animation, so stay tuned!

Meanwhile, any comment or suggestion will be really appreciated!!

Finally, thank you Gerrit, for your inspiring work.

Wednesday, July 18, 2012

My brand new blog. Short presentation

Hi everyone!

My name is José Pereda, and I'm an Structural Engineer, working as a professor in the School of Industrial Engineering in the University of Valladolid (Spain), since 1997.

This blog is not about structures nor teaching, as my real passion is coding, and make useful applications to solve engineering problems.

So the incoming posts will be, mostly, related to coding stuff of applications I'm working on or have been, not neccessary in historic order.

I must warn you I'm not a professional software developer, so this blog it's not intended to provide with academic solutions for advanced problems.

On the contrary, I'd like to share with you snnipets of my not-allways-by-the-book practical solutions. I'll be glad if they're usefull for anyone. Your opinion will be allways welcome!

The next post will be related to JavaFXthe next step in the evolution of Java as a rich client platform.