Interact onClick not working

Hi guys



Can anyone help me debug my onClick handlers? I cant seem to debug Nifty itself because the code is compiled (although I have the svn tree checked out on my PC).



Anyway… they used to work fine. However, I did a major refactoring of my code, and they no longer work (we’ve all had that before!).



The way they used to work was that each screen was in its own XML file, and each XML file/screen had its own controller. I still have them in their own XML files, but they now use the same controller. That controller extends AbstractAppState. Actually it extends another class I created which extends AbstractAppState.



It seems to load the first screen fine, and the hover effects work. But the onClick handlers dont work anymore. I’ve tried changing them to methods defined in the parent class, and I’ve even tried the special clicked method that takes an x and a y parameter. But nothing seems to work, none of my breakpoints get hit. I’m not sure how to proceed in order to diagnose the problem. I’ve checked that the screen controller is correctly set to the new class - it is. The parent element does have visibleToMouse=true (as I said it worked fine before the refactoring).



Some snippets:



This is done in my SimpleApplication class. MainGameController is another AbstractAppState, GameScreenController is the one giving problems.

[java]niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);



nifty = niftyDisplay.getNifty();



this.getGuiNode().detachAllChildren();

flyCam.setEnabled(true);

flyCam.setDragToRotate(true);



MainGameController mainGameController = new MainGameController(this, flyCam, rootNode);

String[] screens = new String[]{“GUI/MainMenu.xml”, “GUI/SinglePlayerMenu.xml”, “GUI/MultiPlayerMenu.xml”, “GUI/ConnectToServerMenu.xml”, “GUI/OptionsMenu.xml”};

GameScreenController gameScreenController = new GameScreenController(nifty, flyCam, screens, settings, mainGameController);

stateManager.attach(gameScreenController);

stateManager.attach(mainGameController);



guiViewPort.addProcessor(niftyDisplay);

gameScreenController.showMenu(“mainMenu”);[/java]



Excuse me for posting the entire XML file but I think it makes it easier to see. You can see the first onClick was changed for debugging.

[xml]<?xml version=“1.0” encoding=“UTF-8”?>

<nifty xmlns=“http://nifty-gui.sourceforge.net/nifty.xsd” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://nifty-gui.sourceforge.net/nifty.xsd http://nifty-gui.sourceforge.net/nifty.xsd”>

<useStyles filename=“nifty-default-styles.xml” />

<useControls filename=“nifty-default-controls.xml” />

<!-- +++++++++++++++++++++++++++++++++++++++ -->

<!-- start screen -->

<!-- +++++++++++++++++++++++++++++++++++++++ -->

<screen id=“mainMenu” controller=“GUI.GameScreenController”>

<layer id=“layer” backgroundColor="#000f" childLayout=“center”>

<panel id=“panel” height=“75%” width=“50%” align=“center” valign=“center” backgroundColor="#000f" childLayout=“vertical” visibleToMouse=“true”>

<panel id=“headingPanel” childLayout=“center” align=“center” valign=“center” color=“000f” height=“25%” width=“100%” padding=“50px,0px,50px,0px” >

<text id=“headingText” font=“Fonts/Vinque_32B.fnt” color="#8B0000ff" text=“Main Menu” align=“center” valign=“center” size=“24” width=“100%” height=“100%” />

</panel>

<panel id=“singlePlayerPanel” childLayout=“center” align=“center” valign=“center” color=“000f” height=“15%” width=“100%”>

<text id=“singlePlayerText” font=“Fonts/Vinque_32B.fnt” color="#C6E2FFff" text=“Single Player” align=“center” valign=“center” size=“24” width=“100%” height=“100%” />

<interact onClick=“clicked()”/>

<effect>

<onHover name=“border” color="#822f" post=“true” />

<onEnabled name=“renderQuad” startColor="#2228" endColor="#2220" post=“true” length=“150” />

<onDisabled name=“renderQuad” startColor="#2220" endColor="#2228" post=“true” length=“150” />

</effect>

</panel>

<panel id=“multiPlayerPanel” childLayout=“center” align=“center” valign=“center” color=“000f” height=“15%” width=“100%”>

<text id=“multiPlayerText” font=“Fonts/Vinque_32B.fnt” color="#C6E2FFff" text=“Multi Player” align=“center” valign=“center” size=“24” width=“100%” height=“100%”/>

<interact onClick=“showMenu(&quot;multiPlayerMenu&quot;)”/>

<effect>

<onHover name=“border” color="#822f" post=“true” />

<onEnabled name=“renderQuad” startColor="#2228" endColor="#2220" post=“true” length=“150” />

<onDisabled name=“renderQuad” startColor="#2220" endColor="#2228" post=“true” length=“150” />

</effect>

</panel>

<panel id=“optionsPanel” childLayout=“center” align=“center” valign=“center” color=“000f” height=“15%” width=“100%”>

<text id=“optionsText” font=“Fonts/Vinque_32B.fnt” color="#C6E2FFff" text=“Options” align=“center” valign=“center” size=“24” width=“100%” height=“100%” />

<interact onClick=“showMenu(&quot;optionsMenu&quot;)”/>

<effect>

<onHover name=“border” color="#822f" post=“true” />

<onEnabled name=“renderQuad” startColor="#2228" endColor="#2220" post=“true” length=“150” />

