Showing posts with label jfxtras. Show all posts
Showing posts with label jfxtras. Show all posts

Wednesday, January 9, 2013

Fun with PreView releases...

Aloha,
I was not sure if it is worth the time to blog about something that might be outdated within weeks but it's so much fun that I decided to share it with you.
At Devoxx 2012 I talked to Daniel Blaukopf (Oracle) where he told me that it won't take long until JDK8 for ARM Preview will be released for the Raspberry Pi and in the beginning of December last year it happened...yipppeah
As much as I loved coding for the BeagleBoard...coding for the Raspberry Pi is even more fun and that's not because of Java/JavaFX (which is in principle the same) but more because the setup of the Raspberry Pi is much easier than the BeagleBoard.
Long story short I had a Raspberry Pi already and the second was ordered at that time so that I was able to start coding for the Pi directly after JDK 8 was released.
First of all I have to say that the instructions on the Oracle page are really good this time and you could get something up and running within a short time.
Because I started porting some of my controls to JDK8 already I was really looking forward to use some of these controls on the Pi...BUT...it didn't work :(
I was not sure why and tried different things but in the end the solution was quite simple...the Embedded team and the Desktop team at Oracle just based their SDKs on different snapshots which lead to my problems.
Don't get me wrong...the "normal" Java stuff works fine but when it comes to Custom Controls (and that's the stuff I'm interested in) you will find different behavior in JavaFX between JDK8 SE and JDK8 for ARM. The problem is only because of one class...SkinBase. 
In JDK8 SkinBase moved from 

    com.sun.javafx.scene.control.skin.SkinBase

to 

    javafx.scene.control.SkinBase

In addition to this the constructor changed from

    SkinBase(Control control, ControlBehavior behavior)

to

    SkinBase(Control control)

So that seems to be not a big deal right...you just have to adjust your Skin class and everything should be fine...
This is only correct for the JDK8 SE version because the JDK8 ARM preview is based on a different version it still takes two arguments in the constructor.
The solution for the problem was to extract the jfxrt.jar from the JDK8 ARM preview, link it to your project and compile your project against JDK7 on the Desktop. Most of the time I spent on figuring out how to compile the jar in a way that it works on the Raspberry Pi on JDK8 ARM preview.

Because it's only a temporary version and will change in the near future I won't post any source code here but I will give you the jar with the controls so you can play with it on your Raspberry Pi.

Related to the new name of the css file in JDK8 which is now Modena instead of Caspian I named the lib Enzo because of Enzo Ferrari who's company Ferrari is placed 18 km away from Modena in Italy. (You have to login to Jira to see the images of Modena and Caspian).
The lib contains the following controls:

  • Clock
  • Lcd
  • Led
  • LedBargraph
  • SevenSegment
  • SimpleIndicator

These are the controls that you will also find in the JFXtras-labs project but implemented in a different way. I completely change the style of creating controls after I discussed with Jonathan Giles, Richard Bair and Jasper Potts.
You don't have to decompile the jar file to get the source code because I will blog about Enzo in the near future anyway and for those of you that can't wait you could find a repository on github here.
There's also a radial gauge in the package but it's work in progress so you can't really use it because it has no tickmarks at all at the moment :)

Download:
Binary jar: Enzo7.jar

Because this post has no images right now...here is one to see the controls in Action running on one of my Raspberry Pi's



The image shows my Raspberry Pi no. 3 that is connected to a 10" touch screen. In addition I've attached logitech usb audio speakers and a high power rgb led from yoctopuce. On the display you see two Lcd controls visualizing the temperature measured by my Raspberry Pi no. 1 and no. 2, two SimpleIndicator controls that visualize the temperature range of each pi and a Clock control showing the current time.

I've also recorded a little video of the setup that you could find on YouTube.

Have fun and keep coding...

Saturday, September 15, 2012

Touch me...

Aloha,

again a short post about using the touch api in JavaFX to interact with a control. I played around with the touch api last week and used it to move the pointer of a gauge with my fingers. 
That was something I would like to do for months and I really was surprised how easy it was to realize.
This morning I read a comment on one of my last posts where someone created a gauge where you could drag the pointer to a certain value and I thought it might be a good idea to share this touch thing with you, so here we go...
First of all I created one of my gauges with the following code...


