JavaFX custom controls

Post to Twitter

We started with our JavaFX UI in January and we are on the home stretch!
All features were implemented and we have some Feature Requests and known Bugs in our Ticketing system and some open Issues in the JavaFX ticketing system (JIRA, at the moment).

At the beginning we thought that 2 months will be sufficient to implement the whole UI :) We were very optimistic but not far away from the reality but we didn't know that JavaFX had a lot of missing pieces.

Missing pieces?

Don't get me wrong, because JavaFX is an awesome UI toolkit and will be a perfect replacement for Swing, but it needs some real world applications. Yes, applications and not fancy hello world examples. Sure, there are some great applications but most use custom controls because of problems with standard controls. The overall performance is still not perfect and there's still a lot of tuning potential. Currently a swing application acts faster without delays.

The biggest problem for us was that standard controls like Toolbar, Menus didn't work as expected and other controls like DesktopPane or Internal Frame weren't available. We didn't find a date + time combobox editor. Some standard controls like Button, CheckBox or RadioButon didn't offer specific alignment options and another problem was the coding philosophy because many useful methods are public final or private. You can't replace internal listeners or remove internal listeners because you can't access all list elements.

But this article shouldn't cover our development problems because many of them will be solved with Java8 u60 and we have custom controls for the rest. Currently we have many useful classes for our UI and also for you, because we tried to implement all extensions independent of JVx. This article gives a short overview.

Re-usable controls and classes

We have some additional classes without images:

  • FXNullPane

    Acts like a Swing panel with null layout.

  • FXSceneLocker

    From the javadoc: The FXSceneLocker is a static helper utility that allows to to lock a Scene, meaning that only events that belong to the locking Node or its children are processed. If a Scene is locked by multiple Nodes, that last one does receive events.

You'll find all other utilities and controls in the dev repositoriy. The ext Package is independent of JVx. We use it as base for our UI implementation.

JavaFX + Android + Live Preview

Post to Twitter

We had a lot of fun this week - with JavaFX :)

My last article was about JavaFX on mobile devices with JavaFXPorts. It was awesome that JavaFX worked without bigger problems on mobile devices but the number of needed re-deployments was high. The app build process needs some time (~2-3 mins) and if you do a lot of UI related changes in your application (CSS, layout, ...) you lose development time.

How to save deployment time?

Simply don't deploy!

We have our product VisionX and it has a Live Preview for applications while developing. Our idea was that we could use the existing functionality to show changes on mobile devices immediately. It should work with Android devices because dynamic class loading is possible with custom classloaders.

But as so often, things won't work as expected.

Android has support for URLClassLoader but it doesn't work because the implementation is "legacy" . This means that loading classes with URLClassLoader didn't work. Android has a DexClassLoader!

The DexClassLoader works great if you have the archive on the device. But it has no support for remote class loading. The other thing was that DexClassLoader needs a jar that contains a classes.dex archive. The classes.dex contains all class files (in dex format).

The first problem was: How to create the DEX archive?

Not too hard because Android comes with dx.bat and dx.jar. It's super easy to convert a jar file or a classes folder to a dex archive. After the hardest part was solved, it was simple to implement remote class loading with Android, for our JavaFX application! If you need more information, leave a comment!

Here's the result of our Live Preview experiment as Video:

Window shutter web control

It works great and reduces deployments to a bare minimum: 1

JVx' JavaFX UI with JavaFXPorts

Post to Twitter

A few hours ago, we published a screenshot from our Demo ERP application running on Nexus 9 (an Android tablet).
It wasn't a fake!

Before we'll show you more screenshots, we want say that we've reached a long awaited goal!

Use JVx and write an application for all polpular platforms and devices.
This is real "write once run anywhere".

Create an application for Windows, Linux, Mac, iOS, or Android, PS4, OUYA or WiiU. Run it as desktop application, as html5 application in web browsers, as native iOS or Android application or as JavaFX application on Android and iOS devices. There's nothing like JVx in the world - not with only one framework with such a small footprint as JVx and certainly not Open Source!

