Thursday, 28 November 2013

What's new in JavaFX 2.2 ?

Earlier this week, Oracle released JavaFX 2.2, which is a significant update release:
  • With version 2.2, JavaFX is finally available on Windows (32-bit & 64-bit), Mac OS X (64-bit), and Linux (32-bit & 64-bit), which means that most developers can build and test JavaFX applications on their preferred development environment. Have a look at the JavaFX Certified System Configurations for more details.

  • The JavaFX 2.2 Runtime is now part of Oracle’s Java SE 7u6 implementation. While we already had some form of integration between these two products since December 2011, , we now have one unified installer, with the JavaFX libraries installed alongside the Java SE libraries for both the JDK and the JRE. This means a more streamlined user experience, and the assurance for application developers that the number of computers capable of running JavaFX applications will soon be as large as for Java SE applications.

  • A stand-alone implementation of JavaFX 2 will remain available for Java SE 6 users, but only on Windows. Additionally, that stand-alone version will no longer be supported when Java SE 6 reaches End of Life (EOL) in February 2013. As explained previously, this means there will no longer be bug fixes or security fixes available for Java SE 6 users after that date, unless you or your customers sign up for our commercial Java SE Supportoffering. Otherwise, plan your migration to Java SE 7 right now.

Besides these important changes, JavaFX 2.2 brings in some key new features:
  • JavaFX applications can now be redistributed as self-contained application packages. These platform-specific packages include all application resources and a private copy of Java and JavaFX Runtimes. Distributed as a native installable package, they provide the same installation and launch experience as native applications for that operating system. A key benefit to take into consideration is that it will allow you to deploy JavaFX 2.2 applications bundled with Java SE 7 without impacting existing deployments of older Java SE implementations.

  • Multi-touch support for touch-enabled devices. As of today this is mostly relevant for desktop-class touch screen displays and touch pads, this will enable the adoption of sophisticated UIs on embedded devices running Java SE Embedded on ARM-based chipsets, such as kiosks, telemetry systems, healthcare devices, multi-function printers, monitoring systems, etc. This is a segment of the Java application market that is usually overseen by most application developers, but that is thriving.

  • The JavaFX Canvas API, a Canvas 2D drawing surface that provides HTML5 Canvas-style operations. Developers familiar with HTML5 will definitely be at ease with the JavaFX Canvas API, although it is important to notice that this is not meant to be a duplicate of the HTML5 Canvas Graphics API. We believe this API will also be welcome by developers with other backgrounds, such as AWT or SVG. You can run a demo of the “Fireworks” canvas demo under the section “NEW!” of the Ensemble sample application, or you can watch the making of another Canvas example on this video.

  • JavaFX 2.2 introduces the ability to read and write pixels to and from JavaFX image objects. An example is available as “Image Operator” in the “NEW!” section of Ensemble.

  • Two new UI controls have been added to JavaFX 2.2: a color picker, and a pagination control; you can give them a try in the “NEW!” section of Ensemble. In addition, the WebView control now provides the ability to manage web history. Finally, we have documented how to create a custom control with FXML, which takes advantage of FXML enhancements.

  • HTTP Live Streaming support is a feature that strengthens up JavaFX’s media support. Essentially, media players are now able to switch to alternate video and audio streams, as specified in a downloadable playlist file and based on network conditions.

  • Additional information to help Swing developers implement a Swing application in JavaFX, and SWT developers to integrate JavaFX content in SWT applications. We also have documented some Best Practicesfor developing a JavaFX application.

  • Last but not the least, JavaFX developers can now leverage the new JavaFX Scene Builder 1.0 to visually layout an application UI, and generate FXML content that helps keep a clean separation between application logic and UI. Scene Builder is also a great example of a complex application written in JavaFX. It is currently available on Windows and Mac OS X, and is optimized to work seamlessly with NetBeans 7.2 or higher (it can also be used with other Java IDEs).


In summary, JavaFX 2.2 is a key release that brings much more than Linux support. It fulfills Oracle’s vision to integrate JavaFX with Java SE to a large extent, and is a proof of our commitment for cross-platform support and predictable timelines.

Timed JavaFX Dialogs

When I wrote the original MonologFX dialogs for JavaFX, I was just trying to clean up a few things I'd done in my earlier project, DialogFX, that I felt could have been done better. Based upon some excellent feedback and suggestions, I rolled out the update...just as the OpenJFX team was releasing their own dialog code that is destined to be in JavaFX/OpenJFX. :-) As I mentioned in this previous post, rather than just hoard the code, I released it anyway in the hopes others might continue to find it useful - and updated the dialogs in the JFXtras Labs library as well - but didn't really expect there to be much continued interest.