<onDisabled name=“renderQuad” startColor="#2220" endColor="#2228" post=“true” length=“150” />

</effect>

</panel>

<panel id=“exitPanel” childLayout=“center” align=“center” valign=“center” color=“000f” height=“15%” width=“100%”>

<text id=“exitText” font=“Fonts/Vinque_32B.fnt” color="#C6E2FFff" text=“Exit” align=“center” valign=“center” size=“24” width=“100%” height=“100%” />

<interact onClick=“exitGame()”/>

<effect>

<onHover name=“border” color="#822f" post=“true” />

<onEnabled name=“renderQuad” startColor="#2228" endColor="#2220" post=“true” length=“150” />

<onDisabled name=“renderQuad” startColor="#2220" endColor="#2228" post=“true” length=“150” />

</effect>

</panel>

</panel>

</layer>

</screen>

</nifty>

[/xml]

Is the class still GUI.GameScreenController? I guess it should say mygame.MainGameController in the XML now.

Yes the class is still GUI.GameScreenController. MainGameController has nothing to do with the GUI. It is just passed in as a parameter to the GameScreenController.



EDIT: I should probably explain, I dont have a source package to which all of these packages belong. So GUI is a root package itself if that makes sense. I may fix that one day.

So your java classes are in a package called “GUI”? Else it does not make sense to me…?

Yes. And the XML files are in the same folder.



Well not all of the classes obviously. The SimpleApplication is in the Game package.



EDIT:MainGameController is also in the Game package.

Ok, if I read things right, nifty is looking for a method named public void clicked() inside the GUI.GameScreenController class.

What is the exact error you are receiving?

That and I’ve also tried showMenu() (with a string parameter) and showSinglePlayermenu() and showMultiPlayerMenu() (without any parameters). Neither works.



I dont get any exceptions and none of my breakpoints are hit. I dont see anything in the Nifty output.



Maybe I’ll add some more logging to Nifty tonight, to see why it is not happening.



The other thing I’m going to try is to make a test class that doesnt use inheritance. GameScreenController extends a class that implements ScreenController - perhaps that is why it is not receiving the event? I’ll also put a breakpoint in its bind() method - if that isnt caught then it is definitely not receiving events. I mean the GameScreenController code is definitely run, but then I do call its constructor directly. I’ll have another look tonight.

Okay what seemed to work is this:



[java]MainGameController mainGameController = new MainGameController(this, flyCam, rootNode);

String[] screens = new String[]{“GUI/MainMenu.xml”, “GUI/SinglePlayerMenu.xml”, “GUI/MultiPlayerMenu.xml”, “GUI/ConnectToServerMenu.xml”, “GUI/OptionsMenu.xml”};

for(int i = 0; i < screens.length; i++)

{

nifty.addXml(screens);

}

nifty.gotoScreen(“mainMenu”);

TestScreenController gameScreenController = (TestScreenController)nifty.getScreen(“mainMenu”).getScreenController();

//GameScreenController gameScreenController = new GameScreenController(nifty, flyCam, screens, settings, mainGameController);

//TestScreenController gameScreenController = new TestScreenController(nifty, flyCam, screens, settings, mainGameController);



stateManager.attach(gameScreenController);

stateManager.attach(mainGameController);



guiViewPort.addProcessor(niftyDisplay);[/java]



TestScreenController is the controller that I created to test the theory that the problem is related to inheritance. Its not, so I’ll change it back.



But this does present a slight problem, because even though the events now seem to be hooking up, I cant use the default constructor. Which means I need to use a few setters prior to doing anything. It works but I dont really like it.



EDIT: Okay more testing. Its back to how it was, using the class that extends MenuScreenState. That works. However, what I’ve noticed is that it instantiates a new screen controller object for each screen that uses the same controller. In other words, if you have one controller shared between multiple screens (which I thought was recommended?), you will get one instance of the class per screen.



So I’ll need to think carefully about whether its actually worth it. Might not be worth the overhead of additional classes because most are fairly small. Its a pity I only know this now, I wouldnt have bothered to refactor them into one class. It also means, if you want to use the appstate part of them, you need to attach each instance of the controller to your appstate. And make sure each of them has the variables it needs set - you cant use a non default constructor as I said.

Well…

When you let Nifty instantiate the screencontroller you get one per screen. You can however provide your own the moment you load the screen. Through this method you should be able to have one instance for all screens. Check the nifty API for the different methods to load the XML.

Thats if you use fromXml. AddXML doesnt support a second parameter.



EDIT: In other words, I would need to put all of the screens into one XML, which I dont think is good practice. One view per file.

Sorry for double post, I think I might have figured out a solution which provides what I want, which is a single controller class, a single instance of that class, and multiple XML files (one for each view/screen).



What I’m going to do is instantiate a SequenceInputStream and pass that into nifty’s fromXMl. FromXML will allow me to instantiate my own ScreenController - which also means I can use any constructor that I like. The only thing that might cause a problem is if there are statements at the top of a nifty XML that are not supposed to be repeated. I suppose I could just remove them from all XML files except for the main menu one. Then only one copy of those statements would exist in the merged nifty XML files.



I’m going to try this tonight when I get home from work and see if it works.



I’ve got it working at the moment with multiple instances of my screencontroller, but I’m still wanting a more elegant solution.