JavaFX Tip 27: HiRes / Retina Icons

I recently had a lot of icons sent to me by a graphics / UX designer. It was my job to add them to a JavaFX application. Each icon was shipped in three sizes (16×16, 32×32, 64×64). The naming convention for them was like this:

  • icon-name.png
  • icon-name@2x.png
  • icon-name@3x.png

At first I thought that this was some kind of standard naming used by graphic designers for their files but in the end it turns out to be a convention that was initially introduced by Apple for their Retina displays and adapted by the JavaFX team. The idea is that JavaFX will automatically load the appropriate image file for the current screen resolution. So when the application wants to load a 16×16 icon and JavaFX determines that the screen is a Retina / HiRes display it will then load the @2x file. The result of this are crisp graphics that take full advantage of these beautiful screens.

To enable this automatic image loading one can use CSS or code. In CSS you can define a style like this (assuming image file is in the same directory as CSS file):

    .my-icon {
        -fx-graphic: url("icon-name.png");
    }

Then you can apply the style to your button and it will show the @2x icon if applicable:

    button.getStyleClass().add("my-icon");

When you want to load images in code you have to make sure not to use input streams but a URL. Example:

    Image image = new Image(MyApp.class.getResource("icon-name.png").toExternalForm());

Using hires icons is really worth your time as your UI will look even more beautiful on HiRes displays.

JavaFX Tip 26: Go Dark – The “Darcula” Theme

I am a big fan of IntelliJ IDEA and use it every day for the various projects I work on. One thing I like a lot is the dark theme called “Darcula”. I like it because it looks cool and because of the low contrast it is better for my eyes. When you stare at something for at least eight hours a day for decades (yes, I am that old) then you better make sure it goes easy on your eyes. This said I obviously also like to use dark themes for my own creations. The following snapshot shows an application called “Presentation Builder”. It will be used by sports coaches to assemble presentation videos for their teams to discuss previous matches or to study the next opponent.

Another project I worked on is called “AnimakerFX” (working title). This is a side-project I like to work on when I have time (which unfortunately currently is not the case). Here I also used the dark theme. In general I think the dark theme goes well with applications that are used to produce visually rich content. The dark theme makes sure that the user’s focus remains on the content.

So how can we do this in JavaFX? By simply setting a new value in CSS for the “-fx-base” variable. This variable is part of the default modena.css stylesheet and it is the “base” for various other color constants. Below you can see how -fx-base is defined in Modena and how other colors are derived from it:

.root {
    /***************************************************************************
     *                                                                         *
     * The main color palette from which the rest of the colors are derived.   *
     *                                                                         *
     **************************************************************************/

    /* A light grey that is the base color for objects.  Instead of using
     * -fx-base directly, the sections in this file will typically use -fx-color.
     */
    -fx-base: #ececec;

    /* A very light grey used for the background of windows.  See also
     * -fx-text-background-color, which should be used as the -fx-text-fill
     * value for text painted on top of backgrounds colored with -fx-background.
     */
    -fx-background: derive(-fx-base,26.4%);

    /* Used for the inside of text boxes, password boxes, lists, trees, and
     * tables.  See also -fx-text-inner-color, which should be used as the
     * -fx-text-fill value for text painted on top of backgrounds colored
     * with -fx-control-inner-background.
     */
    -fx-control-inner-background: derive(-fx-base,80%);
    /* Version of -fx-control-inner-background for alternative rows */
    -fx-control-inner-background-alt: derive(-fx-control-inner-background,-2%);
    ....
}

As you can see in the snippet above the -fx-base color is the base for the background color and the “inner” background color. All in all -fx-base can be found around 60 times inside the modena stylesheet.

In the stylesheets of our applications all we need to do now is to override -fx-base with a dark color like this:

.root {
    -fx-base: rgba(60, 63, 65, 255); // dark
}

The cool thing is that the text color is also dependent on this base color and Modena will pick a text color that has good contrast to the background color. As a result the application will end up using white for text. So we get this for free.

Obviously more fine-tuning will be needed to reach the final appearance but -fx-base will take us to our goal very quickly.

Happy coding everyone!

Invalid JavaFX Scroll Event Deltas?

BREAKING NEWS: this bug is now officially being tracked in the Java bug tracker.

