7
\$\begingroup\$

In a prototype 4X space game that I am working on recently, I have two different scroll panes to show the ships and the stars of the player. The ships are displayed in a vertical scroll pane on the right side of the screen, and the stars are displayed in a horizontal scroll pane running along the bottom. Here is a picture for the sake of clarity:

ship and star panes

With the vertical scroll pane, displaying the labels along with the images is very straightforward. When iterating over the list of ships, a label is added for each ship, then a row, then the ship image.

The horizontal scroll pane presents a problem, however. I want to have the label displayed above the corresponding image. Accomplishing this is a bit more complicated than simply adding a row between each element in the table.

I thought about having two lists, iterating over the first list and getting the correct element from the second list based on the index. Instead of doing this, I went with a Map<Label, Image>. I'm not sure about this decision, and would love feedback on this approach. It feels wrong to be using a Map here, because I will never be using it to look up the values based on the keys.

First, I have this method that creates the contents that will be used when building the scroll pane:

private void createContents() {
    this.contents = new HashMap<Label, Image>();

    for (Star star : this.game.getPlayerStars()) {

        Image starImage = new Image(this.libGDXGame.starTextures.get(star.type));
        starImage.addListener(new StarClickListener(star) {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                StarScrollPane.this.gameScreen.playerClickedStar(star);
            }
        });

        Label starLabel = new Label(star.type.name(), this.libGDXGame.skin);

        this.contents.put(starLabel, starImage);
    }
}

Then I have another method that actually creates the table and adds the contents to it like this:

    for (Label label : this.contents.keySet()) {
        this.starTable.add(label);
    }

    this.starTable.row();

    for (Image image : this.contents.values()) {
        this.starTable.add(image).width(width).height(height);
    }

By adding all of the labels to the table, then one row, then all of the images, they line up perfectly.

\$\endgroup\$
7
\$\begingroup\$

A HashMap does not guarantee any order whatsoever, so that is a bad idea to use.

Your Image and Label belongs together, so make a class where they actually do belong together.

public class StarView {
    private final Label label;
    private final Image colorImage;
    // constructor and stuff...
}

private void createContents() {
    this.contents = new ArrayList<StarView>();

    for (Star star : this.game.getPlayerStars()) {

        Image starImage = new Image(this.libGDXGame.starTextures.get(star.type));
        starImage.addListener(new StarClickListener(star) {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                StarScrollPane.this.gameScreen.playerClickedStar(star);
            }
        });

        Label starLabel = new Label(star.type.name(), this.libGDXGame.skin);

        this.contents.add(new StarView(starLabel, starImage));
    }

    for (StarView starView : this.contents) {
        this.starTable.add(starView.label);
    }

    this.starTable.row();

    for (StarView starView : this.contents) {
        this.starTable.add(starView.image).width(width).height(height);
    }
}

This could be combined with @Vogel's suggestion about changing the layout manager. Or you could make the StarView extend Actor and put it in a horizontal group.

\$\endgroup\$
6
\$\begingroup\$

I think you're using the wrong layout manager for this problem. What you seem to be looking for is a grid layout or even a small container Pane.

Consider:

for (Map.Entry<Label, Value> entry : contents) {
    this.starTable.add(createPane(entry.getKey(), entry.getValue());
}

This allows you to painlessly line these two things up. In addition to that you may want to look into finding a Tuple or Pair you can use so that you can actually go with a List<Pair<Label, Image>> instead of the hack-around with a Map

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.