Here are the screenshots:

Maximized frame with charts

Maximized frame with charts

Frame with tree

Frame with tree

Also in portrait mode:

Portrait mode

Portrait mode


And now a very strange one. It's the application with our styled stage. It's crazy because you can drag the window around (makes no sense, but it just works):

Styled stage with tabset desktop

Styled stage

Sure, the application wasn't optimized for mobile devices. It has the same style as the desktop application. The mobile version should have bigger frame buttons and a bigger frame header :) To be honest - MDI on mobile devices? We were positively surprised about the usability. But, whatever. You have the option and decide what's best for your application (but please don't use MDI for smartphones).

Are you interested in some details?

We've used Netbeans IDE because there's a very useful plugin from gluon. We're Eclipse users but it was easier to use a preconfigured environment without doing everything manually. It was simple to configure Netbeans with gluon plugin and there's a video for your first steps. A "bigger" problem was gradle because the project was a gradle project and we've never used gradle. We love using ant.

We had a bad start with Hello World application because it didn't work. There were different problems: Missing ANDROID_HOME or DEX compiler problems. After reading the documentation it was possible to start compilation. The DEX problem was very strange because we had JVM 1.8 u31 and JVM 1.8 u40 configured in Netbeans, but Netbeans didn't use our configured JVM 1.8 u40. We removed the JVM 1.8 u31 from Netbeans and after that we successfully compiled our Hello World application. Very strange!

The next step was using JVx as library dependency for our project, but how did this work with gradle? We had the library in the libs directory of the project, in the file system. We didn't use a maven lib because it was easier to replace the library after recreation. We tried to find a solution in the official gradle documentation and found Chapter 51. C'mon gradle is a build tool and not a programming language! So much documentation means: complexity. Sure, ant wasn't the holy grale but it it's simple to understand and doesn't hide anything.

Our current gradle script:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.0.0-b7'

    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')
}

mainClassName = 'com.sibvisions.gluon.JVxGluonApp'
   
jfxmobile {
   
    ios {
        forceLinkClasses = [ 'com.sibvisions.gluon.**.*' ]
    }
   
    android {
      androidSdk = 'C:/tools/android/android-sdk_r04-windows'
      compileSdkVersion = 21  
    }
}

It's short but we ddin't know what happened behind the scenes without additional research. But if it works it's good enough for many developers.

The integration of JVx was simple because JVx was compiled with JVM 1.6. The Dalvik VM or DART do support 1.6 and 1.7 syntax. It was cool to see that JVx and especially the communication worked without problems - Great job from Johan Vos and all people behind JavaFXPorts!

Our next step was the integration of additional dependencies like our JavaFX UI. It was based on JVM 1.8 u40 and heavily used lambdas. But lambda expressions weren't supported from Dalvik or ART. We thought that gluon plugin solves the problem for us, but it didn't. It contains retrolambda but only for project source files and it doesn't touch your dependencies. There was no additional gradle build task for that, so we had to convert the libs manually. Not a problem but you must be aware of it.

After we solved all dependency problems, we had the first version of our desktop ERP running on our android device. But don't think everything was trouble-free. We had problems with method references, Java Preferences because of write problems, new Date API, forEach calls, scene size and much more. We did solve most problems but not all - yet.

Charts with JVx and JavaFX

Post to Twitter

In my last article about JavaFX, JVx and data binding you saw a first impression of our chart binding. We have additional screenshots for you. The first two images show a Swing application with different charts. The next two images show the same application, with JavaFX. Which UI do you like more?

Bar chart with Swing

Bar chart with Swing

Line chart with Swing

Line chart with Swing

Bar chart with JavaFX

Bar chart with JavaFX

Line chart with JavaFX

Line chart with JavaFX

The JavaFX UI is clean and fresh. It looks modern compared to Swing. A desktop application should look modern and not dusty!