I noticed today that the delta values provided by the JavaFX ScrollEvent object seem to be invalid at the end of the scroll event cycle. The absolute value of those delta values becomes bigger again even though they should end up in values around zero. I ran my tests on a Mac with the Magic Mouse and the Magic Touchpad. The values getting bigger causes stuttering in the UI, for example a swipe scroll inside the ListView will cause the ListView to finish the scrolling with a stutter at the end (see this video).

(Please notice that this is not relevant for mouse wheel scrolling as the mouse wheel will not continuously fire scroll events).

A typical output looks like this:

--- Scroll started ----
7.0001220703125 <-- first the values start to get bigger
10.0
13.000030517578125
12.0001220703125
12.0001220703125
13.000030517578125
12.0001220703125
13.000030517578125
12.0001220703125
11.00006103515625
10.0
9.000091552734375 <-- then the values are going down
9.000091552734375
8.000030517578125
8.000030517578125
7.0001220703125
7.0001220703125
6.00006103515625
6.00006103515625
6.00006103515625 <-- getting closer to zero (all good, normal so far)
14.000091552734375 <-- but now all of a sudden bigger values again
14.000091552734375 <--
13.000030517578125 <--
11.00006103515625 <--

The code below can be used to reproduce this issue. Simply start a scroll gesture with your touchpad or magic mouse on the label inside the window.

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class ScrollBugApp extends Application {

  @Override
  public void start(Stage primaryStage) throws Exception {
      Label label = new Label("Scroll On Me!");
      label.setAlignment(Pos.CENTER);
      label.setOnScrollStarted(evt -> System.out.println("--- Scroll started ----"));
      label.setOnScroll(evt -> System.out.println(evt.getDeltaY()));
      Scene scene = new Scene(label);
      primaryStage.setScene(scene);
      primaryStage.setWidth(200);
      primaryStage.setHeight(200);
      primaryStage.centerOnScreen();
      primaryStage.show();
 }

 public static void main(String[fusion_builder_container hundred_percent="yes" overflow="visible"][fusion_builder_row][fusion_builder_column type="1_1" background_position="left top" background_color="" border_size="" border_color="" border_style="solid" spacing="yes" background_image="" background_repeat="no-repeat" padding="" margin_top="0px" margin_bottom="0px" class="" id="" animation_type="" animation_speed="0.3" animation_direction="left" hide_on_mobile="no" center_content="no" min_height="none"][] args) {
      launch(args);
 }
}

If anyone knows of a work-around or a way to filter out those freak values at the end then please let me know.[/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]

JavaFX Real-World Apps: Monastery Disentis

[fusion_builder_container hundred_percent=”yes” overflow=”visible”][fusion_builder_row][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][fusion_text]

Finally the first “JavaFX Real World Apps” post that actually covers an “app” and not an “application”, meaning the first JavaFX application in this series that was designed for mobile devices and not the desktop. The application is simply called “Monastery Disentis”. It was developed by cnlab in Switzerland. It can be used by visitors of the monastery as a guide. Below you can see a couple of screenshots that were taken on an Android device.

Video: a screencast of the application.[/fusion_text][fusion_text]What is cool about this application is that everybody can try it out be following the links to the app stores, either the Apple App Store for iPhone users or Google Play for Android.

As usual I asked the development team a couple of questions and Daniel Zimmermann was nice enough to answer them below:

General Questions

What is the name of your product / project?

Monastery Disentis

Who are your users / customers?

Monastery of Disentis, Mustér, Switzerland.

What is the purpose of your software? What are its benefits?

Mobile app to guide the user through the monastery church.

Is the application operational? If yes, since when. If not when do you plan to go live?

Yes. It can be installed via the iTunes app store or Google play.

iTunes: https://itunes.apple.com/ch/app/hora-benedicti/id930800749?l=en&mt=8

Google Play: https://play.google.com/store/apps/details?id=ch.cnlab.horabenedicti

Development

How did you get the necessary JavaFX Know-How into your team? (Consultants, Internal / External training courses)?

Internal training.

With which version of JavaFX did you start? 1, 2, 8?

We started with version 8.

When did you start developing the application and how long did it take?

September, 2016, 6 Month with some pauses in between.

How many developers worked on it? In total and on the UI.

2 Developers in total. 1 exclusively on the UI.

How big is the application? Lines of code, Number of classes.

Lines of Code: 11000, No. of Classes: 113.

How big is the JavaFX client? Lines of code, Number of classes.

Lines of Code: 7500, No. of Classes: 51

Why did you choose JavaFX as frontend technology? And very importantly: why did you not choose HTML / Web?

