[SOLVED] Which class for dialog box?

Hello, i want to open a Kind of dialog-window (while the game pauses or keeps on running in the Background) where the uster can input some data.
I tried the “Swing GUI Forms \ JFrame Form”, but i don’t know how to get the focus back on the game-window automatically. Then i tried the JinternalFrame Form, but i didn’t even succed in getting the window visible. I didn’t find something suitable in the demos. Can anyone show me a simple example how to open a dialog-window and close it again without loosing the focus on the main(game)window?

1 Like

Generally with games you don’t have a dialog so much as a graphic or GUI control that is above everything else, sometimes with an overlay covering the screen such as a semi-transparent quad.

I want to do something like this.

1 Like

What you see in the background is already done with JME

I’m just trying to explain the difference between developing a desktop application and a game. They are not one and the same. You can mix and match but you will encounter issues when you do so, such as this.

For GUI, I use Nifty, which includes dialog boxes. The JME Wiki’s documentation on Nifty starts here:
https://wiki.jmonkeyengine.org/jme3/advanced/nifty_gui.html

In Nifty, a dialog box is a kind of popup, so you create it using Nifty.createPopup().

Nifty isn’t easy to figure out, so a dialog-box example is a good suggestion.

The best example I have is TestPopups, which uses a custom library instead of the standard jme3-nifty library. It’s part of the Jme3-utilities Project. The app includes 2 dialog boxes. When you run the app, click on the “Set search string” button (or the “About this app” button) to open a dialog box. Here’s a link to the source code:

https://github.com/stephengold/jme3-utilities/blob/master/tests/src/main/java/jme3utilities/nifty/test/TestPopups.java

I imagine it’s also possible to create dialogs using Lemur or Swing, but I don’t know the details.

Yes, Lemur can do this.

This is actually a rollup panel thats dragable.

Which can be completely removed or added by hitting the f1 key.

You can add fields,

        //Velocity Bias.
        contOAP.addChild(new Label("velBias"), "split 2, growx"); 
        fieldVelocityBias = contOAP.addChild(new TextField(""));
        fieldVelocityBias.setSingleLine(true);
        fieldVelocityBias.setPreferredWidth(50);

and use the data,

        //The velocity bias settings.
        if (!getState(UtilState.class).isNumeric(fieldVelocityBias.getText()) 
        ||  fieldVelocityBias.getText().isEmpty()) {
            displayMessage("[ velocityBias ] requires a valid float value.", 0);
            return;
        } else {
            velBias = new Float(fieldVelocityBias.getText());
            //Stop negative input.
            if (velBias < 0.0f || velBias > 1) {
                displayMessage("[ fieldVelocityBias ] requires a float value between 0 and 1 inclusive.", 0);
                return;
            }
        }
        ObstacleAvoidanceParams params  = new ObstacleAvoidanceParams();
        params.velBias          = velBias;

If you wish to learn Lemur then the demos and gems are priceless.

Edit: I should add that the interface shown is configuring the Recast4j crowd and thats a bitching complex library so you can do just about anything you can dream of I expect with Lemur.

2 Likes

Could you publish the code (or more parts) of it. It seems more mature than examples and forum examples I had found so far. I will need (if I have the time) a complex menu like that soon. It would be a nice inspiration. Dont worry I have my own style and some own menu stuff and wont copy it 100 %. It would realy be only an inspiration.
Another question: This display message. I cant remember it from lemur demo. Is it lemur or some own stuff?

I use the JFX bridge and just create the dialog boxes in JFX. I use Lemur for other in game labels and graphic controls. Sort of a best of both worlds. The General Information panel in the top right is Lemur, the Shipyard Components tare out panel on the right is JFX and the “Select Ship” dialog box in the center is JFX.

2 Likes

… and to do that kind of thing above:

2 Likes

I used the older version because I am still on JDK8 but yes

2 Likes

Thank you all for your answers.
I’m trying get the Job done with nifty-guy now, and i succeded in opening the screen in the nifty-tutorial (by pushing the button “K”) with

 nifty.gotoScreen("start");

But how do i close this window again and return to the game??? When i try it with

nifty.removeScreen("start");

then i get an “Uncaught exception thrown in Thread[jME3 Main,5,main]
NullPointerException”.

