experimenting with javafx and java 8

I’ve been working a bit with JavaFX for a little while now, looking to achieve complex graphical applications with more power and greater programmatic ease than I ever could with the Java Foundation Classes (AWT, Swing, and Java 2D). If nothing else, the ability to tool the look and feel through CSS (Cascading Style Sheets) is a huge advance over pure Java programming, But I digress…

I’ve had one application that uses JavaFX Canvas (javafx.scene.canvas.Canvas) for some complex rendering, but it hasn’t worked the way I wanted it to. So I backed up and created a simple JavaFX lab to work with and better understand how to use a JavaFX Canvas in a BorderPane. I did finally come to understand how to use the various components together. I’m sharing this in the hope that it’ll help anyone with similar needs and looking for a solution.

package borderpaneexample;import javafx.application.Application;import javafx.event.ActionEvent;import javafx.geometry.Insets;import javafx.geometry.Pos;import javafx.scene.Scene;import javafx.scene.control.Button;import javafx.scene.layout.BorderPane;import javafx.scene.layout.HBox;import javafx.scene.layout.Pane;import javafx.scene.layout.StackPane;import javafx.scene.layout.VBox;import javafx.stage.Stage;public class BorderPaneExample extends Application {@Overridepublic void start(Stage primaryStage) {BorderPane borderPane = new BorderPane();Button rightButton = new Button("Right");rightButton.setOnAction((ActionEvent event) -> {System.out.println("Right button");});Button leftButton = new Button("Left");leftButton.setOnAction((ActionEvent event) -> {System.out.println("Left button");});Button topButton = new Button("Top");topButton.setOnAction((ActionEvent event) -> {System.out.println("Top button");});Button bottomButton = new Button("Bottom");bottomButton.setOnAction((ActionEvent event) -> {System.out.println("Bottom button");});Pane centerPane = new Pane();ResizeableCanvas resizeableCanvas = new ResizeableCanvas(centerPane);centerPane.getChildren().add(resizeableCanvas);centerPane.setStyle("-fx-padding: 0;" +"-fx-border-style: solid inside;" +"-fx-border-width: 1;" +"-fx-border-insets: 0;" +"-fx-border-radius: 0;" +"-fx-border-color: #000;");borderPane.setCenter(centerPane);borderPane.setRight(rightButton);BorderPane.setAlignment(rightButton, Pos.CENTER_RIGHT);VBox vbox = makeVBox();vbox.getChildren().add(leftButton);borderPane.setLeft(vbox);BorderPane.setAlignment(leftButton, Pos.CENTER_LEFT);HBox hbox = makeHBox();hbox.getChildren().add(topButton);borderPane.setTop(hbox);BorderPane.setAlignment(topButton, Pos.TOP_CENTER);borderPane.setBottom(bottomButton);BorderPane.setAlignment(bottomButton, Pos.BOTTOM_CENTER);borderPane.setStyle("-fx-padding: 2;" +"-fx-border-style: solid inside;" +"-fx-border-width: 2;" +"-fx-border-insets: 2;" +"-fx-border-radius: 0;" +"-fx-border-color: #cccccc;");Scene scene = new Scene(borderPane, 800, 600);primaryStage.setTitle("BorderPane Example with Canvas");primaryStage.setScene(scene);primaryStage.show();}public static void main(String[] args) {launch(args);}public HBox makeHBox() {HBox hbox = new HBox();hbox.setPadding(new Insets(5, 5, 5, 5));hbox.setSpacing(5);hbox.setStyle("-fx-background-color: #cccccc;");return hbox;}public VBox makeVBox() {VBox vbox = new VBox();vbox.setPadding(new Insets(5, 5, 5, 5));vbox.setSpacing(5);vbox.setStyle("-fx-background-color: #dddddd;");return vbox;}}

The main class is where the application is constructed and launched. The key to making this work is to create a class derived from Canvas.

package borderpaneexample;import javafx.scene.canvas.Canvas;import javafx.scene.canvas.GraphicsContext;import javafx.scene.layout.Region;import javafx.scene.paint.Color;import javafx.scene.text.Font;public class ResizeableCanvas extends Canvas {private double width, height;public ResizeableCanvas(Region region) {widthProperty().bind(region.widthProperty());heightProperty().bind(region.heightProperty());widthProperty().addListener(event -> resizeDraw() );heightProperty().addListener(event -> resizeDraw() );}private void resizeDraw() {width = getWidth();height = getHeight();GraphicsContext gc = getGraphicsContext2D();gc.clearRect(0, 0, width, height);gc.fillOval((width - 40)/2.0, (height - 40)/2.0, 40, 40);Font font = gc.getFont();gc.fillText("Width: " + Double.toString(width), width/2 + 2, font.getSize());// Some interesting graphics context manipulation. Move to the left// edge and print the height, rotated 90 degrees parallel to the// left edge.//gc.save();gc.translate(font.getSize(), height/2);gc.rotate(-90);gc.fillText("Height: " + Double.toString(height), 2, 0);gc.restore();gc.setStroke(Color.RED);gc.setLineWidth(2);gc.strokeLine(0, 0, width, height);gc.strokeLine(0, height, width, 0);gc.strokeLine(width/2.0, 0, width/2.0, height);gc.strokeLine(0, height/2.0, width, height/2.0);}@Overridepublic boolean isResizable() {  return true;} @Overridepublic double prefWidth(double height) {  return getWidth();} @Overridepublic double prefHeight(double width) {  return getHeight();}}

The exposition for how this works is in the comments of ResizeableCanvas. But if you want to see where it was added, then check out highlighted lines 46-48 in the main class. All of this was done in NetBeans 8.2 as the editor/IDE, and Java 8 update 152. It’s going to be a while yet before I move to Java 9; all the tools I need just aren’t there yet.

example alternatives to java-based applications – etcher by resin.io

I’m back to finding alternatives to the use of Java. Oracle is working to increase license collections on Java big time starting this year. I loath Oracle and all things Oracle, and the fact they now own Java and have gone after licensing fees for Java means, for me, that I have come to loath Java equally. It is for this reason I’ve once again flip-flopped toward finding and using any and all alternatives to Java on every platform I work with. An excellent example of an alternative is the image burner application Etcher from resin.io.

Etcher ticks a number of key boxes for me:

  • It can safely copy a Linux image from an image file (iso, img, etc) to a USB drive or SDHC device.
  • It can work on Windows, Linux, or macOS. In this example I tested it on macOS Sierra.
  • It’s open source and available via github.
  • It’s based on Electron, using CSS, HTML, and JavaScript.
  • I can use it to copy my Raspberry Pi images to micro SDHC cards simply and reliably on my MBP.

That last bullet is what makes it a full keeper for me, as well as the tool I now point novices towards who want to work with the Raspberry Pi and want to create their own micro SDHC cards. It is absolutely as simple as starting the application, pointing it towards the image, and then plugging in the device to be flashed. Etcher finds the device automatically, making it dead simple to click the button and start the image copy to the device. No more tricky and down-right dangerous CLI dances with mount, umount, and dd.

Other Electron-based applications I now use are Atom, the editor, and Slack. There’s a whole bunch more out there, and the tooling to write even more is available where-ever there’s tooling for writing web applications. Java isn’t going to die anytime soon as it has a lock on a lot of legacy software. But that’s the same formidable block that Microsoft Windows posed back in the day, and we’ve seen where Microsoft is today, especially in mobile. Rather than complain about how bad Oracle and Java have become, my energy would be better spent promoting Electron and other foundational products and tools as better solutions than Java, even Java 8. It really is time to move on.