The developer already knew Cordova, but wanted something else. The app‘s scope
seemed small enough to be used for it.

Was it difficult to convince decision makers to agree on JavaFX?

No. Since so we did not need to create two native apps with two developers.

What were the biggest challenges / problems / issues / bugs you faced in the JavaFX part and how did you solve them?

Rendering performance of Text nodes – heavily relied on asynchronous content loading and
lazy content display (in other words: lazily put it onto the Scene Graph).

Which 3rd-party products / frameworks / tools (open source and commercial) did you use and why did you choose them?

JavaFXPorts, Gluon Charm Down, ControlsFX, FontawesomeFX, jackson, commons-codec, Afterburner.fx, ScenicView.

Did you mix JavaFX and Swing code?

No.

Outlook

Would you use JavaFX again for your next project? Please elaborate why or why not.

Yes, but I will think twice for mobile, because the performance is not yet where it needs to
be on all platforms / phone variants.

Which recommendations do you have related to JavaFX for other companies / projects?

Not much, except for: Just give it a try. If you need platform independent Desktop
applications and/or don‘t want to rely on long-term browser support, this is a good and
good-looking alternative.

Which features would you like to see being added to JavaFX?

CSS closer to Web, faster CSS, improved layouting/API, faster text rendering performance.

[/fusion_text][/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]

Interview on jaxenter.de

I was interviewed by Hartmut Schlosser of jaxenter.de last week and this week the article was published (in German) on their website. You can find it here: https://jaxenter.de/javafx-java9-javascript-56083. The interview was embedded in the “JavaFX Sixpack” series that tries to evaluate the potential of JavaFX. Hartmut was kind enough to also include information on my two commercial JavaFX frameworks CalendarFX and FlexGanttFX.

JavaFX Animation Tool

[fusion_builder_container hundred_percent=”yes” overflow=”visible”][fusion_builder_row][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][fusion_text]Ok, I guess it is time to let you in on a little secret. The last three months or so I worked on a private project with the goal to create a tool that would allow me to easily create animations for Java desktop applications. JavaFX contains fantastic support on the API level for doing animations but for beginners or even intermediate level programmers it is not trivial to leverage it. However, when I use Apple’s Keynote for creating presentation slides, or when I see the animation / slider plugins for WordPress I realize how easy it can be to do animations, so why not bring the ease of these tools to JavaFX. What you can see in the screenshot below is the result of my work so far.

This is still at an early stage and things are subject to change but the basic idea is this: the output of the tool will be a presentation consisting of several slides. Each slide contains one or more elements. Element types are: region, node (code or fxml), images, and videos (more most likely to come). Each element can have any number of transitions associated with it. The background of the slides can be an image or a video or both. The image below shows a presentation with a background video, and three videos on top of it. Video playback starts when the user presses the green “play” button. However, the start of each video can be delayed by moving the “play” transitions further to the right / to the future, hence adding an initial delay.

It took me 60 seconds to create this second example, just to give you an idea on how much time you can save by using a tool.

Ok, that’s all for now. I hope I will find time to continue work on this tool and maybe present it at JavaOne this year. That is if Trump has resigned before then 🙂

Happy coding everyone!

 

P.S.: below you will find two YouTube videos showing the tool in action

[/fusion_text][fusion_text]Video 1, Video 2[/fusion_text][/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]

JavaFX Tip 25: Use FXSampler!

The Problem

As a framework developer it is essential to have an easy way to individually test the appearance of and the interaction with each custom control. I really hate it when I first have to open five different screens before I finally get to my new control so that I can test it. Not only is it annoying but it also costs too much time. When doing UI work you constantly make changes to your controls and look at the impact of those changes. If a single change roundtrip (code, launch, test) takes 5 minutes then you can only squeeze 12 change iterations into an hour, making slow progress. If it takes 1 minute then you are looking at 60 iterations and fast progress. As simple as that.

The Solution

Luckily the ControlsFX project contains a very nice subproject called FXSampler, which is a generic sampler application for any JavaFX framework. I am currently using it for FlexGanttFX and CalendarFX. The screens below show the individual CalendarFX samples in a hierarchical tree structure on the left-hand side. The selected sample shows up in the center pane. In this case it is showing the view used for visualizing a calendar entry on a weekday. The property sheet on the right-hand side allows the user to edit the properties of the selected control. It should be noted that the right-hand side can show any kind of control for interacting with the sample, it doesn’t have to be a property sheet. However, very often the property sheet is the fastest way of coming up with a good way of manipulating the control.