I'm happy to say I was wrong. One of my goals was to make a very simple set of dialogs that worked well in most cases and that just "got out of the developer's way"...tools you didn't have to think about extensively to use in your JavaFX application, just "drop & go". They were never meant to be all things to all people, rather a solid option for most use cases. But...


I've gotten some excellent follow-on requests, and I've explored several of them. While I may never have the time to implement them all - and some wander FAR from the original goals - some just fit. One of those ideas was for timed dialogs.


What is a Timed Dialog, and When Would I Use It?
A few developers pointed out that there are occasions when an app is running unattended and dialogs can either a) stop everything or b) pile up by the droves on the user's desktop. And JFXtras implementer Scott mentioned how nice it would be to have an informational dialog that worked similar to a mail notification, popping up and then disappearing after some pre-determined amount of time. The user should also be able to clear the dialog immediately, of course.


Enter the timed dialog. Drawing inspiration from the aforementioned mail notifications and a sample game by colleague Angela Caicedo, I expanded upon Angela's game-switching example to create a (hopefully pleasing) dialog fade in/out effect. Using the number of seconds specified by the developer (you!) via the methodsetDisplayTime(int displayTime), MonologFX apportions a reasonable percentage of that time to fade in, display, and fade out operations...making user input entirely optional.


What Does it Look Like?


It's much easier to demo than it is to explain, so I created a quick video of a normal dialog, then a timed one, in action. Click here to watch it on YouTube.


Limitations, Caveats, "Keep Off the Grass" Signs
A timed dialog is really best suited for informational dialogs - those where there is no user input required, like the aforementioned mail notifications. If a response is required from a user and a dialog disappears of its own volition, which option should be chosen? The "cancel" option would seem best in some cases, and the "default" in others.


Creating the fade in/out effect required a non-blocking implementation, which meant that it would always return a value immediately...and in the current design, that is "cancel". Which again points to using them as informational dialogs, but not for obtaining user feedback.


So for the foreseeable future, timed dialogs are really focused upon and should be confined to use as informational dialogs. If you need the application user to make a conscious choice prior to proceeding, keep that dialog prominently displayed until you get a response!


Where Can I Get Them?


I've already pushed the code to my Github repository for MonologFX and the JFXtras-Labs 2.2 and JFXtras-Labs 8.0 repos. And if you just want to download a .jar file and kick the tires, I've put a copy in the MonologFX repo's dist folder. Just download the .zip file, unzip it, and run java -jar MonologFX.jar for a quick demo.



Odds & Ends

I also made a few architectural changes to MonologFX this weekend during our first-ever "Thanks For Sharing Informal, International HackFest", and more will be integrated over time. Please stay tuned for more information. :-)

Happy Coding!
Jay Thakkar

Tuesday, 26 November 2013

Simple Calendar for JavaFX 2.0

One of the missing controls in JavaFX 2.0 is a date picker. So I have developed the SimpleCalendar for that purpose. It was also a good practice to learn what you could do with JavaFX. You can download it from http://code.google.com/p/javafx-widgets/downloads/list
The SimpleCalendar is a combination of two components: A popup container for date picking and a button to display the hidden popup container. The container consist of three blocks. The top block displays the month and the year and hosts two arrows to navigate back and forth between months. The center block only displays first letters of the names of the days. The bottom block displays the days of previous, present and next months. The names are retrieved based on default locale. Since the first day of the week is Monday in some locales it is taken into account.


A string bean property (changed to ObjectProperty 28.01.2012) is used to bind the date information. It can be accessible by adding a change listener to the instance of SimpleCalendar.

A Complex Widget : Waterfall Display

A waterfall display (aka Spectrogram) is a moving bitmap image that shows the history of the recorded spectra. As time proceeds, old samples will be scrolled out of view. I think it is a complex widget (at least for me). I developed it to explore the JavaFX capabilities. The problem is that JavaFX Image and ImageView classes are rather simple to perform complex image operations. Therefore I used AWT classes then converted the buffered image to a JavaFX image in PNG format with the PngEncoder which is developed by J. David Eisenberg (PngEncoder).

The waterfall display is refreshed at intervals between 200 and 3200 ms. The intensity data is stored in a byte array. At each refresh time the last line is added to the array, and the image is regenerated in the memory with the timestamps and the overlay texts if exist.


In this process, first the waterfall part and the timestamp part of the image are created as buffered images. The waterfall part contains the byte array which has the intensity data normalized to 0 – 127. The data are colored with an indexed color model spanned between a first color and a second color. Then both parts are combined into a full buffered image on which the texts are drawn. Last operation is the conversion of the buffered image to an PNG format so it can be handled by JavaFX Image class. Whole generation process runs in the background so the mouse movements are not affected. I implemented JavaFX Task class for threading and think it is easy to implement.