final Gauge radial = 
    GaugeBuilder.create()
                .prefWidth(600)
                .prefHeight(600)
                .valueAnimationEnabled(false)
                .frameDesign(FrameDesign.STEEL)
                .backgroundDesign(BackgroundDesign.BRUSHED_METAL)
                .pointerType(PointerType.TYPE15)
                .valueColor(ColorDef.CYAN)
                .ledColor(LedColor.CYAN)
                .build();

which leads to the following gauge...



By the way...it shows the new brushed metal background that is now also available in the JFXtras gauges :)

In the next step we have to add the EventHandler for the RotateEvent...


private double value = 0;

radial.addEventHandler(RotateEvent.ROTATION_STARTED,
  new EventHandler<RotateEvent>() {
    @Override public void handle(RotateEvent event) {
      value = radial.getValue();
    }
  });

radial.addEventHandler(RotateEvent.ROTATE,
  new EventHandler<RotateEvent>() {
    @Override public void handle(RotateEvent event) {
      radial.setValue(value + event.getTotalAngle() /
        radial.getAngleStep());
      }
    });


And that's all I have to do to receive rotation events from the touchpad of my Macbook Pro and use the values to rotate the pointer of my gauge...nice isn't it...

For those of you who would like to see it in action I recorded a short video with my iPad (so the quality might be not ideal)...here you go...






That's all I wanted to share with you so...keep coding...

Friday, September 14, 2012

JFXtras SimpleGauge

Today just a very short post about a nice little gauge I have added to the JFXtras-labs project...the SimpleGauge. I found this simple gauge on the web where someone created it in JavaScript and it looked like this...


Because this gauge is really simple and simple is most of the times good enough I decided to create something like this in JavaFX. 
The result looks as follows...



The interesting thing about this gauge is the visualization, it uses only one single node to visualize the bar...a simple Arc and the with and rounded ends are done by using setStrokeWidth() and setStrokeLineCap(StrokeLineCap.ROUND).
It uses the same model as the other gauges from the JFXtras-labs project but it only uses a few of it's features. You could adjust the following parameters

  • animate value
  • bar background color
  • bar color
  • bar width
  • font size of the label
  • font size of the unit
  • color of the label
  • color of the unit
  • no of decimals
  • unit

In addition one could add sections like in the other gauges which will change the color of the bar related to the color of the current section. For example if you use the gauge to visualize the temperature you could define a section for a critical area. Lets say from 80°C to 100°C the bar should be red. Therefor you need the following code

SimpleGauge gauge = new SimpleGauge();
Section criticalRange = new Section(80, 100, Color.RED);
gauge.setSection(criticalRange);

I really like this simple gauge because it shows the current value in a nice way and is enough for most of the use cases.

And for those of you who like to see it in action I've uploaded a little screenvideo to youtube.

That's it for today so...keep coding...


Monday, August 20, 2012

Beach coding...

Aloha everyone,
back home after two weeks in Greece being completely offline (I had to promise my wife that I do not take any electronical equipment with me). Feels good to be connected again.
Because I had no electronic device with me I decided to take my Devoxx notebook and a pen with me. And in fact I've found some time to do some beach coding and here is the result...


As you could (hopefully) read it's about an elliptical gradient. This was something I would like to do for a while and now finally did it. Unfortunately it was not as much work as I first thought.
The biggest challenge was to remember some mathematics without the chance to check it on the web...but as I've transfered the "beach code" to real java code and the result I've got was like this...


Again I have used the WritableImage and PixelWriter feature of JavaFX 2.2 to generate this elliptical gradient. Sometimes this elliptical gradient could be useful to visualize lights etc. so it's up to your creativity...
I've compared the gradient to the elliptical gradient that could be generated in Adobe Fireworks and it seems that they are a bit different. I did not found the time to figure out the details but as soon as I know I will let you know.

The code to create this gradient is really simple, you loop over each pixel in the WriteableImage and simply check if the current point is within the ellipse or not. If it is in the ellipse you just simply calculate the distance from the center and normalize it to one. The result could be used to lookup the color in a given gradient.

This is the code to generate a simple two color gradient...

Stop[] stops    = {
  new Stop(0.0, Color.RED), 
  new Stop(1.0, Color.BLUE)
};
int     width   = 500;
int     height  = 200;
double  a       = width / 2.0;
double  aSquare = a * a;
double  b       = height / 2.0;
double  bSquare = b * b;

WritableImage raster      = new WritableImage(width, height);
PixelWriter   pixelWriter = raster.getPixelWriter();