The center pane has several tabs. The first one shows the actual sample. The second one displays the javadocs / API of the control. Ideally each sample shows exactly the API of the featured control and not just the index page of the entire framework API. Which page gets loaded into this tab can be configured individually for each sample.

The next tab is used for showing source code. This can be any code that you find relevant for the sample but in my case I always show the code of the sample itself.

Tab number four contains CSS styling information that is relevant for the selected sample. If your control overrides the getUserAgentStylesheet() method then the tab should display the stylesheet that is returned by this method. In CalendarFX all controls inherit from CalendarFXControl which does override this method and always returns “calendar.css”. So in this case there is only a single large CSS file and that is what is being displayed here.

The Setup

For my frameworks and projects I usually work with a multi-module Maven setup and add a separate module just for the samples. The pom.xml file of this module has to contain a dependency to FXSampler like this:

[fusion_builder_container hundred_percent=”yes” overflow=”visible”][fusion_builder_row][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”]

<dependency>
   <groupId>org.controlsfx</groupId>
   <artifactId>fxsampler</artifactId>
   <version>1.0.9</version>
</dependency>

The next thing needed is a class that represents the sampler project. The class has to implement the fxsampler.FXSamplerProject interface. It is used to specify a project name, a base package, and a welcome page. The code below shows the implementation of this interface as it was done for CalendarFX.

[/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”]

package com.calendarfx.demo;

import fxsampler.FXSamplerProject;
import fxsampler.model.WelcomePage;

public class CalendarFXSamplerProject implements FXSamplerProject {

   @Override
   public String getProjectName() {
      return "CalendarFX";
   }

   @Override
   public String getSampleBasePackage() {
      return "com.calendarfx.demo";
   }

   @Override
   public WelcomePage getWelcomePage() {
      return new CalendarFXSamplerWelcome();
   }
}

Welcome Page

The welcome page is optional and allows you to specify a title for the sampler and to show a UI that will be presented to the user when the sampler application starts up. The CalendarFX sampler shows a simple “about message”.

Base Package

FXSampler will use the “base package” to find all classes that are samples. FXSampler will place the samples found in the base package at the top of the navigation tree on the left-hand side of its window. Samples found in sub packages will end up in a tree node. The image below shows the package structure of the CalendarFX sampler project.

The base package for CalendarFX is com.calendarfx.demo and because the “day entry view” sample was found inside the entries package it means that the sample will be displayed in a tree node called “Entries”. The next image shows how the navigation tree reflects the package structure.

You will notice that the samples are all prefixed with “Hello…”. This is simply a convention I inherited from the ControlsFX project. There is no technical reason for it.

The Samples

A class becomes a sample if it implements the fxsampler.Sample interface. But it is even better if the class extends from fxsampler.SampleBase. The clever thing about this class is that it extends from Application, which means that each sample can also be run standalone.

A sample defines / contains the following things:

  • The name of the sample (in our example “Day Entry View”).
  • A short description of the sample / the control (what does it do? what is it used for?).
  • The name of the project that is belongs to.
  • The project version (e.g. 8.4.0).
  • A node that will be placed in the center pane and that displays the custom control.
  • A control panel for manipulating / interacting with the sample (right-hand side, often a property sheet).
  • The position of the control panel divider handle (based on the width requirements of the control panel).
  • The URL to the JavaDocs (I always point to the docs on my server).
  • The URL to the stylesheet that is relevant for the sample.
  • The URL to the source code of the sample.
  • A flag to indicate if the sample is currently visible (good for hiding samples that are still work-in-progress).

The Launcher

To run the sampler project we need a class with a main() method that extends the JavaFX Application class. Luckily FXSampler ships a class called fxsampler.FXSampler. For CalendarFX it looks like this:

[/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”]

package com.calendarfx.demo;

import fxsampler.FXSampler;
import javafx.stage.Stage;

public class CalendarFXSampler extends FXSampler {

   @Override
   public void start(Stage primaryStage) throws Exception {
      super.start(primaryStage);
   }

   public static void main(String[] args) {
      FXSampler.main(args);
   }
}

You will notice that the launcher does not reference / instantiate any specific sampler project. You would normally expect to see the  launcher create an instance of CalendarFXSamplerProject but its’ main() method simply delegates to the main() method of FXSampler. So how does it find anything?

The Service Provider

