# Pairing Labels with Images when building a UI

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:

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));
@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.row();

for (Image image : this.contents.values()) {
}


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

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));
@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);

}

for (StarView starView : this.contents) {
}

this.starTable.row();

for (StarView starView : this.contents) {
}
}


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.

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 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