Showing posts with label JavaFX. Show all posts
Showing posts with label JavaFX. Show all posts

Saturday, 14 April 2018

JavaFX out of Java 11

In somewhat recent news Oracle has moved JavaFX out of the standard Java install from Java 11. There is a certain fun that Donald Smith describes this as "making JavaFX easier to adopt by making the technology available as a separate download" — don't you always find having to download two things instead of one makes things easier... but that's not really what I want to chat about here.

I teach a couple of university courses that have usually used JavaFX: one in distributed software development, and another in functional programming in Scala. Not because we're particularly teaching UI programming, but because there are plenty of occasions where you're not teaching UI programming but still want students to be able to put something on the screen easily. It's in that context I'd like to say a little about JavaFX — the good, the bad, and the ugly.

I should perhaps also mention that I think that realm — just being so much easier — was Java's best route to being a relevant client technology again. I have this thing I need to knock up, do I set up npm, bower, etc, to do it in Electron -- nah, it's just a small thing at the moment, I'll just whip it up in JavaFX. And then just having a smooth progression where there just isn't a point where it feels uncomfortable to write your program in this toolkit. This is also where JavaFX didn't quite get it right.

Ok, enough rabbiting about the space I'd like Java UIs to sit in. How did JavaFX fare in my experience?

The good