The answer is simple but not something that every Java developer has encountered in their day to day coding routine. FXSampler finds the sampler project because it will be registered as a “service provider”. This is done by adding a file to the directory META-INF/services. The file name has to be fxsampler.FXSamplerProject. Inside the file we add the full class name of the sampler project. FXSampler can now lookup all service providers that implement the FXSamplerProject and instantiate them. This allows FXSampler to show the samples found in several JARs at the same time. If I wanted to I could create a single application showcasing the samples found in FlexGanttFX, CalendarFX, and ControlsFX at the same time. The image below shows the location of the service provider file and its content inside the CalendarFXSampler module.

The Executable

When you download CalendarFX or FlexGanttFX you will see that the distributions include the sampler projects (inside “demos” folder). They were added as executable / runnable JAR files. The required Maven configuration for building them looks like this:

[/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”]

<build>
   <plugins>
      <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
         <version>2.4</version>
         <configuration>
            <finalName>sampler-demo</finalName>
            <appendAssemblyId>false</appendAssemblyId>
            <descriptorRefs>
               <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
            <archive>
               <manifest>
                  <mainClass>com.calendarfx.demo.CalendarFXSampler</mainClass>
               </manifest>
            </archive>
         </configuration>
         <executions>
            <execution>
               <id>make-samples</id>
               <phase>package</phase>
               <goals>
                  <goal>single</goal>
               </goals>
            </execution>
         </executions>
      </plugin>
   </plugins>
</build>

Conclusion

I highly recommend using FXSampler and making it a habbit to add a sample for every custom control you write, no matter if you are a working on a framework or an application. The benefits of being able to quickly test a control in a controlled environment greatly outweighs the overhead of creating and maintaining the sample.

Happy coding everyone![/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]

JavaFX Tip 24: Custom Layouts for Performance and Flexibility

I just finished a two month sprint on advancing CalendarFX and getting it ready for release 8.4.0. One focus of this sprint was on performance. There are many things that can influence performance but when it comes to JavaFX the number of nodes in your scenegraph and CSS styling are top candidates for optimisation. After reviewing the custom controls that ship with CalendarFX I realized that many of them used a lot of nested panes (BorderPane, VBox, HBox, GridPane) in order to achieve a specific layout. Nested panes result in a high node count and complex CSS styling instructions.

One simple example are the views that CalendarFX creates to visualize calendar entries in the DayView control. This control shows the 24 hours of a day vertically and places DayEntryView instances on them. These entry views look like this:

day-entry-view

In the previous releases of CalendarFX the skin of the entry view used a VBox instance to lay out the two labels that show the title of the entry and its start time. That was the only purpose of the VBox. Doesn’t sound like a big issue but when your application starts to show hundreds of those entries then you end up creating hundreds of VBox instances, too.

The way to avoid this is to mange the positioning of these labels yourself and to implement / override the layoutChildren() method of the skin. Not only do we save one node but it also gives us more flexibility. We can now decide to hide or show the labels based on the available space. In the case of the DayEntryView we can decide to hide the start time label if the available height of the view is not big enough to show both labels. This kind of, may I dare to say it, “responsiveness” is not possible when using the out-of-the-box layout panes that are shipping with JavaFX.

The code of the layoutChildren() method of DayEntryViewSkin can be seen below.

[fusion_builder_container hundred_percent=”yes” overflow=”visible”][fusion_builder_row][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”]

    @Override
    protected void layoutChildren(
                               double contentX, 
                               double contentY, 
                               double contentWidth, 
                               double contentHeight) {

        // Title label.
        double titleHeight = titleLabel.prefHeight(contentWidth);

        // It is guaranteed that we have enough height to display 
        // the title (because "computeMinHeight" returns the min
        // height of the title label).

        titleLabel.resizeRelocate(
                snapPosition(contentX), 
                snapPosition(contentY), 
                snapSize(contentWidth), 
                snapSize(titleHeight));

        // Start time label (only show it when there is enough space).

        double timeLabelHeight = 
                           startTimeLabel.prefHeight(contentWidth);

        if (contentHeight - titleHeight > timeLabelHeight) {

            // make sure to set visibility to true again
            startTimeLabel.setVisible(true);

            startTimeLabel.resizeRelocate(
                    snapPosition(contentX), 
                    snapPosition(contentY + titleHeight), 
                    snapSize(contentWidth), 
                    snapSize(timeLabelHeight));

        } else {
            // Not enough space, hide the start time label.
            startTimeLabel.setVisible(false);
        }
    }