double isInside;
for (int y = 0 ; y < height ; y++) {
  for (int x = 0 ; x < width ; x++) {
    isInside = ((x - a) * (x - a)) / aSquare + 
               ((y - b) * (y - b)) / bSquare;
    isInside = isInside > 1 ? 1 : isInside;
    Color color = interpolateColor(stops[0].getColor(), 
                                   stops[1].getColor(),
                                   isInside);
    pixelWriter.setColor(x, y, color);
  }
}

// now raster contains the following gradient

A the end raster contains the following image... 



The code of the interpolateColor() method is like follows...

private Color interpolateColor(Color c1, Color c2, double frac) {
  frac = frac < 0 ? 0 : (frac > 1 ? 1 : frac);
  double red   = 
      c1.getRed()+(c2.getRed()-c1.getRed())*frac;
  double green = 
      c1.getGreen()+(c2.getGreen()-c1.getGreen())*frac;
  double blue  = 
      c1.getBlue()+(c2.getBlue()-c1.getBlue())*frac;
  double alpha = 
      c1.getOpacity()+(c2.getOpacity()-c1.getOpacity())*frac;
  return new Color(red, green, blue, alpha);
}

In the code you could download further down I've implemented a version that is able to create multicolor gradients too. This code is also part of the JFXtras labs util package.

Grab the source here.

So that's it for today...nothing special but again fun...keep coding...

Friday, July 13, 2012

Pushing pixels with PixelWriter

Rembember my blog post about the JavaFX Canvas node? I was so happy to be able to draw some pixel graphics to a node and use it as an ImagePattern to fill a shape...especially the conical gradient was fun to create.
BUT as you might have recognized the colors have not been as brilliant as in the Java Swing version. That's the image I'm talking about...




The reason for the subdued colors is the method that I used to create this gradient. In principle I simply rotate a line around the center of the image and vary the color of the line during the rotation. Because the lines have a defined width and the variation of the rotation angle happens in steps it could come to strange effects on large areas...




Now you could argue to decrease the angle stepsize but this would lead to a kind of smear effect in the inner part of the gradient where all the lines will overlay.


Long story short...this is not the right approach !!!


So what could be the solution then ??? Exactly, use the raster of pixels and calculate the color for each pixel dependend on the angle and the distance to the rotation center. To give you an idea I've tried to create an image that hopefully helps to explain it...




Each of those squares should represent one pixel and instead of drawing a simple line from the rotation center of the gradient to the outer part we now have to calculate the color for each pixel. Because we have no overlays and no problems on the outer parts of the gradient the colors will look much better as you could see on the next image...




On the left you see the line based gradient and on the right you see the raster based gradient. The colors are much more brilliant on the raster approach than on the line approach. If you take a close look to the left image you will also see some artifacts at 90°, 180° and 270°.


To get this raster based gradient I used the PixelWriter class that will be available in JavaFX 2.2. The following code shows you how to use it in the simplest way...

public Image randomPixels(int width, int height) {
    WritableImage img = new WritableImage(width, height);
    PixelWriter   pw  = img.getPixelWriter();
    Random        rnd = new Random();
    for (int y = 0 ; y < height ; y++) {
        for (int x = 0 ; x < width ; x++) {
            // Do the pixel manipulation
            pw.setColor(x, y, Color.rgb(rnd.nextInt(255), 
                                        rnd.nextInt(255), 
                                        rnd.nextInt(255)));
        }
    }
    return img;
}

If you call this method you will get something like this...




This means with a little math you could implement a lot of fun image filters/generators. The method that creates the conical gradient looks like this...



public Image getImage(int width, int height, List<Stop> stops) {
    WritableImage raster = new WritableImage(width, height);
    PixelWriter pixelWriter = raster.getPixelWriter();
    Color color = Color.TRANSPARENT;
    Point2D center = new Point2D(width / 2, height / 2); 
    for (int y = 0 ; y < height ; y++) {
        for (int x = 0 ; x < width ; x++) {
            double dx = x - center.getX();
            double dy = y - center.getY();
            double distance = Math.sqrt((dx * dx) + (dy * dy));
            double angle = Math.abs(Math.toDegrees(Math.acos(dx / distance)));
            if (dx >= 0 && dy <= 0) {
                angle = 90.0 - angle;
            } else if (dx >= 0 && dy >= 0) {
                angle += 90.0;
            } else if (dx <= 0 && dy >= 0) {
                angle += 90.0;
            } else if (dx <= 0 && dy <= 0) {
                angle = 450.0 - angle;
            }
            for (int i = 0; i < (stops.size() - 1); i++) {
                double offset = stops.get(i).getOffset();
                double nextOffset = stops.get(i + 1).getOffset();
                if (angle >= (offset * 360) && angle < (nextOffset * 360)) {
                    double fraction = 
                        (angle - offset * 360) / ((nextOffset - offset) * 360);
                    color = 
                        interpolateColor(stops.get(i).getColor(), 
                                         stops.get(i + 1).getColor(), 
                                         fraction);
                }
            }
            pixelWriter.setColor(x, y, color);
        }
    }
    return raster;
}