Here is the complete Code (I’m sure there a lot of mistakes because I’m not an experienced developer)

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.builder.LayerBuilder;
import de.lessvoid.nifty.builder.PanelBuilder;
import de.lessvoid.nifty.builder.ScreenBuilder;
import de.lessvoid.nifty.builder.TextBuilder;
import de.lessvoid.nifty.controls.button.builder.ButtonBuilder;


/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 * @author normenhansen
 */
public class Main extends SimpleApplication {

    public static boolean rotation;
    public static Main app;
    public static Nifty nifty;
    NiftyJmeDisplay niftyDisplay;
    
    public static void main(String[] args) {
        app = new Main();
        app.start();
        
    }

    public static void quitGame(){
        System.exit(0);
    }
    
    public static void closeGui(){
        nifty.removeScreen("start");
    }
    
    public void initKeys(){
        inputManager.addMapping("openDialog", new KeyTrigger(KeyInput.KEY_K));    
        inputManager.addListener(actionListener, "openDialog");
    }
    
    private final ActionListener actionListener = new ActionListener(){
    
        public void onAction(String name, boolean keyPressed, float tpf) {
            
            if (name.equals("openDialog") & !keyPressed  ){ 
                
                onEnable();
                
            }        
        }
    };
    
    @Override
    public void simpleInitApp() {
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        rootNode.attachChild(geom);
        flyCam.setDragToRotate(true);
        initKeys();
    }
    