The nice thing about the layoutChildren() method is that it tells you exactly which space it is that your children nodes can use. The space is given by the four parameters contentX, contentY, contentWidth, and contentHeight. So there is no need to first lookup things like insets or padding. The “content” rectangle is the space that is available to you.

The second nice thing when writing your own layoutChildren() method is that you can utilize the snapXYZ() methods provided by the SkinBase superclass. These methods ensure that the child nodes will be sized and placed in such a way that they will appear crisp and not blurry. Why is this needed? Because JavaFX uses double precision coordinates to place nodes and unfortunately “int” coordinates are actually located between pixels on your display. So the snapPosition() method might take your x / y coordinate of 100 / 100 and change it to 100.5 / 100.5.

As mentioned before, the DayEntryView is a simple example. Obviously you can also create very complex layouts by overriding the layoutChildren() method. Did I always do this in the current release of CalendarFX? No, I did not. Very often I exchanged all those nested panes with instances of type GridPane, which does give you a lot of layout options but unfortunately no support for responsiveness.

Hope this has been helpful for some of you.

Happy coding![/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]

CalendarFX 8.4.0 Released

I would like to inform you that version 8.4.0 of CalendarFX has seen the light of day today. You can download it here. The first thing you will notice is the different version scheme. CalendarFX now uses the target Java version as its first number. In this case 8. With Java 9 lurking around the corner there will be a Java 9 compatible version soon which will start with number 9. Even though this is a new major release the current license keys will continue to work.

screen-shot-2017-01-31-at-18-09-43

Anyone planning to upgrade to this release should be aware that there have been quite a few changes in the structure of the controls and their CSS styling. All of these changes were made to improve the framework, especially performance. Please make sure to read the CHANGES.txt file. You will most certainly have to invest a day or two to execute the upgrade.

If you find yourself having trouble upgrading then please use the CalendarFX forum on dlsc.com to ask for support.

Major new features in 8.4.0:

  • Printing support: a new control called PrintView has been added. It is already integrated with the CalendarView class, so anyone using this control will have a whole new user experience when trying to print.
  • Now using a responsive layout in the “day” page of the CalendarView control.
  • New control “MonthSheetView” for showing multiple months in a column layout.
  • New control “DetailedDayView”: a “DayView” with chrome (time scale, calendar headers, all day view, scrollbar, etc…)
  • New control “DetailedWeekView”: a “WeekView” with chrome just like DetailedDayView.
  • New control: “ButtonBar”: for showing segmented buttons.
  • New control: “DayViewScrollPane”: for custom scroll pane behaviour that not only knows how to scroll the embedded day view but also changes its properties so that the current time range stays visible when the scrollpane gets resized.
  • and so on ….

More detailed blog posts will follow in the next couple of weeks with information on the new controls and the overall changes.

I hope you will enjoy the release and that you will let me know about any issues you encounter.

JavaFX Talks @ JUG Poznan

[fusion_builder_container hundred_percent=”yes” overflow=”visible”][fusion_builder_row][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][fusion_text]This week I had the pleasure to give my JavaOne 2016 presentations at JUG Poznan in Poland. I compressed all three talks into a two hour talk and I think it worked out well and gave the attendance a good idea what can be accomplished with JavaFX technology. Sebastian Pozoga, a member of JUG Poznan, recorded the session and made it available on YouTube. So if you are interested in “JavaFX vs. Swing”, “JavaFX Real World Applications” or “JavaFX Tips & Tricks” then check them out. Again, thank you to PSI Poland for sponsoring this trip.[/fusion_text][/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][fusion_youtube id=”gZIedbPdXRM” width=”” height=”” autoplay=”no” api_params=”” class=””/][/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][fusion_youtube id=”RwrEz6MG7eY” width=”” height=”” autoplay=”no” api_params=”” class=””/][/fusion_builder_column][fusion_builder_column type=”1_1″ background_position=”left top” background_color=”” border_size=”” border_color=”” border_style=”solid” spacing=”yes” background_image=”” background_repeat=”no-repeat” padding=”” margin_top=”0px” margin_bottom=”0px” class=”” id=”” animation_type=”” animation_speed=”0.3″ animation_direction=”left” hide_on_mobile=”no” center_content=”no” min_height=”none”][fusion_youtube id=”gZIedbPdXRM” width=”” height=”” autoplay=”no” api_params=”” class=””/][/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]