With this feature it was easy to implement some more of the missing features of the gauges in the JFXtras-labs project. Here is a little screenshot of a gauge using this kind of gradient for the frame and the background...




Well that's all for today, I hope you enjoy coding in JavaFX as much as I do...and if not...I don't care :)


So keep coding...

Friday, June 22, 2012

JFXtras Series: Segmented controls

And another one, today I'll show you the segmented controls in the JFXtras-labs project.
There are three different kinds of segment based controls in the project

  • SevenSegment Control
  • SixteenSegment Control
  • DotMatrixSegment Control

Seven Segment:
The seven segment control is only able to show numbers like you know it from calculators etc. A single seven led segment looks like this...




And if you combine it you could get results like this...






Sixteen Segment:
The sixteen segment control is also able to show characters because of it's additional segments.
A single sixteen led segment looks like this...




Combining some of these elements makes it possible to create an alphanumerical display like this...






Dot Matrix Segment:
The dot matrix segment control is able to show even more characters than the sixteen segment control because of it's more flexible dot oriented design. A single 5x7 dot matrix led segment looks like this...


And you could image that combining these elements you could nearly do anything you like, for example something like this...






This is how the three controls will look like in the JFXtras-labs project...




For each of these controls you could define the color. In addition you could choose if the plain color or a gradient based on the color should be used to fill the segments. On the image above you could see the difference between these two modes (middle plainColor == true, right plainColor == false). To give you an idea how you could use the segments here comes some code...



DotMatrixSegment segment = 
    DotMatrixSegmentBuilder.create()
                           .color(Color.AQUA)
                           .character("F")
                           .plainColor(true)
                           .prefWidth(100)
                           .prefHeight(150)
                           .build();

At the moment there are three different builders (one for each control) but that might change in the future (there might be an additional SegmentBuilder) because this controls are very similar.
Instead of using the .character(String) method you could also use the .character(Character) method which makes it possible to use also other ascii characters (only SixteenSegment and DotMatrixSegment control).
The DotMatrix controls even offers the possibility to use your own dot mapping. This feature will give you the ability to use the DotMatrix control for whatever you have in mind. To create you own dot mapping you have to know how the DotMatrix control handles the dots. 
The DotMatrixSegment class contains an enum named Dot which is defined like follows...


public static enum Dot {
    D11, D21, D31, D41, D51,
    D12, D22, D32, D42, D52,
    D13, D23, D33, D43, D53,
    D14, D24, D34, D44, D54,
    D15, D25, D35, D45, D55,
    D16, D26, D36, D46, D56,
    D17, D27, D37, D47, D57
};


The mapping is realized by a HashMap<Integer, List<Dot>>, so the character "Y" is for example mapped like this...

mapping.put(89, Arrays.asList(new Dot[]{
    Dot.D11, Dot.D51
    Dot.D12Dot.D52
    Dot.D23, Dot.D43
    Dot.D34
    Dot.D35
    Dot.D36
    Dot.D37}));

That means you could create your own codes with the associated dots to create your own characters, for example a smiley like this...


Let's say we would like to map this smiley to the 0 the code would look like this...


Map<Integer, List<DotMatrixSegment.Dot>> customMapping = 
    new HashMap<Integer, List<DotMatrixSegment.Dot>>();


customMapping.put(0, Arrays.asList(new DotMatrixSegment.Dot[] {
    Dot.D22, Dot.D42,
    Dot.D34,
    Dot.D15, Dot.D55,
    Dot.D26, Dot.D36, Dot.D46
}));


DotMatrixSegment segment = 
    DotMatrixSegmentBuilder.create()
                           .customSegmentMapping(customMapping)
                           .character((char) 0)
                           .color(Color.RED)
                           .prefWidth(300)
                           .prefHeight(420)
                           .build();

And here is the result...


I'm not sure if it is a drawback or a feature that you have to create the logic of more complex displays by yourself but I personally like the ability to be free in my decision how I implement something.

So unleash your creativity and keep coding...