Storing objects in a listbox (Fixed)

Let me explain…



In my game I use several controls that I use to display information to the player. Like a DropDown box in the option screen, or a ListBox listing the bodies in a solar system or a galaxy node. Each of those items is displayed correctly; ie: customized toStrings() mehods are implemented in each class, but I have no reference to the objects themselves. So I can’t access their underlying structures. For the option screen DropDown, it would not a real issue as it can easily be parsed with the name since those are static. But I do use Localized strings, so the returned value could be pretty much anything. Finally, “event” (EventBus) doesn’t support returning the index, I can’t use that.



For the other example though, it would be much easier to simply be able to hold a hidden object that can be immediately referenced so no lookup has to be made. That same info panel is reused throughout the game depending on the current view (galaxy node view, solar system node view, etc). In the galaxy view, there can be up to 2000 objects and I feel it would be much better and faster to have those objects stored hidden from view inside the control. And again, since I’m using localized strings, I can’t parse the strings.



For some info about that info panel, here’s what I do with it:



When the user clicks on, for example, a planet in the list, a second listbox in the “popup” info panel displays that planet’s characteristics like, its G, radius, type of planet (gas, rocky, etc), moons, etc. Similar for stars and solar systems each having its distinct attributes. Moreover, there’s a viewport into that panel that will be used to display a closer look at the selected item.



Anyway. I don’t know if it would be practical or efficient (it could be disabled by default I guess) to have such a feature inside nifty. Of course it wouldn’t very hard to do it “by hand”, but since I remember these controls in VC++ have such hidden “fields”, I thought it would be a good idea to have that in nifty.







That’s the basic idea.



Now, I’m currently using a custom “model class” when adding items to the list box using an object.

[java]

public class ControlsModelClass {



private String label;

private Object obj;



public ControlsModelClass(final Object obj) {

label = obj.toString();

this.obj = obj;

}



public Object getObject() {

return obj;

}



@Override

public String toString() {

return label;

}

}

[/java]



Now, when the event is triggered:

[java]

@NiftyEventSubscriber(id=“stellarBodiesBox”)

public void onListBoxSelectionChanged(final String id, final ListBoxSelectionChangedEvent<ControlsModelClass> changed) {

if (!changed.getSelection().isEmpty())

System.out.println("Selection = " + changed.getSelection());

}

[/java]



changed is an array of “String”. In reality it’s a List but there’s nothing I can do to retrieve the getObject() method in ControlsModelClass.



What am I missing? Is is possible to do the above?

Why not extend the control class to add the field/List/ArrayList/whatever you need? Override the add, get, etc methods, or whatever they are called (I don’t use the predefined controls) to add in the custom fields, objects, etc you need to store and retrieve? There is no possible way void could guess what you want to do with the list box, and honestly, adding in features that “pre-guess” usage could potentially be VERY limiting to those who would never use them.



I personally suggest writing your complex control classes from the base elements/controls provided by Nifty to ensure they do exactly what you are looking for. The only controls I use from Nifty are the button and (now) label controls. All other scroll panels, list boxes, drop-downs, checkboxes, tree-views, etc, etc… can easily be developed using just these. And the best part is: They function EXACTLY the way YOU need them to!



// SOAP BOX ON //

Using this method, and handling events from jme instead of nifty (if it gets fixed), you can add mouse right-click & mouse wheel support easily as well.



Before:

You could determine the mouse position over a Nifty element and capture mouse wheel interaction. forward this to a custom scroll control and execute code to scroll the window.



Currently:

This no longer works :frowning:



Before:

You could determine the mouse position over a Nifty element and capture right click events. Convert them to left click and forward them to Nifty to show right-click menus ONLY when a right-click was used.



Currently:

This no longer works :frowning:



Before:

You could determine the mouse position over a Nifty elements and capture clicks. If they were no intended for your game, but for the GUI only, you could stifle them and point them to Nifty only.



Currently:

This decision is made for you and it no longer works :frowning:



There are more… buuuut… anyways

// SOAP BOX OFF//

I somehow agree.



But not only me could gain from that. Anyone wanting to hide an object as a reference could do so. You either use the object as you see fit or set it to null if you don’t want to use it and only use a String label if you don’t need the object.

Have you tried using your own ListBoxViewConverter? through this, you can actually add the complete object to the list and through this display those parts of it you want to display. Then, when something is selected, it “should” give you the original object instead of the string.

I do have a custom Converter (both for DropDown and ListBox), but I haven’t fiddle with those much. I was pretty certain those values were handled by the “ModelClass”. Unfortunately, I won’t have much time today to work on this, except maybe a couple of hours this morning.

It seems I’m too dense or too dumb to get it.



If I add an object like so:

[java]

lbc.addItem("-" + new ControlsModelClass(Galaxy.getGalaxy()));

[/java]



When I retrieve it, no matter what I’m passing addItem(), I always get a String upon getting it from the subscriber and I couldn’t find a way to get the Object stored in the ControlsModelClass.



[java]

public void onListBoxSelectionChanged(final String id, final ListBoxSelectionChangedEvent<ControlsModelClass> changed) {

ListBox lb = nifty.getCurrentScreen().findNiftyControl(id, ListBox.class);

if (lb.getFocusItem() != null) {

System.out.println(lb.getFocusItem().toString());

}

System.out.println("Selection = " + changed.getSelection());

// update the label in the panel with info from selection

nifty.getCurrentScreen().findControl(“selection_info”, LabelControl.class).setText(changed.getSelection().toString());

}

[/java]

Above, “changed” is ALWAYS the selected item’s value, a String. I somehow expected a reference to the class in the list (it’s always only 1 element since multiselect is off), as defined in ListBoxSelectionChangedEvent which defines it as:



[java]

private List<T> selection;

[/java]

So, in my head I should get back a List of ControlsModelClass, not an List of String.



Please someone explain to me where’s the big flaw in my thinking. I’m guessing here there’s something java does that I’m not aware of due to my noobiness. :frowning:

The problem is here:

[java]

lbc.addItem("-" + new ControlsModelClass(Galaxy.getGalaxy()));

[/java]



by adding the {"-" + } it automatically call the toString() method on your ControlsModelClass before adding it. This causes a String to be added instead of what you think, a ControlsModelClass.



if you want a “-” in front of your labe, you should handle this either in your ListBoxViewConverter class or in the toString method of your ControlsModelClass.

1 Like

Oh gawd. shakes head



I didn’t even want to put that bit at first, lucky I did. I can’t believe I didn’t see that one though.



:facepalm



Edit: And of course it now works as intented… At least my classes implementations are ok, only a stupid blunder. Lost perspective there I guess.