How about the data binding?

Our screen has two charts. Every chart gets its records from a data book (our model class). The labels and values are dynamic and every change in the databook updates the chart. Here's the source code for the chart definition:

//BAR chart
UIChart chartBar.setChartStyle(UIChart.STYLE_BARS);
chartBar.setTitle("Annual Statistics");
chartBar.setXAxisTitle("Year");
chartBar.setYAxisTitle("Grosstotalprice");
chartBar.setDataBook(rdbV_statistic_order_offer_year);
chartBar.setXColumnName("YEAR_");
chartBar.setYColumnNames(new String[] {"OFFER_GROSSTOTALPRICE", "ORDER_GROSSTOTALPRICE"});

//LINE chart
UIChart chartLineArea.setChartStyle(UIChart.STYLE_LINES);
chartLineArea.setTitle("Monthly Statistics");
chartLineArea.setXAxisTitle("Month");
chartLineArea.setYAxisTitle("Grosstotalprice");
chartLineArea.setDataBook(rdbV_statistic_order_offer_month);
chartLineArea.setXColumnName("MONTH");
chartLineArea.setYColumnNames(new String[] { "OFFER_GROSSTOTALPRICE", "ORDER_GROSSTOTALPRICE" });

The complete source code is available on sourceforge. It's from our Demo ERP application.

The databooks are remote databooks because our Demo ERP is a 3-tier application. The databook definition:

//BAR Chart
RemoteDataBook rdbV_statistic_order_offer_year = new RemoteDataBook();
rdbV_statistic_order_offer_year.setName("v_statistic_order_offer_year");
rdbV_statistic_order_offer_year.setDataSource(getDataSource());
rdbV_statistic_order_offer_year.setReadOnly(true);
rdbV_statistic_order_offer_year.open();

//LINE Chart
RemoteDataBook rdbV_statistic_order_offer_month = new RemoteDataBook();
rdbV_statistic_order_offer_month.setName("v_statistic_order_offer_month");
rdbV_statistic_order_offer_month.setDataSource(getDataSource());
rdbV_statistic_order_offer_month.setReadOnly(true);
rdbV_statistic_order_offer_month.setMasterReference(
                                      new ReferenceDefinition(new String[] { "YEAR_" },
                                                              rdbV_statistic_order_offer_year,
                                                              new String[] { "YEAR_" }));
rdbV_statistic_order_offer_month.open();

Both remote databooks are connected to a remote storage, identified by name (v_statistic_order_offer_year, v_statistic_order_offer_month). The storages are defined as server objects:

//Name: v_statistic_order_offer_year (BAR CHART)
DBStorage dbsV_statistic_order_offer_year = new DBStorage();
dbsV_statistic_order_offer_year.setWritebackTable("v_statistic_order_offer_year");
dbsV_statistic_order_offer_year.setDBAccess(getDBAccess());
dbsV_statistic_order_offer_year.open();

//Name: v_statistic_order_offer_month (LINE CHART)
DBStorage dbsV_statistic_order_offer_month = new DBStorage();
dbsV_statistic_order_offer_month.setWritebackTable("v_statistic_order_offer_month");
dbsV_statistic_order_offer_month.setDBAccess(getDBAccess());
dbsV_statistic_order_offer_month.open();

Both storages read data from database views (instead of tables). The views are not magic and could also be simple tables, but our Demo ERP has views for demonstration purposes.

Here's the definition of the view, used for the BAR chart:

CREATE OR REPLACE VIEW v_statistic_order_offer_year AS
SELECT ofe.YEAR_ AS YEAR_,
       sum(ofe.GROSSTOTALPRICE) AS OFFER_GROSSTOTALPRICE,
       sum(case when ord.GROSSTOTALPRICE IS NULL
                then 0
                else ord.GROSSTOTALPRICE
           end) AS ORDER_GROSSTOTALPRICE
  FROM (v_statistic_offer ofe
        LEFT JOIN v_statistic_order ord
               ON (((ofe.YEAR_ = ord.YEAR_) AND (ofe.MONTH = ord.MONTH))))
 GROUP BY ofe.YEAR_;

