This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information

Posts tagged: JavaFX

Zoom support for applications

Some weeks ago, JavaFX links of the week contained a very interesting link: It was about ZoomFX 1.0.1.

It's a zoomable pane for your JavaFX application.
There's another small project, called MagniFiX. It's a "simple" magnifier but different than ZoomFX.

Why was this so interesting for us?

In the past we had a lot of requests from customers for automatic application scaling for simple touch devices (terminals). Usually we solved the problem with extra source code and specific fonts/control settings - horrible.

We had other requests about image zoom in/out features and charts, ...

So we thought that ZoomFX could be a very useful extension for our JavaFX UI. We tried the demo and configured a simple test application. But first: Maven. Not new: We aren't big fans.
Sure, it wasn't hard to start a test application but we were suprised about the dependencies:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-math3</artifactId>
</dependency>

<dependency>
    <groupId>com.github.dejv78.commons.jfx</groupId>
    <artifactId>jfx-binding</artifactId>
</dependency>

<dependency>
    <groupId>com.github.dejv78.commons.jfx</groupId>
    <artifactId>jfx-geometry</artifactId>
</dependency>

<dependency>
    <groupId>com.github.dejv78.commons.jfx</groupId>
    <artifactId>jfx-input</artifactId>
</dependency>

The overlays were saved as FXML and we thought that it's not a good idea for a library like ours. Anyway, we tried the integration in our lib and stopped suddenly because ZoomFX didn't work with our dynamic layouts. It simply didn't work out-of-the-box and it had too many dependencies for such a "simple" feature.

We had no luck... but we love researching new things. So we started with our own zoom implementation without any dependencies and also integrated in our UI. We made a short screencast of the result.

Application coder

Every application and internal frame has this zoom feature because it was integrated in the UI implementation. We need to do some fine tuning, but it works great!

JVx' JavaFX UI - first release

We're happy to announce our first beta release of JVx' JavaFX UI with version number 0.9 :)

The release is two weeks later than planned but we had some extra tasks to do. We didn't set 1.0 as version number because we have some open tickets which are important, in our opinion, for 1.0. The 0.9 beta is already feature complete with some known bugs.

We also released an extra library: JFXtensions
It contains all standalone controls and extensions which are independent of JVx. The MDI system, our layouts, styled scene and much more.

Here are the download links:

All libraries are available on maven central as well.

We've released DnDTabPane as external lib on maven central, because it wasn't available and our UI needs the dependency. The DnDTabPane is licensed under EPL 1.0 and JVxFX UI, JFXtensions are Apache 2.0 licensed.

The DnDTabPane is still based on Tom Schindls implementation for Efxclipse.

We've a very cool video of our work during the last 4 months. It's the visualizaton of our dev repository:

Respository visualization


The visualization was created with Gource.

Developer Information

The dev2015 branch was merged back to trunk. If you're working with our branch, please switch to trunk.

JavaFX Table and Tree lazy loading

JavaFX doesn't define a specific model for table or tree. The implementations are based on ObservableList which is not more than an extension of standard List interface with some additional listeners and sorting, filtering. The general design doesn't take care of one important feature: Lazy loading of records.

This is an important feature if you're working with databases or large datasets. If you have millions of records, it's not a good idea to show all records in your GUI. You shouldn't load more than needed and of course, not more than the user is able to handle.

We have a model in our JVx framework which supports lazy loading of records (not only database records). To use our model with JavaFX, we had to do some Trial and Error because an ObservableList is too lightweight. Sure it wasn't a problem to simulate more entries than the list really had. This was needed to load records on demand. If a "virtual" element was requested it was simply loaded from the datasource. Sounds simple enough. To be honest - it was that simple!

A bigger problem was the scrollbar handling of the controls because it didn't set the scrollhandle position correctly after loading "virtual" records. We didn't find a perfect solution for this problem but our current solution works and is user-friendly enough. We've used our JVx model implementation for TableView and TreeView.
Means: One model for all UI controls.

A simple screencast of our test application is available on YouTube. The video shows a simple TableView which loads records from a remote server via http. The remote server reads data from a HSQLDB. The table contains 317027 records with filenames and additional filesystem information. The remote server returns exactly 100 records, per request, for our test application.

LazyLoading JavaFX TableView


We have the same lazy loading mechanism for TreeView.

Our implementation was done for JVx' model (IDataBook), but the mechanism should work with any other model definition. The complete source code is available in our dev repository. Simply start with ObservableDataBookList.

JavaFX Tree with self-joined table

Trees are always tricky, because it's not easy to fill a tree with data. The problem is not the tree itself, but the preparation of data for the three. It's easy if your data is structured or if you have only few records to prepare. If you have differnet datasources, it could be very tricky to build a tree.

The official tree documentation from Oracle has some examples.

It's boring to create trees because it needs a lot of boilerplate code - per tree. You need more boilerplate code if your trees should be editable.

We solved the "boilerplate code problem" with JVx and the active model implementation. I'll show you a simple example with a self-joined database table. The database table contains all filesystem folders of our Linux test VM.

The table was created with following statement:

CREATE TABLE FOLDERS
(
  ID        INTEGER IDENTITY,
  FOLDER    VARCHAR(256) NOT NULL,
  FOLD_ID   INTEGER,
  constraint FOLD_UK UNIQUE (FOLD_ID, FOLDER),
  constraint FOLD_FOLD_ID_FK FOREIGN KEY (FOLD_ID) REFERENCES FOLDERS (ID) ON DELETE CASCADE
)

Not really tricky. The table contains an unique identifier, the folder name and the identifier of the parent folder. A simple self-joined table.

The UI code for the tree:

IDataBook dataBook = createDataBook();

FXDataBooksTree tree = new FXDataBooksTree();
tree.getDataBooks().addAll(dataBook);

Short and no boilerplate code!
The missing piece is the createDataBook() method, because it defines the access to our database table:

RemoteDataBook rdbData = new RemoteDataBook();
rdbData.setDataSource(getDataSource());
rdbData.setName("folders");
rdbData.setMasterReference(new ReferenceDefinition(new String[] {"FOLD_ID"},
                                                   rdbData,
                                                   new String[] {"ID"}));
rdbData.open();

The code is similar to other examples likeJavaFX, JVx and data binding or Plain JDBC vs. DBStorage.

The tree will look like this one:

Self-joined tree

Self-joined tree

The whole source code is available in our dev branch.

Above test application reads records from a remote database via http, but it could also use a memory databook without database access, like this one:

IDataBook dataBook = new MemDataBook();
dataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("ID",
                                                new BigDecimalDataType()));
dataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("PARENT_ID",
                                                new BigDecimalDataType()));
dataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("NAME",
                                                new StringDataType()));
dataBook.setMasterReference(new ReferenceDefinition(new String[] { "PARENT_ID" },
                                                    dataBook,
                                                    new String[] { "ID" }));
dataBook.setName("MASTER");
dataBook.open();

An example with a MemDataBook is available in our kitchensink application.

JavaFX custom controls

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

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

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

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.

JavaFX, JVx and data binding

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?

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!