The scene graph in JavaFX managed simplicity very well. I have a fairly common little demo that I write live in front of students for showing the concept of threads (as their Java unit doesn't always cover it). I put a spinning rectangle above a button, and have the button's action listener put the thread to sleep for 10 seconds. Instant frozen rectangle. Then we move the task onto a background thread, and the UI doesn't freeze. Five minutes, about twenty lines of code, gets the point across pretty well.

Hidden in there, of course, I'm doing some things Swing never really let you do. Mixing a shape primitive in a scene graph with controls (buttons). And as the rectangle spins its dimensions change but I don't have to worry about its drawing being clipped by its bounds. And the VBox I put them in just goes into the component graph, I don't have to deal with setting layout managers.

The bad

There's two places I think JavaFX fell down:

  • Both times they created it (the old JavaFX 1 in JavaFX Script, and JavaFX 2), they had far too particular a model for how you'd do your UI. JavaFX 1 dictated what language you worked in. JavaFX 2 didn't, but see below with the observable lists, it very much packaged the programming model into the controls. It didn't have the neat separation that HTML5 does -- that the scene graph just does displaying the scene graph, and you can chop and change different frameworks for how you tie your data model to that.
  • It tried to be too deep. Style your UI with CSS! Underlying every control there's a complex region model that lets you style multiple regions in every control! While this looked fun if you were really very interested in JavaFX, it meant that if you opened up the API documentation there was just so much of it. Separating what you could ignore from what you couldn't became a task for the reader, and it just looked scarily big for students that just wanted to whack some buttons, a canvas, and a graph on the screen.

The ugly

The part my students really found awkward was the controls. In 2017, I set the Scala students an assignment of writing a particle swarm optimiser. So that they could see it working, I also asked them to show various properties of the swarm at each frame of the simulation. That was supposed to be just a little prod in the assignment so students could easily see what was happening -- but it turned out they found writing the UI much harder than writing the particle swarm. Let's just highlight that for a moment:

A functional programming assignment, in Scala (a famously large language for students to get to grips with), and it turns out the fiddliest part is getting the UI to show some simple graphs on-screen. Hmm...

I think the issue there was that JavaFX's controls model is quite so deeply married to its observable lists. For students who are quite happy calling map on a sequence of values, to update them in one fell swoop, having to deal with code that says:

series.getData().add(new XYChart.Data(1, 23));

starts to looks weird. No, I don't want to get the data, I want to add a datapoint.... It's not that it's a lot of code, it's just that JavaFX imposes an opinionated mental model for how data in a UI should be updated, and if that's different to how you write the rest of your code then it's asking you to jump mindsets when you touch the UI parts of your code.

Where too next?

From outside Oracle, it does look like JavaFX has been put out to pasture. I used to have a cynical saying that when companies and governments fund projects, one of the things they really like about open source is that "we've released it to the open source community" sounds so much more successful end to a project than "we've dropped it like a stone".

Which is unfortunate, as in reverting to just supporting Swing until 2026, we've lost the simpler parts of JavaFX. The scene graph that just let you chuck shapes into VBoxes. Letting you paint outside your control's bounds if you want, so you can do things like have a row of buttons, but highlight one for some help text by circling it or making it wiggle. The slightly neater animation classes too. We've fallen back in time ten years to when the toolkit still got in the way for the simple but visually interesting stuff.

So what I'd like to see happen with JavaFX is for it to be modularised, rather than it being a big fat module put out to grass. For Oracle to back the scene graph to the hilt, and make sure you can add one dependency in gradle, and you'll get a really simple toolkit for putting together attractive little UIs, with the elementary controls such as buttons and text fields. Put the complex controls out to libraries, but putting some buttons and a canvas on screen, and making a button do a little dance so you can draw attention to it shouldn't be hard.

And, as seems to work for html, the frameworks can deal with different ways of tying data to code. The react-like ones that let your code appear relatively pure, and then do a diff on what's in the code. Or the reactive ones that treat every property like an observable that automatically updates its controls when you do. Or the d3.js like ones that treat it as sets of data that are new, changed, or removed. etc.

Thursday, 21 October 2010

Apple's Java runtime "deprecated": less news than we might think?

Web news outlets have picked up on a comment in the release notes for the latest Apple Java update saying that Apple's version of Java is now deprecated and will receive less frequent updates. The new Mac App Store doesn't permit Java applications, so some, including The Register, have concluded that Apple is trying to kill Java on the Mac.

This time, I think they are seeing conspiracy theories unnecessarily. (For all I know, Apple might well want to kill Java, but this change makes sense even if they don't.)

When The Register first published their story, the author conflated "Java" with "Swing". The original version of the story, when trying to describe the few desktop apps that require Java, linked to a list of apps that use the Swing toolkit. And so, for instance, didn't include significant applications like Adobe's Flash Builder 4, which uses SWT not Swing. (The Reg has edited the story since then.)

Why does that matter? Well, at JavaOne Oracle trumpeted JavaFX not Swing as the way of the future for Java user interfaces. Oracle's JavaFX roadmap promises a Java plug-in that runs JavaFX without even starting the old abstract windowing toolkit (or, consequently, Swing). But the most visible part of Apple's investment in their own Java runtime has been making Swing look nice and work well on Apple desktops. So it sounds like Oracle effectively deprecated a lot of Apple's work for them!

Just under where Apple's release notes say "Java Deprecation", it immediately headlines "Third Party JVM Support" (effectively, making it easier to put Oracle's Java runtime on the Mac instead of Apple's.)

Meanwhile, the SWT toolkit that Eclipse and Adobe Flash Builder 4 use already the Mac's "Cocoa" bindings even when not using Apple's Java runtime. So those guys, including a lot of Java developers who use Eclipse, probably won't even notice a bump -- their interfaces should look identical on Oracle's runtime or on Apple's.

All in all, it seems as though deprecating the Apple Java runtime is an attempt to move Mac users to the Oracle Java runtime, not actually a nefarious "kill Java" machination after all.

Edit: The thing I'm trying to speculate, without overstepping the mark (it is just speculation), is that I reckon Oracle might have wanted this change to happen. Oracle's recently announced JavaFX roadmap promises a new browser plug-in. The browser plug-in for Java is normally part of the JRE. That suggests to me that Oracle would already have been thinking about whether they needed to take over providing the Mac JRE in order to deliver on their roadmap fast enough.

That could still be very worrying news for Swing/AWT on Mac, though.

Tuesday, 19 October 2010

Another JavaFX mistake: LoggerFactory.getLogger(this.getClass())

Every now and then I come across a mistake in our code (either mine or someone else's on the team) that demonstrates something about the JavaFX compiler -- a behaviour that breaks a hidden assumption that programmers sometimes have. Here's another one:



That code's got a potential mistake in it -- if you instantiate a subclass of AlignedContainer, the logger's name won't be AlignedContainer, but the name of the subclass. In JavaFX, the compiler generates subclasses for object literals, and you'll find that many of your loggers are named after generated classes.

So, in this particular case the logger ended up being

au.com.nicta.cose.comlex.fx.TimelineGui$1AlignedContainer$ObjLit$17

Which is a more awkward to turn on or off individually using log4j.properties (notice that one of the generated parts of the name, "TimelineGui$1", comes before "AlignedContainer"). Why is this the case? Well, the AlignedContainer was instantiated using an object literal:



The JavaFX compiler neatly generates an inner class extending AlignedContainer to implement this object literal:



So then it makes sense that this.getClass() does not return the AlignedContainer class but this anonymous inner class.

Wednesday, 29 September 2010

JavaFX Script isn't in JavaFX 2.0 - what's the practical impact for working with JavaFX now?

from my JavaOne talk.

At JavaOne, it was announced that JavaFX 2.0 won't support JavaFX Script. (Or at least, Oracle won't be updating the JavaFX Script compiler for JavaFX 2.0.) Although Oracle had kindly given partners and speakers a little advanced warning of this, I met quite a few people at JavaOne who were taken by surprise. And at face value, the situation today is a little odd:
  • JavaFX 1.3.1 requires you to write in JavaFX Script
  • JavaFX 2.0 won't let you write in JavaFX Script
  • (and 2.0 isn't out until next year)
And many people find themselves in a dilemma: Does that mean all code for 1.3.1 has to be thrown away? What do you do until 2.0 is available if you can't just "wait a year" -- 2.0 code can't be written yet but 1.3.1 code would be wasted?

After rejigging my talk a little, I inserted a few slides on what I think the practical impact on our project is in the short term. After all, my team has a JavaFX 1.3.1 client. How has this announcement affected us?

Well, the first thing to say is that even today a lot of a JavaFX client can be written in Java. I ran some rough line counts on our JavaFX client -- the client I demo'ed at JavaOne -- and it came up as:
  • 27% JavaFX Script
  • 73% plain ol' Java
So the impact for us is a bit smaller than it appears. Part of that is because I was very cautious about committing the client to JavaFX. JavaFX 1.2, which we had to cope with until April 2010, had some very awkward bugs in it -- and there seemed to be a lot of risk with the Oracle buy-out and JavaFX gaining little market-share. So I kept as much of our code as possible in Java, ready to jump ship from JavaFX if we needed to. The libraries, model, data handling, and most of the guts of our code aren't written in JavaFX Script but just in Java. And it seems that's just as well. I realise other projects might not be in that situation though.

So this seems to be rule 1 for working with JavaFX at the moment:

If a class doesn't have to be written in JavaFX Script, write it in Java, Scala, Groovy or some other JVM language. Save yourself the effort of converting it later.

Various talks at JavaOne described possibilites for working in a JavaFX-Script-like way in JavaFX 2.0:
  • Stephen Chin is keen to get an open source project going to update the JavaFX Script compiler so it can target 2.0
  • Jonathan Giles and Stephen Chin showed how code in Scala, Groovy, or Clojure can look very similar indeed to JavaFX Script
In my view, it's too early to assess whether it will be easy to convert non-trivial JavaFX Script code to Scala or another JVM language. The 2.0 libraries are still being written, and nobody has much experience converting non-trivial apps yet -- even some of Oracle's demos in Richard Bair's JavaFX 2.0 talk were still written in JavaFX Script code; they hadn't been converted yet. It should be straightforward -- the 2.0 libraries are supposed to contain all the functionality of the existing JavaFX, so it should just be a matter of converting syntax, not redesigning your client. But let's wait and see on that.

It's also to early to assess whether the open source project to update the JavaFX Script compiler will be successful or not. Again, it should be. The JavaFX Script compiler always compiled to Java, and under 2.0 it'll have some libraries to target that will be a very close mapping to its language features.

So what can you do now?
  • JavaFX 1.3.1 is a production release. And it works pretty well. (Unlike, say, 1.2!) So in the short term, targeting an app at 1.3.1 isn't so bad.
  • JavaFX Script is still very fast for prototyping. Many of our visualisations were written in hours, not days. If you are doing prototyping or scientific experimentation where the results and the design decisions are more valuable than the code, JavaFX Script is still a pretty good choice.
  • If you do keep most of your model code in Java, then the JavaFX Script code you write will usually be fairly simple. That means it's going to be less complicated to convert to another language if you decide to.
For my project, in fact, JavaFX Script not being supported in 2.0 makes very little difference. Government-funded research projects get fixed funding periods, and our current funding round finishes before 2.0 will be released. So we couldn't target 2.0 anyway. (If our hospital partners' experiments are successful, and more funding is won to take it further, that'd come with more development funding to deal with productisation issues -- including upgrading from 1.3.1 to 2.0. We'll make that as easy as possible to do, but we don't have to pencil it into the calendar yet.)

Wednesday, 22 September 2010

JavaOne slides & Thanks for listening

I just wanted to say thank you to all who came to my talk today. Especially as I know there was a much higher profile JavaFX Graphics talk going on in another room at the same time. (Yes, that was a bit demoralising!)

I deliberately skipped some of the technical slides in the presentation -- this is because they are particular to JavaFX Script (deprecated in 2.0). The slides were the top few most hair-pulling bugs we came across in our JavaFX Script code. Things my team wished someone had told us before we started.

But to make sure you don't hit the same issues if you do any JavaFX Script, I have uploaded all the slides (including those) to Slideshare. The code examples should explain the problems reasonably well, and if not then please do ask.

Those slides are tucked in at the end of the presentation (91-106!). No, I didn't really expect to have time to show them -- when the 2.0 changes were announced, I thought it would be more useful to talk about the practical impact of the "death of Script", rather than talk about some technical traps in a language that's been discontinued.

Tuesday, 21 September 2010

Things to expect in my JavaOne talk on JavaFX, OSGi, and the science of good (medical) conversation

Things to expect in my talk on Wednesday at JavaOne:

Wed 22nd Sept, 16:45 Hilton San Francisco, Golden Gate 3:
Visualizing the Science of Conversation with JavaFX and OSGi to Save Lives. William Billingsley, senior research engineer, NICTA
Session S313951
  1. A JavaFX demo that isn't yet another video wall.  Not even wrapped around a big ball and rolling down a slide into yet another video wall.
  2. The fastest, and hopefully clearest, introduction to OSGi.  We use OSGi on the client
  3. A little commentary on the JavaFX 2.0 changes.  How to sensibly use JavaFX 1.3 given it requires you to use JavaFX Script and that's going away next version.
  4. Programming as experimentation.  What do you do when it's actually a requirement that your requirements are unknown, and the goal of your software is to mine how your non-yet-users think.
  5. What the picture below means, and why JavaFX on Mac finds it harder than a video wall.

  6. How OSGi lets us build the great wall of science...

    ...how this picture knows what you're talking about...


    ...and how this one knows how hard you were thinking when you said it.

Saturday, 18 September 2010

Science, JavaFX, and OSGi: appearing this week at JavaOne

On Wednesday, I'm giving a talk at JavaOne on how my team is using JavaFX to analyse and visualise medical conversations -- JavaFX in a scientific app, all pluggable and extensible via OSGi.
Wed 22nd Sept, 16:45 Hilton San Francisco, Golden Gate 3:
Visualizing the Science of Conversation with JavaFX and OSGi to Save Lives. William Billingsley, senior research engineer, NICTA
Session S313951
There have been a few lists of interesting JavaFX talks at JavaOne posted to Twitter and on the Web, and a few of those lists haven't included my talk. How to scare a speaker in one easy step: post a list of interesting talks on his topic and don't include his!

So, I just wanted to reassure anyone who's thinking of coming to my talk that yes it is on, and it should be relevant and interesting. (Or if it's not interesting, tell me off!)

A little later, I'll post more on what you can expect to hear at my talk.

Tuesday, 9 March 2010

JavaFX initialisation order (solved?)

The semantics of JavaFX's initialisation order can be hard to find, and in a previous post, I was finding it gave some odd effects. Having looked on the JavaFX bug tracker, it turns out it the issue is fairly simple, but needs trumpeting from the hills because it is still unexpected.



B.one will be null. How is that possible? Because of what override means -- it changes the definition but not the "order of declaration".

A naive person might think that B.one would first be set to 1 (in the initialisation of A) and then to 2 (in the initialisation of B). Or they might think that B.two will be set before B.one because it comes first in B's script. But that's not how JavaFX does it. The variable one is initialised first because it is declared first (in A's class declaration, which comes before B's.) But it is set to B.two because only the override initialiser takes place. Unfortunately, this means it is set to B.two before B.two has actually been defined -- so it gets set to null.

The moral of the story: Don't use override var if you want to set the variable to refer to another member variable. It's a forward reference. Even if the member variable you want to refernce also comes from a superclass, it could still be a forward reference (because you don't know what the order of declaration was in the superclass).

If in doubt, set it in the init block. That always happens in the order that you specify in the block, after everything else has happened. It's boring and more Java-like, but at least you can even step through it with a debugger and put log messages in if you need to!

Tuesday, 2 March 2010

JavaFX initialisation craziness

UPDATE: Another post describes the solution.

JavaFX is Sun/Oracle's new user interface platform for Java. It has many features that are quite nice. But it has a few oddments that are hair-pullingly irritating.



The naïve among us might think that pushing the mouse button would indeed be wired through to MyBehaviour.onMousePressed, and "MOUSE PRESSED" would be printed. Apparently not.

In the language reference, there is this irritating line when it describes the initialisation order:
The values of the object literal's instance variable initializers are computed (but not set).

"but not set". Of all the evil villainous schemes... The MySkin and MyBehaviour objects are created, but MyControl.skin isn't actually assigned until later, so the following line wiring the mouse events to it breaks.

I keep finding that JavaFX is wonderfully concise, but really tricky to debug, and irritatingly fragile as many of its conventions don't do what you'd expect (like let you refer to an assignment you made in the previous line during initialisation, as in this example).