    //onEnable()/onDisable() can be used for managing things that should
    //only exist while the state is enabled. Prime examples would be scene
    //graph attachment or input listener attachment.
    private void onEnable() {
        niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay(
                assetManager,
                inputManager,
                audioRenderer,
                guiViewPort);

        nifty = niftyDisplay.getNifty();
        guiViewPort.addProcessor(niftyDisplay);
        //flyCam.setDragToRotate(true);

        nifty.loadStyleFile("nifty-default-styles.xml");
        nifty.loadControlFile("nifty-default-controls.xml");

        nifty.addScreen("start", new ScreenBuilder("start") {{
            controller(new mygame.MySettingsScreen());
            // layer added
            layer(new LayerBuilder("forground") {{
                childLayoutVertical();     
                backgroundColor("#0000"); 
                
                // panel added
                panel(new PanelBuilder("panel_top") {{
                    childLayoutCenter();
                    alignCenter();
                    backgroundColor("#aaa1");
                    height("25%");
                    width("50%");

                    text(new TextBuilder() {{
                        text("Kubus Erzeugen");
                        font("Interface/Fonts/Arial.fnt");
                        height("50%");
                        width("50%");
                    }});
                }});
                
                panel(new PanelBuilder("panel_mid") {{
                    childLayoutCenter();
                    alignCenter();
                    backgroundColor("#aaa1");
                    height("50%");
                    width("50%");

                    // add text
                    text(new TextBuilder() {{
                        text("Here goes some text describing the game and the rules and stuff. "
                           + "Incidentally, the text is quite long and needs to wrap at the end of lines. ");
                        font("Interface/Fonts/Arial.fnt");
                        wrap(true);
                        height("50%");
                        width("50%");
                    }});
                }});

                panel(new PanelBuilder("panel_bottom") {{
                    childLayoutHorizontal();
                    alignCenter();
                    backgroundColor("#00f8");
                    height("25%");
                    width("50%");

                    panel(new PanelBuilder("panel_bottom_left") {{
                        childLayoutCenter();
                        valignCenter();
                        backgroundColor("#4458");
                        height("40%");
                        width("25%");
                        // add control
                        control(new ButtonBuilder("StartButton", "Start") {{
                            visibleToMouse(true);
                            interactOnClick("eingabeStart()");
                        }});
                    }});

                    panel(new PanelBuilder("panel_bottom_middel") {{
                        childLayoutCenter();
                        valignCenter();
                        backgroundColor("#4468");
                        height("40%");
                        width("25%");

                        // add control
                        control(new ButtonBuilder("StopButton", "Stop") {{
                            visibleToMouse(true);
                            interactOnClick("eingabeStop()");
                            
                        }});
                    }});
                    
                    panel(new PanelBuilder("panel_bottom_right") {{
                        childLayoutCenter();
                        valignCenter();
                        backgroundColor("#4478");
                        height("40%");
                        width("25%");

                        // add control
                        control(new ButtonBuilder("CloseButton", "Close") {{
                            visibleToMouse(true);
                            interactOnClick("eingabeClose()");
                        }});
                    }});
                    
                    panel(new PanelBuilder("panel_bottom_right2") {{
                        childLayoutCenter();
                        valignCenter();
                        backgroundColor("#4488");
                        height("40%");
                        width("25%");

                        // add control
                        control(new ButtonBuilder("QuitButton", "Quit") {{
                            visibleToMouse(true);
                            interactOnClick("eingabeQuit()");
                        }});
                    }});
                }}); // panel added
                
            }});
            // layer added

        }}.build(nifty));

        nifty.gotoScreen("start"); // start the screen
        
    }
    protected void onDisable() {
        //Called when the state was previously enabled but is now disabled
        //either because setEnabled(false) was called or the state is being
        //cleaned up.
    }
 
    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
        if (rotation){
            rootNode.rotate(0.314f*tpf, 0.753f*tpf,  tpf);
        }    
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

package mygame;

import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Klein_M
 */
public class MySettingsScreen implements ScreenController {

/*  public String getPlayerName(){
    return System.getProperty("user.name");
  }
*/
    @Override
    public void bind(Nifty nifty, Screen screen) {
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onStartScreen() {
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onEndScreen() {
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    
    
    public void eingabeStart(){
        System.out.println("Start");
        mygame.Main.rotation=true;
    }
    
    public void eingabeStop(){
        System.out.println("Stop");
        mygame.Main.rotation=false;
    }
    
    public void eingabeClose(){
        System.out.println("Close");
        mygame.Main.closeGui();
        
    }
    
    public void eingabeQuit(){
        System.out.println("Quit");
        mygame.Main.quitGame();
        
    }
    
}
1 Like

I was out sick yesterday and just saw your post. I’ll take a close look at your issue soon.

Updated on Sunday 1700 GMT:

I built your app without modification. When I ran it, the “Arial.fnt” asset was missing, so I commented out both references to it. With those changes, I was able to open the dialog box by pressing K. Clicking on the “Close” button reproduced the NPE you saw—at least, I hope it’s the same one: when reporting a Java exception you should always provide the complete stack trace, like so:

SEVERE: Uncaught exception thrown in Thread[main,5,main]
java.lang.NullPointerException
	at com.jme3.niftygui.InputSystemJme.handleMouseEvent(InputSystemJme.java:124)
	at com.jme3.niftygui.InputSystemJme.onMouseButtonEventQueued(InputSystemJme.java:231)
	at com.jme3.niftygui.InputSystemJme.forwardEvents(InputSystemJme.java:295)
	at de.lessvoid.nifty.Nifty.update(Nifty.java:368)
	at com.jme3.niftygui.InputSystemJme.endInput(InputSystemJme.java:112)
	at com.jme3.input.InputManager.processQueue(InputManager.java:850)
	at com.jme3.input.InputManager.update(InputManager.java:914)
	at com.jme3.app.LegacyApplication.update(LegacyApplication.java:724)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:227)
	at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:499)
	at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:581)
	at com.jme3.system.lwjgl.LwjglWindow.create(LwjglWindow.java:423)
	at com.jme3.app.LegacyApplication.start(LegacyApplication.java:463)
	at com.jme3.app.LegacyApplication.start(LegacyApplication.java:424)
	at com.jme3.app.SimpleApplication.start(SimpleApplication.java:125)
	at mygame.Main.main(Main.java:35)

The source code where the exception occurred can be found on the web:
https://github.com/jMonkeyEngine/jmonkeyengine/blob/v3.2/jme3-niftygui/src/main/java/com/jme3/niftygui/InputSystemJme.java#L124

Code inspection suggests that nifty.getCurrentScreen() returned null. Likely cause is the nifty.removeScreen("start") in Main.closeGui().

I don’t know a safe way to disable Nifty once it’s started. To hide the dialog, a better approach might be to create an empty Nifty screen (with backgroundColor("#0000")) and switch to that, rather than removing the active screen.

1 Like

Thank you for the hint with the empty screen. This works fine for me!!

1 Like