Creating Elements Dynamically

I am trying to extend my game on the client side by adding controls dynamically but I can’t wrap my head around this Nifty java builder api.



I get the screen with nifty.getScreen(“screen”),



I call screen.getLayerElement(“layer”) and addElement using the ButtonBuilder class and I call screen.layoutElements(); at the end. it seems like this is the way to do it but the gui doesn’t render at all.



What is the best way to add a control to Nifty dynamically?

That sounds like it should work. Have you thought about using the menu control though? You can add menu items to that and the control adds the buttons for you…

Doesn’t fit with my design goals. I like the idea of being able to add controls whenever.

The xml is the HelloJme.xml slightly modified.

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

<nifty>

<screen id="ui" controller="client.Game">

<layer id="layer" backgroundColor="#0000" childLayout="center">

<panel id="panel" height="25%" width="35%" align="center" valign="center" backgroundColor="#f60f" childLayout="center" visibleToMouse="true">

<interact onClick="quit()"/>

<effect>

<onStartScreen name="move" mode="in" direction="top" length="300" startDelay="0" inherit="true"/>

<onEndScreen name="move" mode="out" direction="bottom" length="300" startDelay="0" inherit="true"/>

<onHover name="pulsate" scaleFactor="0.008" startColor="#f600" endColor="#ffff" post="true"/>

</effect>

<text id="text" font="aurulent-sans-16.fnt" color="#000f" text="Hello from jME3" align="center" valign="center" />

</panel>

</layer>

</screen>

<screen id="end">

</screen>

</nifty>[/xml]

Heres my code for building the screen.

[java] final String id = "button_" + ID.newAlphaNumericID(4);



Screen screen = nifty.getScreen("ui");

screen.addLayerElement(new LayerBuilder("layer"+id)

{

{

childLayoutVertical();



panel(new PanelBuilder()

{

{

childLayoutAbsolute();



control(new ButtonBuilder(id, text)

{

{

childLayoutAbsolute();



align(Align.Center);

valign(VAlign.Center);

height(String.valueOf(height));

width(String.valueOf(width));

}

});

}

});

}

}.build(nifty, screen, screen.getRootElement()));

screen.layoutLayers();[/java]

  1. Don’t call screen.addLayerElement() … that is done internally by the “new LayerBuilder(“layer”+id) { … }.build()” call
  2. The parent panel of your button is using childLayoutAbsolute(); This means you need to provide x, y, width and height properties for the button
  3. childLayoutAbsolute() in the ButtonBuilder would influence all child elements of the button. Since you don’t have any - and since it is a button it’s unlikely that it would have any you should remove this as well.
  4. align(Align.Center) and valign(Valign.Center) will only work when the parent panel has a childLayoutCenter() but not for childLayoutAbsolute()



    [java] final String x = "20px";

    final String y = "30px";

    final String height = "50px";

    final String width = "250px";

    new LayerBuilder("layer"+id)

    {

    {

    childLayoutVertical();



    panel(new PanelBuilder()

    {

    {

    childLayoutAbsolute();



    control(new ButtonBuilder(id, text)

    {

    {

    // childLayoutAbsolute();

    // align(Align.Center);

    // valign(VAlign.Center);

    x(String.valueOf(x));

    y(String.valueOf(y));

    height(String.valueOf(height));

    width(String.valueOf(width));

    }

    });

    }

    });

    }

    }.build(nifty, screen, screen.getRootElement());

    screen.layoutLayers();[/java]

I got this working after I found the “nifty bible”. Explained a lot and helped me quite a bit.



[java] public static String newButton(final String text, PyFunction func) {

checkInit();



final String id = “button_” + ID.newAlphaNumericID(8);



Screen screen = nifty.getCurrentScreen();

Element layer = screen.findElementByName(“baseLayer”);

layer.add(new ButtonBuilder(id, text){{

childLayoutCenter();

visibleToMouse(true);

interactOnClick(“handleControlOnClick(” + id + “)”);

}}.build(nifty, screen, layer));

UIManager.instance.registerOnClick(id, func);

return id;

}[/java]

“baseLayer” layout = “absolute” so that buttons can be placed on x and y coords.



and called from jython

[java]import game



def test(control_id):

print("Hello from " + control_id)

game.UI.hide(control_id)



game.UI.newButton(“Test”, test)

game.UI.newWindow(“Test Window”, 50, 50, 200, 200)[/java]

Thanks for your help too void now I just need to figure out the “style” format. What Nifty needs is a styling tool.

Again, don’t call “layer.add()” on your own. The the buttonBuilder.build() call will already do that for you …