scene2d.ui Selection

scene2d.ui’s List has never been terribly feature-packed, mostly because it only really sees use in SelectBox. I ended up needing it for skinning in Spine, so it got some love.

First, it can now draw a background which makes it easier to use outside of a ScrollPane. I figured even a Label has a background in its style, so why not.

Next I needed multiple selection, so I set off implementing it. While this seems like such a simple task, just managing a list of selected objects, it turns a proper implementation is quite a chunk of code: more than 250 lines. This is literally larger than the rest of the List implementation! SelectBox and Tree also have selection, and their implementations aren’t really complete. Given this, I decided to create a class called Selection which handles that, and List, SelectBox, and Tree can use it.

Selection turned out pretty nice. At its core it is an ObjectSet with set, add, remove, clear methods. The choose method handles the logic for changing the selection based on user interaction and has features like multiple selection, holding ctrl, toggle, etc. When the selection is changed a ChangeEvent is fired on an actor. If the event is cancelled, the change to the selection is reverted.

Now the bad news, List, SelectBox, and Tree had to change to accomodate the new class. Here are the API changes that may impact you:

  • List and SelectBox previously used strings for the items and you had to correlate the string or selected index back to your list of actual objects. Now they use generics, so you can store your actual objects in the widget, eg List. To get the old behavior, use List or SelectBox.
  • List and SelectBox no longer take items in their constructor. Instead, call setItems after construction. There is now a setItems that takes varargs, which is convenient.
  • Most selection methods having moved to Selection, which you get from getSelection(), but a few stayed behind:
    • getSelection() -> getSelected() or getSelection().first()
    • setSelection() -> setSelected() or getSelection().set()
    • getSelectionIndex() -> getSelectedIndex()

As always, sorry for the API breakage! This effort and your pain is for the greater good. I had to fix up my 50k+ LOC scene2d.ui application so, as your dad probably used to say, this hurts me more than it hurts you. 😉