An extended cross hairs is added to get the intensity value at desired points. It is also used to add overlay texts on the image. They can be entered by right click.



The source code can be downloaded from : javafx-widgets

The DoubleSlider Control

Sometimes one may need to adjust upper and lower limits of a variable. In this case it is necessary to utilize one control for each limit. However it could be more useful if two controls would have been integrated into one control. With this idea I’ve developed the DoubleSlider Control which has one thumb for each limit, by modifying the code for the Slider Control in OpenJFX project. It works with JavaFX 2.1.


It can be downloaded from : javafx-widgets

I haven’t implemented the keyboard bindings expect “Home” and “End”, because I couldn’t find an efficient way to handle them. The problem is that I couldn’t manage a thumb focused at a time.



import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import org.controlsfx.Sample;
import org.controlsfx.control.RangeSlider;

public class HelloRangeSlider extends Application implements Sample {
    
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override public String getSampleName() {
        return "RangeSlider";
    }
    
    @Override public Node getPanel(Stage stage) {
        VBox root = new VBox(15);
        
        Region horizontalRangeSlider = createHorizontalSlider();
        Region verticalRangeSlider = createVerticalSlider();
        root.getChildren().addAll(horizontalRangeSlider, verticalRangeSlider);
        
        return root;
    }
    
    @Override public void start(Stage stage) {
//        setUserAgentStylesheet(STYLESHEET_CASPIAN);
        stage.setTitle("RangeSlider Demo");

        Scene scene = new Scene((Parent)getPanel(stage), 520, 360);

        stage.setScene(scene);
        stage.show();
    }
    
    Region createHorizontalSlider() {
        final TextField minField = new TextField();
        minField.setPrefColumnCount(5);
        final TextField maxField = new TextField();
        maxField.setPrefColumnCount(5);

        final RangeSlider hSlider = new RangeSlider(0, 100, 10, 90);
        hSlider.setShowTickMarks(true);
        hSlider.setShowTickLabels(true);
        hSlider.setBlockIncrement(10);
        hSlider.setPrefWidth(200);

        minField.setText("" + hSlider.getLowValue());
        maxField.setText("" + hSlider.getHighValue());

        minField.setEditable(false);
        minField.setPromptText("Min");

        maxField.setEditable(false);
        maxField.setPromptText("Max");

        minField.textProperty().bind(hSlider.lowValueProperty().asString("%.2f"));
        maxField.textProperty().bind(hSlider.highValueProperty().asString("%.2f"));

        HBox box = new HBox(10);
        box.getChildren().addAll(minField, hSlider, maxField);
        box.setPadding(new Insets(20,0,0,20));
        box.setFillHeight(false);

        return box;
    }
    
    
    Region createVerticalSlider() {
        final TextField minField = new TextField();
        minField.setPrefColumnCount(5);
        final TextField maxField = new TextField();
        maxField.setPrefColumnCount(5);

        final RangeSlider vSlider = new RangeSlider(0, 200, 30, 150);
        vSlider.setOrientation(Orientation.VERTICAL);
        vSlider.setPrefHeight(200);
        vSlider.setBlockIncrement(10);
        vSlider.setShowTickMarks(true);
        vSlider.setShowTickLabels(true);

        minField.setText("" + vSlider.getLowValue());
        maxField.setText("" + vSlider.getHighValue());

        minField.setEditable(false);
        minField.setPromptText("Min");

        maxField.setEditable(false);
        maxField.setPromptText("Max");

        minField.textProperty().bind(vSlider.lowValueProperty().asString("%.2f"));
        maxField.textProperty().bind(vSlider.highValueProperty().asString("%.2f"));

        VBox box = new VBox(10);
        box.setPadding(new Insets(0,0,0, 20));
//        box.setAlignment(Pos.CENTER);
        box.setFillWidth(false);
        box.getChildren().addAll(minField, vSlider, maxField);
        return box;
    }
    
}

Java3D Tutorials By Jonathan Miyamoto

Saturday, 23 November 2013

Loading, cropping, saving an image in Java

You'd typically
  1. Create a new BufferedImage with the desired width and height.
  2. Get hold of it's Graphics object
  3. Load the original .jpeg image
  4. Paint the desired part of that, onto the BufferedImage
  5. Write the buffered image out to file using ImageIO.
In code:
Image orig = ImageIO.read(new File("duke.jpg"));

int x = 10, y = 20, w = 40, h = 50;

BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
bi.getGraphics().drawImage(orig, 0, 0, w, h, x, y, x + w, y + h, null);

ImageIO.write(bi, "png", new File("duke_cropped.png"));
Given this .jpg...
...It generates this .png: