JavaFX embedded in jme3

Edit:
Code is currently hosted at

and contains a lot more than just a javafx wrapper.
——————————————————————–

I’m playing around with java 8 + javafx and tried to embed it inside jme3 window. It is work in progress:

Basic idea is that you do normal javafx programming and attach javafx scene into special gui node in jme3 and things just work. Obviously, javafx component cannot interact with jme3 scenegraph directly (like getting light, having jme3 particle etc), but on the other hand, you get mature widget toolkit with all bells and whistles (like Scene builder etc). Most javafx apps should run even unmodified if you just extract top level scene from them.

It is already interactive - you can click around, type, copy/paste, select things with mouse, use popup menus etc. It performs reasonably well (only needed repaints, direct texture modification). Biggest missing thing is event consumption - currently, mouse events are coming down through jme3 scenegraph, even if consumed by javafx components. There are few solutions to that, with different level of hackery involved, will have to look into that.

It requires jdk 8 build 115 (or 116), which is not yet available, so not posting code here yet.

12 Likes

it’s very interesting (i never heard about javafx before, even if it seems to be an oracle project). Thanks a lot for what you are doing. It’s even xml-based, so it’s a “good” approach.

My main question is : is javafx available on mobile devices ? This questions means : is it a possible option to replace all the nifty-gui stuff with javafx in the futur ?

And congratulation for what you already done !

I don’t think it is runnable right now (and anyway my port requires development version of jdk8, so it is not even really runnable under windows atm). But I have seen IOS classes inside javafx and they have OpenES 2 rendering backend as well - and support for both platforms is certainly on the roadmap. So it might be possible in future (not sure if you will want to get 20MB extra jar to enable javafx on the other hand…)

Hey cool, how did you make stuff clickable? I tried something similar as you might know and posetd about it, with the 7jfx one. And it was impossible for me to get any events into it.

This is very much work in progress, but take a look at

http://pastebin.com/SR7wbT19

Bottom of the file contains bits about event handling. I’m using EmbeddedStage interface exposed in javafx 8 for that - and they have scenePeer.mouseEvent, scenePeer.keyEvent hooks for that. Javafx is using this to embed itself inside swing container, so most things (except for event transparency) is handled.

Without this interface, second choice would be scene.snapshot and FXRobot/BaseFXRobot. Third choice would be finding node under cursor and doing node.fireEvent, but this could get quite complicated especially with regards to focus handling.

About the 20 mb … well, as oracle is the dev, i hope that they’ll include it with the default jre, meaning that i’ll not have to include it myself. This is really what we are missing : a cross plateform approach that isn’t embedded with jme. You know, something which just use different backend and give a transparent access to the most common features. I think that there will be something like that in the future, as most os seems to converge to the same ui stuff (radio, button, tab, etc.)

So, we will not have to reinvent the wheel over and over again (and applications will be able to have smaller binaries)

Yes, they are already including it by default in jdk/jre. It is the android which will not have it installed by default I’m afraid.

Ok, updated version available at
http://pastebin.com/SR7wbT19

You will need jdk9 b115 to get it working, but hopefully it should be available soon. I had to do major hackery to support full screen mode - it is using very internal APIs and a bit of reflection, so might break without warning. Windowed mode should be more stable.

Everything seems to work so far. Performance is also quite good from what I can see.

2 Likes

Wikipedia says that some Android devices have it, others don’t.

Beta 116 is out and it contains all the bugfixes needed for that. I have uploaded latest version of bridge class to
http://pastebin.com/SR7wbT19

1 Like
@abies said: Beta 116 is out and it contains all the bugfixes needed for that. I have uploaded latest version of bridge class to http://pastebin.com/SR7wbT19

can you use online repo for storing all the stuff with examples?
https://code.google.com/hosting

I’ll put it in virtual mat repo (hosted at assembla), but I need to do some unrelated cleanup in other classes first.

Hi @abies has this gone into a repo yet? Dunno if you noticed that @EmpirePhoenix was also working on a JFX integration of his own, but it sure would be nice if you two managed to pool your efforts together :wink:

And lastly, would love to see a video example!

https://subversion.assembla.com/svn/vmat/vmat/trunk/src/main/java/net/virtualmat/jme3/JmeFxContainer.java

This is the latest version - you need recent java 8 snapshot to have it working, because of one of interfaces changed name recently.

I’m aktually looking kinda forward to this, as it would allow to replace a lot of selfmade gui stuff with one where I do not have to maintain it XD

Just took a quick look, are you sure you are registering the rawinputlistener as the first listener? Cause then the consumption of events should work (if I’m not missing something here)

One small fix/change I would propose (or in a similar way), registering a appstate in the initialisation that closes the jfx stuff upon closing the jme application

[java]

	app.getStateManager().attach(new AppState() {

		@Override
		public void update(final float tpf) {

		}

		@Override
		public void stateDetached(final AppStateManager stateManager) {

		}

		@Override
		public void stateAttached(final AppStateManager stateManager) {

		}

		@Override
		public void setEnabled(final boolean active) {

		}

		@Override
		public void render(final RenderManager rm) {

		}

		@Override
		public void postRender() {

		}

		@Override
		public boolean isInitialized() {
			return true;
		}

		@Override
		public boolean isEnabled() {
			return false;
		}

		@Override
		public void initialize(final AppStateManager stateManager, final Application app) {
			// TODO Auto-generated method stub

		}

		@Override
		public void cleanup() {
			Platform.exit();
		}
	});

[/java]

This is already fixed long time ago :wink: Issue was with mouse motion events - how to determine if they should be passed to jme3 or not, depending if they are over javafx component or not. Ended up inspecting alpha of generated image under the mouse (which probably means it is not possible to have completely invisible javafx components receiving this kind of events, which hopefully should not be a problem in real life).

At the moment, everything works properly, at least for the cases I was testing.

Well I have the strange problem, that the background of my scene is not transparent under windows/linux.

Do I need to ensure something special so that the background is not rendered?

Root node should be preferrably Group (other containers often have non-transparent backgrounds which are very hard to get rid of) and you need to call scene.setFill(new Color(0,0,0,0)); Try with following scene
[java]
public static Scene createScene() {

    Group root = new Group();

    Scene scene = new Scene(root,600,600,true);
    scene.setFill(new Color(0,0,0,0));

    final TreeItem<String> treeRoot = new TreeItem<String>("Root node");
    treeRoot.getChildren().addAll(Arrays.asList(new TreeItem<String>("Child Node 1"), new TreeItem<String>("Child Node 2"), new TreeItem<String>("Child Node 3")));
    treeRoot.getChildren()
            .get(2)
            .getChildren()
            .addAll(Arrays.asList(new TreeItem<String>("Child Node 4"), new TreeItem<String>("Child Node 5"), new TreeItem<String>("Child Node 6"), new TreeItem<String>(
                    "Child Node 7"), new TreeItem<String>("Child Node 8"), new TreeItem<String>("Child Node 9"), new TreeItem<String>("Child Node 10"), new TreeItem<String>(
                    "Child Node 11"), new TreeItem<String>("Child Node 12")));

    final TreeView treeView = new TreeView();
    treeView.setShowRoot(true);

    treeView.setRoot(treeRoot);

    treeRoot.setExpanded(true);
    treeView.setLayoutY(100);

    Button test1 = new Button("Test1");
    test1.setLayoutX(500);
    test1.setLayoutY(500);

    CheckBox test2 = new CheckBox("Test2");
    test2.setLayoutX(700);
    test2.setLayoutY(700);

    MenuBar bar = new MenuBar();

    Menu testMenu = new Menu("Test");
    bar.getMenus().add(testMenu);
    MenuItem i1 = new MenuItem("Entry1");
    MenuItem i2 = new MenuItem("Entry2");
    Menu sub = new Menu("Submenu");
    sub.getItems().addAll(new MenuItem("Sub entry 1"),new MenuItem("Sub Entry 2"));
    testMenu.getItems().addAll(i1,sub, i2);
    
    TextArea ta = new TextArea();
    ta.setOpacity(0.7);
    ta.setLayoutX(400);
    ta.setLayoutY(300);
    
    cb = new ChoiceBox();
    
    cb.setItems(FXCollections.observableArrayList("Alfa","Beta"));
    cb.setLayoutX(300);
    cb.setLayoutY(200);
            
    
    

    root.getChildren().addAll(treeView, test1, bar, test2,ta,cb);

    
    return scene;
}

[/java]

To see if it works.