22 thoughts on “scene2d.ui Selection

  1. Thanks for all your work on scene2d.
    I love it and many other people too as evidenced by this little excerpt from libgdx irc channel.

    [16:07] scene2d should be an extension anyway
    [16:07] na scene2D is core because its essential to create a game!
    [16:08] lies
    [16:08] world extends Stage
    [16:08] 😀
    [16:08] Scene2d is wonderful for making games
    [16:08] scene2d is not essential but is great for ui and animations 😉
    [16:08] I want to have children with Scene2D
    [16:11] lol that’s obscene2d 😀

  2. I have always considered scene2D.ui unnecessary for games, but I have to admit it is VERY impressive in Spine2D. Maybe I’ll give it a chance one day.

    Just a thought (a little unrelated because it’s about scene2D, not scene2D.ui) – I wanted to report it as a feature request in the bug tracker, but maybe here it will receive some feedback from others. In scene2D there is Actions.forever and Actions.repeat – I don’t know how others use it by I almost 99% of the time put Actions.sequence inside – it would be nice if forever and repeat allowed multiple actions just like sequence does… So instead of:

    forever(sequence(move, fadeout, move, fadein));

    We could just write:

    forever(move, fadeout, move, fadein)

  3. Hehe thanks! Don’t usually get much feedback from users. I guess a number of people have trouble getting started with scene2d.ui, but I’m not sure what to do to improve that.

  4. Don’t punish yourself by not using it. 😉

    Lots of actions could probably also be a sequence or parallel, but they can’t be both. Better to keep them separate. Write yourself a utility method, that is all Actions is, a bunch of utility methods.

  5. Yes you’re right. That’s a good quick reference about table showing its html-like api. But it’s just that and nothing more!
    I think that a kind of tutorial describing a sample project that shows the real power of scene2d, i.e. skins, tables, actions and main widgets, would make developer’s life easier. Actually, if you have something to play with you learn faster and easily identify what fits your needs.
    Personally I don’t use scene2d for the gameplay, but I think it’s perfect to animate splash screen and main screen, and to implement game settings ui.
    And it’s likely suitable for some board games too.
    It’s not a simple task, but putting all this together in a tutorial would likely entice developers to use scene2d for this kind of stuff which is its real strength imo.

  6. The docs show how to use all features of TableLayout, people are expected to try it out on their own. I guess we could do a wiki page that walks you through creating some UI from nothing.

  7. I think the problem is that people don’t even know what you can really do with scene2d. Well this is what happened to me until I read the book mentioned above.
    But yes, a wiki page might help.

  8. 🙁 this broke my code….. i have selectboxes in a controller configuration screen with some custom code … there are sometimes duplicate names in it (2 times: “Key/Mouse”)… now these duplicate names are always selected together… any ideas how i can fix that?

  9. Part of the problem is probably that people have no idea that they have to go to some other github repo to figure out how to use Table (which mostly hides the fact it uses what is essentially a third-party library). It probably also doesn’t help that the TableLayout javadocs are not included in the libgdx api docs.

  10. You did a great work with scene2D (and with all your lib), it’s the heart of my app (kryo, kryonet are great too).

    Not reaylly need to improve Scene2D but maybe stuff like this could be cool :

    – a use case documentation with example could be usefull (but it’s a huge works)
    – More controls (simple and high level like, grid, color picker, loader, etc…)

    – other cool skin

    And maybe a big book of ligbdx, with scene2D and other usefull api writed with mario and the badlogic team ?

  11. Hello and thanks for your hard work. Scene2d.ui is awesome.
    Anyway, I wanted to ask a question…
    Because of this update, I changed my code from
    selCharSkin = new SelectBox(CharacterSkin.values(), skinLibgdx);
    to
    selCharSkin = new SelectBox(skinLibgdx);
    selCharSkin.setItems(CharacterSkin.values());

    but it’s not working…

    Exception in thread “LWJGL Application” com.badlogic.gdx.utils.SerializationException: Error reading file: images/uiskin.json…

    Any ideas?

  12. I always find out about api changes when my compiles break. This o r is s nice change, though. I always thought the string based approach was not the best.

  13. Cant draw generic item from array, here code:

    /////////////////// Generic item:
    public class CharacterItem
    {
    public final String name;
    public final String sprite;
    public CharacterItem(String par_name, String par_sprite)

    {
    name = par_name;
    sprite = par_sprite;
    }

    @Override
    public String toString()
    {
    return name;
    }
    }

    /////////////////// Init array with generics
    playerCharacters = new Array();

    /////////////////// Create List
    charactersList = new List(skin);
    charactersList.setItems(playerCharacters);
    charactersList.setFillParent(true);
    charactersPane = new ScrollPane(charactersList, skin);
    charactersPane.setPosition(10, 220);
    charactersPane.setSize(260, 280);
    graphicSystem.addActorToHUD(charactersPane);

    In game i fill playerCharacters but i didnt see changes…

  14. I’m trying to use this but I’m getting a null pointer exception
    com.badlogic.gdx.scenes.scene2d.utils.Selection.fireChangeEvent(Selection.java:188)

    I’m guessing it has something to do with setting an actor but I’m not sure how to go about doing that. What kind of actors can be set to it? I tried a few and still got the same error.

  15. So I figured out that .setActor() has to be called before .add() otherwise you get a null pointer.
    Now, nothing is showing up. Obviously I’m not getting how to use this properly. Is it possible to get a simple example of how to build a Selection?

  16. Just say this now. I fixed the NPE when no actor is set. The actor is just for firing ChangeEvents when the selection changes, so no actor, no event is fired.

    Selection is just a small API over an ObjectSet. How are you wanting to use it?

  17. List copies the items into its own Array. I think it is safe to change it to set the List array to your array though, I’ll make the change.

  18. Make each item unique by using an object that returns the string in its toString rather than the strings themselves.

Leave a Reply

Your email address will not be published.