That's it. It's really simple to bind a JavaFX chart to a database table or view.

Style vaadin menubar popups

Post to Twitter

Our new application frame has two different vaadin menubars. One for the application menu and one as "hidden" menubar for the user options.

Here's a merged screenshot of both menubars:

Menubar popup

Menubar popup

As you can see, the left popup is dark and the right popup is bright. Usually, vaadin doesn't allow custom "additional" style definitions for menubar popups. The default style name is:

v-menubar-popup

The name is defined in the class com.vaadin.shared.ui.menubar.MenuBarState as

primaryStyleName = "v-menubar"

If you want to add an additional style class, it's simply not possible because the client implementation (com.vaadin.client.ui.VMenuBar) sets the primary style name, from the menubar, as style name for the popup overlay. The only thing you can do is, to change the primary stylename of your menubar. The problem is that you have to define all styles for the menubar-popup and menuitems, submenus, ... again in your style file. We tried it but it was horrible because you can't easily change the theme.

We tried to find a solution without changing vaadin client. We tried to set a primary style name as e.g. customstylepopup v-window-popup. But the client menu implementation has following code in getPrimaryStyleName:

protected static String getStylePrimaryName(Element elem) {
  String fullClassName = getStyleName(elem);

  // The primary style name is always the first token of the full CSS class
  // name. There can be no leading whitespace in the class name, so it's not
  // necessary to trim() it.
  int spaceIdx = fullClassName.indexOf(' ');
  if (spaceIdx >= 0) {
    return fullClassName.substring(0, spaceIdx);
  }
  return fullClassName;
}

(it makes sense to do this!)

So, it wasn't possible with simple tricks. The only solution - we found - was an extension of VMenuBar to override getPrimaryStyleName and return a custom style class concatenated with the default style class, something like this:

@Override
public String getStylePrimaryName()
{
    if (popupStyle != null)
    {
        return popupStyle + " " + super.getStylePrimaryName();
    }
       
    return super.getStylePrimaryName();
}

It wasn't our preferred solution, but we had another hack for setting ids of menu items. So it wasn't hard to add another hack for the style name :)

With our modification, it'll be possible to add custom style classes to menubar popups:

Custom style names

Custom style names

The source code is available on sourceforge.

ARC Welder - what else :)

Post to Twitter

Some days ago, ARC Welder popped up in the news. I guess it was Thursday?

What is ARC? (see Getting started with ARC)

The App Runtime for Chrome (Beta), or ARC, lets you run your favorite Android apps on Chrome OS.

and also in your Chrome browser.

It's strange, but a logical consequence.

We tried our native Android client with ARC Welder and it was working without bigger problems:

ARC Welder - JVx Android Client

ARC Welder - JVx Android Client

It wasn't possible to use the integrated MAPS API, maybe a problem of the beta version or our build?

I'm not sure if it's useful to run an android app on a desktop because the app was designed for mobile devices, usually. But as test environment...

But it could be interesting for JavaFX applications which were converted to Android apps? Not really for desktop pcs, but for Chromebooks.
While Applets will be banned from browsers, ARC could be something similar :)

It's still strange but we'll be ready for it.

JavaFX, JVx and data binding

Post to Twitter

We made great progress with our JavaFX UI for JVx. The whole UI stuff was already implemented and worked with some known problems. The next thing was data binding because this should fill the gap between UI and business logic. This means: bindings for a table, tree, chart, editors, cell editors, cell renderers, ... (hard work).

The data controls of JavaFX were very useful and we didn't implement our own controls because standard controls were working. Sure, we had a different model in JVx than the "model" in JavaFX, but also Swing and vaadin had different models. We're experts in such things.

