CalendarFX goes Open Source

I am happy to announce that CalendarFX has found a new home on GitHub. As of today it is no longer a commercial product but an open source project. Over the last two years I have noticed that the developer community has resisted to use CalendarFX for their projects as the source code was not freely available. So now that CalendarFX has been released into the wild I am hoping that it will live a long and happy live.

Advertisement

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

New CalendarFX View: MonthGridView!

Me and my team have recently begun work on a new view for CalendarFX with the initial goal to display a whole year in vertical columns. The name of the view is MonthGridView. As usual the goal has changed slightly while coding. The view is now capable of displaying any number of months with extra months added in front or in the back. Now, for example, the developer can choose to display six months (a semester) with one month “padding” in front and one month in the back.

The following screenshot shows an entire year with no padding.

Screen Shot 2016-04-06 at 09.57.19

In planning and scheduling applications it is often the case that the person using the software wants to quickly compare the same weekdays with each other (e.g. “see resource utilisation on Mondays”). To make this easier the new view also supports a layout option where the same weekdays are aligned. It looks like this:

Screen Shot 2016-04-06 at 10.02.44

As mentioned above, the view can display any number of months with any number of “padding” months. The screenshot below shows a six month period with one month padding on each side (the styling of the extra months still needs some work :-))

Screen Shot 2016-04-06 at 10.14.13.png

The screenshots do not show any calendar information, yet. This part is still work in progress.

If you have any suggestions for features that you would like to see in this view then please leave a comment.

 

CalendarFX 1.3 Released Today!

I have released a new version of CalendarFX today. Version 1.3 contains several small bug fixes, important memory leak fixes, and most importantly a big fix for correctly displaying different “first day of week” (e.g. Mondays in Germany, Sundays in the US). The new release can be downloaded as usual at http://www.calendarfx.com. Please take it for a spin and let me know what you think.

Bildschirmfoto 2016-03-20 um 13.31.54

CalendarFX is a UI framework for JavaFX 8. It contains several custom controls for visualizing standard calendar information (day, week, month, year view). CalendarFX is a commercial framework that is available for licensing.

Cool: JavaFX in the Browser!

I had a nice long talk today with the guys from Sandec (sandec.de). They were showing me their product called “Centralized Java (CJ)”. With this solution it is actually possible to run a JavaFX application in a browser (for now it works best with Chrome).

The website javafx-samples.com shows several demos that are using this technology. The demos include the JavaFX SceneBuilder, the game 2048, the JavaFX Ensemble demo suite. It is amazing how much of these applications is supported by CJ. There are still a few gaps but the folks at Sandec are planning to close them soon.

calendarfxsample3

CalendarFX running inside Chrome

CJ hosts the application on the server and serializes the JavaFX scene graph. The graph is then sent to the browser and recreated by JavaScript. So you basically end up with a JavaScript rendering engine for JavaFX. Very cool!

CJ even supports a mode called “MultiView”. With this it is possible to share a session with several people, very similar to (for example) TeamViewer.

CJ is one step more for fulfilling the vision that the same code base can be used for any client.

Edit: I have uploaded a video to YouTube showing CalendarFX running in Chrome.