We started with the table, because a table implementation should be easy without CRUD operations and of course, it was easy. The next thing was the integration of our cell renderers and cell editors because a date field should automatically use a date editor and a number field should use a number(only) editor. The same applies for checkboxes and comboboxes. This was a hard job because JavaFX' table had different concepts than e.g. swing. We're still working on the last bits but most functionality was implemented.

It's already possible to bind a database table/view to a JavaFX TableView without additional JDBC, ORM. Thanks to JVx, this works with all supported architectures (mem, 2-tier, 3-tier). Here's a first impression, followed by the source code:

TableView bound to JVx' DataBook

TableView bound to JVx' DataBook

UITable table = new UITable();
table.setDataBook(dataBook);

UIFormLayout editorsPaneLayout = new UIFormLayout();
editorsPaneLayout.setNewlineCount(2);

UIPanel editorsPane = new UIPanel();
editorsPane.setLayout(editorsPaneLayout);

addEditor(editorsPane, dataBook, "ID");
addEditor(editorsPane, dataBook, "BOOLEAN");
addEditor(editorsPane, dataBook, "STRING");
addEditor(editorsPane, dataBook, "CHOICE");
addEditor(editorsPane, dataBook, "DATETIME");
addEditor(editorsPane, dataBook, "NUMBER");
addEditor(editorsPane, dataBook, "TYPE_ID");
addEditor(editorsPane, dataBook, "TYPE_NAME");

UISplitPanel splitPanel = new UISplitPanel(UISplitPanel.SPLIT_LEFT_RIGHT);
splitPanel.setDividerAlignment(UISplitPanel.DIVIDER_BOTTOM_RIGHT);
splitPanel.setFirstComponent(table);
splitPanel.setSecondComponent(editorsPane);

UIPanel content = new UIPanel();
content.setLayout(new UIBorderLayout());
content.add(splitPanel, UIBorderLayout.CENTER);

(see Kitchensink application, hosted on github)

This was the whole source code for the table binding (= UI). The missing piece is the model. In our example, we've used the member dataBook. A databook is the model and controller of JVx. We have different implementations: MemDataBook, RemoteDataBook. A mem is like a database table, but in memory. A remote databook is connected to a remote/local storage. The storage provides data (from a database, filesystem, twitter, ...).

We didn't use a database in our kitchensink, so the dataBook was defined as MemDataBook:

RowDefinition rowdef = new RowDefinition();            
rowdef.addColumnDefinition(new ColumnDefinition("ID",
                                new BigDecimalDataType()));
rowdef.addColumnDefinition(new ColumnDefinition("STRING",
                                new StringDataType(new UITextCellEditor())));
rowdef.addColumnDefinition(new ColumnDefinition("BOOLEAN",
                                new BooleanDataType(new UICheckBoxCellEditor(
                                                    Boolean.TRUE, Boolean.FALSE))));
rowdef.addColumnDefinition(new ColumnDefinition("CHOICE",
                                new StringDataType(choiceCellEditor)));
rowdef.addColumnDefinition(new ColumnDefinition("DATETIME",
                                new TimestampDataType(new UIDateCellEditor("dd.MM.yyyy"))));
rowdef.addColumnDefinition(new ColumnDefinition("NUMBER",
                                new BigDecimalDataType(new UINumberCellEditor())));
rowdef.addColumnDefinition(new ColumnDefinition("TYPE_ID",
                                new BigDecimalDataType()));
rowdef.addColumnDefinition(new ColumnDefinition("TYPE_NAME",
                                new StringDataType(
                                    new UILinkedCellEditor(referenceDefinition))));
               
IDataBook dataBook = new MemDataBook(rowdef);
dataBook.setName("DATABINDING");               
dataBook.open();

It's the definition of a table with some columns and different column types, like String, Date, Number, ComboBox. It's easy to use a real database table if you read following article or this one.

The difference

What's the difference to standard JavaFX without JVx and why should you use JVx?

Here's the official documentation of Table View from Oracle. It's very complex to work with tables ;-) (seems to be so). The example in the official documentation doesn't use a database, like our example above!

The first difference: Save time and LoC.
This will reduce complexity and saves your dev time. It'll be easier to maintain an application with 1.000 LoC instead of 50.000.

Second difference: JVx already is a framework and library - don't create your own and waste dev time.

Advantage of JVx: Simply bind a database table with 10 LoC:

DBAccess dba = DBAccess.getDBAccess("jdbc:hsqldb:hsql://localhost/testdb");
dba.setUsername("sa");
dba.setPassword("");
dba.open();

DBStorage dbs = new DBStorage();
dbs.setDBAccess(dba);
dbs.setWritebackTable("testtable");
dbs.open();

StorageDataBook dataBook = new StorageDataBook(dbs);
dataBook.open();

This is enough to get full CRUD support for your tables.

This article was the first intro of our databinding implementation for JavaFX. The next artile will cover our chart implementation. Here's first a impression:

FX Chart binding

FX Chart binding

We love the clean UI of JavaFX and our maximized internal frames :)

From Swing to Vaadin?

Post to Twitter

Some days ago, vaadin released a Tutorial for Swing developers. It's a hitchhiker's guide to convert a Swing app to modern web app. It's a must-read if you plan to replace/migrate or modernize your Swing application.

We were mentioned in the last paragraph with our JVx framework, as possible conversion strategy. Thanks for that!

I want to hook in at this paragraph, because I totally agree with the rest of the tutorial.

It's true that a wrapper has pros, cons and limitations. You can't wrap everything. Sure you could try, but it needs so many developers and doesn't make sense because a wrapper shouldn't copy the underlying technology. The more features the wrapper has, the more problems will occur with new (different) technologies. The wrapper should be a subset of all technologies. But a subset is limited in functionality!

A wrapper should be focused on a specific domain, e.g. database/data driven applications or game development. A wrapper for multiple domains will fail!

I don't know many working wrappers. There were many attempts to create (UI) wrappers, in the past, but most were stopped because of complexity or the developers had other interests (if project was open source).

JVx is one working solution and in my opinion the most complete one because it contains an UI wrapper, has implementations for different technologies like Swing, JavaFX, Headless and Vaadin. The APIs are bulletproof and there are native applications for Android and iOS. JVx is a generic solution and doesn't generate additional source code.
But it has more than that, because it's full-stack and comes with different application frames for desktop, web and mobile applications.

But what is your advantage if you're using a wrapper?

You're (GUI) technology independent.

An example:

Your current business application is a Swing application and you plan the migration to a modern technology.
Your first migration decision should be: Desktop or Web
Next decision: which UI framework
Optional: Mobile support?

If your platform decision was: Desktop, then it's very simple to find the right UI framework: JavaFX and try JavaFXPorts for mobile support.
Fact: No real web and possible problems with mobile support

If your platform decision was: Web, then it's not an easy task to find the right UI framework, but vaadin should be the first choice because it's comparable to Swing and hides web technology for you!
Fact: No desktop but mobile support

Every decision has pros and cons. If you bet on one technology stack, you're fixed to this technology stack. In our example it was JavaFX or vaadin. And what will be the next preferred UI technology after JavaFX or vaadin?
You'll have the same problems again and it's never easy to migrate a (business) application.

You should bet on a technology independent solution, to be prepared for the future!
Means, you should use a wrapper. But don't use a wrapper which hides the technology from you. It should be possible to access the technology directly - if needed or if it's not important to be technology independent.

Sometimes it's not possible to be technology independent, e.g. some custom controls aren't available for all technologies.

The wrapper should allow technology dependent and independent development without any limitations!

Does it make sense to use the same application with different technologies?

Yes, but...

It's not a good idea to use e.g. Swing AND JavaFX because both technologies are desktop toolkits. But it makes sense to use JavaFX for your backend application and vaadin for your frontend or your mobile devices.

It's also a good idea to create only one application that works as desktop, web and mobile application - the same application. But show different screens/views on different platforms.

There's no big difference between desktop and a standard browser because resolution of a desktop pc is the same. A mobile browser has limited space and you shouldn't use the same screen/view on a mobile device as on the desktop pc.

Example
We use an ERP backend application to manage vacations. The appliation has about 10 screens for resource management, master data management and accounting. The application runs as desktop application with JavaFX. The same application runs in desktop browsers with 3 screens because the web frontend doesn't offer master data management and accounting. The same application runs on mobile devices with only 1 screen because mobile devices are used from employees to enter and view vacations.

We have only one application, started with different UI technologies and with different screens/views.

It would be possible to create 3 different applications with different screens and with dependencies between the applications and ... (complex to maintain, 3 different projects, application frame x 3).

If you'll create a "native" vaadin application and a JavaFX application you'll need different development teams with different know-how.

Don't waste time and resources, focus on the real problems of your application. A wrapper hides technology problems and allows fast development with few developers: Win-win situation!

Vaadin application frame design

Post to Twitter

Many of you probably know our application frame, for web applications: One application, different styles

We had a MDI variant for legacy applications with internal frames for screens. This is useful for applications with many screens and many records. The internal frames help to compare records from one screen with records from other screens.

For modern user interfaces, we use the SDI option. It looks fresh and simple and is great for applications with a small number of screens, because a scrolling menu is not nice - sure it will scroll if needed.

But what about application with e.g. 60 screens. Is MDI the only option? Yes and No, because we didn't have a variant for that kind of applications.... but now we have.

It's a mix of MDI and SDI, with a little bit CI:

Application frame SDI with menu

Application frame SDI with menu

The application frame is still the same as before, but with a different option. The name of the option is corporation, because the UI is meant for applications with many screens. It's still SDI with modal popups, because it shouldn't be too legacy!

Oh, do you see the small buttons on top/right? We use the FontAwesome feature of vaadin 7.2. We're already using vaadin 7.4.2 for our JVx vaadin UI!

We now have one application frame for many different application styles (I don't talk about visual attributes). The application frame is responsive and works well on mobile devices.

JavaFX FlowPane vs. FXFluidFlowPane

Post to Twitter

We're still working on our JavaFX UI implementation for JVx. Some weeks ago, we worked with standard JavaFX layouts (layout panes) like BorderPane and FlowPane. Both layouts are useful but don't work like BorderLayout or FlowLayout from AWT/Swing. There are small differences, e.g.

It was possible to resize a BorderLayout to any size. The BorderPane checks minimum and maximum size of its nodes and doesn't resize if bounds were reached. Sure, that's useful in theory but bad in practice because the content of a screen should always resize to the screen size (e.g internal frames).
The requirement wasn't hard to implement. We now have our own FXBorderPane which has its own min. and max. calculation.

The standard BorderPane was very useful but the standard FlowPane wasn't, because it has bigger problems/limitations:

  • Overlapping of Wrapped FlowPanes with other nodes
    Overlapping

    Overlapping

  • Size calculation depends on prefWrapLength if not stretched to full-size (BorderPane, SplitPane, ...). This means that the pane doesn't grow automatically if the parent has enough space.
    ABC

    Width calculation

  • The FlowPane doesn't support alignment of managed nodes
    Standard FlowPane (centered nodes)

    Standard FlowPane (centered nodes)

    but should:

    fluid flow pane (bottom aligned)

    Fluid flow pane (bottom aligned)

    fluid flow pane (stretched)

    Fluid flow pane (stretched)

We solved all problems with our FXFluidFlowPane because our applications won't work with standard FlowPane.

In JVx applications, we have more than two layouts. The most common layout is our FormLayout. We already have JavaFX implementations for all JVx layouts, like FXFormPane or FXNullPane.

Here's screenshot of our FXFormPane test application:

Form Pane

Form Pane