1

I'm trying to set up a character manager for a LARP game. In the game a character could have more than one role (1 or 2). I want to generate the character using two comboboxes, both drawing from the same enum called Role. That in itself is easy:

    JComboBox roleFirstComboBox = new JComboBox(IPlayerCharacter.Role.values());
    JComboBox roleSeondComboBox = new JComboBox(IPlayerCharacter.Role.values());

Except if say our roles are: Coder, Programmer, SysAdmin, Nerdfighter you can be a Coder/Coder. So the second box needs to exclude whatever is selected in the first box.

One thought I had was making a function to pass the enums to a List of some sort and then when one JComboBox is picked, it uses one of the standard container methods to find the asynchronous union(?) everything in Box2 that isn't in Box1. This seems horrible. I know the solution uses a JComboBoxModel but how to adapt this to my enums, I don't know.

What is the best way to get this kind of functionality?

Edit:

Here is the code I'm using currently, it just lives inside my pane, so I don't think it needs anymore context. Let me know otherwise, if need be.

Creating the comboBoxes

JComboBox roleFirstComboBox = null;
JComboBox roleSecondComboBox = null;
...
roleFirstComboBox = new JComboBox(IPlayerCharacter.Role.values());
roleSecondComboBox = new JComboBox(IPlayerCharacter.Role.values());

Adding an actionListener:

roleFirstComboBox.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent arg0) {
        roleSecondComboBox.removeAll();
        roleSecondComboBox.addItem(null);
        for (Role role : IPlayerCharacter.Role.values()) {
            if (role != roleFirstComboBox.getSelectedItem()) {
                    roleSecondComboBox.addItem(role);
            } 
        }
    }
});
roleFirstComboBox.setSelectedIndex(0);

Adding it to the groupLayout:

.addComponent(roleFirstComboBox)
.addComponent(roleSecondComboBox))

The final look, and bug:

enter image description here

Does this help?

Community
  • 1
  • 1
AncientSwordRage
  • 7,086
  • 19
  • 90
  • 173
  • you'll need it both ways, don't you? plus a possibilty to change one's mind. The typical widget for this would be two lists, one would be to choose the roles from, the other would be the choosen roles. Selection in each would remove from that and add to the other – kleopatra Jul 24 '12 at 09:41
  • Just one way, as it's possible to have just one role, and yes you can change your mind but that will be handled seperately on a different page. A List would work, but for now I'd like to try and get it to work with the comboboxes. – AncientSwordRage Jul 24 '12 at 09:48
  • This code works on my end, how are you creating the comboboxes? – Jacob Raihle Jul 24 '12 at 09:55
  • hmm ... don't quite understand the ui: what should happen if a) user selects an item in the first, b) user selects an item in the second c) user selects another item in the first? – kleopatra Jul 24 '12 at 10:04
  • not two, _another_ (that's the change-of-mind scenario) – kleopatra Jul 24 '12 at 10:58
  • ookay, I think I'm getting nearer: the two roles have a different weight? That is, as _another first_ I could select the same item as the second, but then wouldn't have a second; or I could select any other, then the second would remain the same? – kleopatra Jul 24 '12 at 11:14
  • 2
    giving up :-) Anyway, the reason for the bug is that you don't remove the _items_ but the _subcomponents_ of the combo... (hint: carefully compare yours with the solutions given) – kleopatra Jul 24 '12 at 11:56
  • @kleopatra Thanks, I'm deleting my irrelevant comments now. – AncientSwordRage Jul 24 '12 at 12:09

2 Answers2

1

Add an ActionListener to the first combo box. When the action is triggered, reset the model on the second combo box to the full list of roles, and then use removeItem(Object) to remove the already selected role from the second box. Alternately, empty the model and re-add all items except for the selected one:

private enum Roles {CODER, MANAGER, USER}

JComboBox box1 = new JComboBox(Roles.values());
JComboBox box2 = new JComboBox();
public RoleSelection() {
    box1.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            box2.removeAllItems();
            box2.addItem(null); // For those with only one role
            for (Roles role : Roles.values()) {
                if (role != box1.getSelectedItem()) {
                    box2.addItem(role);
                }
            }
        }
    });
    // Trigger a selection even to update the second box
    box1.setSelectedIndex(0);

    add(box1, BorderLayout.NORTH);
    add(box2, BorderLayout.SOUTH);
    pack();
    setDefaultCloseOperation(EXIT_ON_CLOSE);
}

public static void main(String[] args) {
    new RoleSelection().setVisible(true);
}
Jacob Raihle
  • 3,720
  • 18
  • 34
  • I'm not sure if you know what I'm doing, though stop me if I just don't get what you're on about. I don't see how `removeItem(Object)` will remove an item from the enum the second box can select from, which is defined elsehwere. – AncientSwordRage Jul 18 '12 at 13:03
  • 1
    @Pureferret `JComboBox#removeItem` will remove the given item from the model of that combo box. It won't be removed from the enum, only from the list of values selectable in the combo box. See my edit, though I ended up implementing it a bit differently. – Jacob Raihle Jul 18 '12 at 14:42
  • Jacob, I've implemented this in my code, but I'm getting duplicates in the comboBox. I have the first list, and then a gap and then the reduced list. Should I be creating a model for both boxes, or does Swing do this auto-magically? – AncientSwordRage Jul 23 '12 at 16:25
  • Swing automatically creates a model for each combobox unless you give it one to use. Please edit your code into the question so we can help :) – Jacob Raihle Jul 24 '12 at 08:27
  • Jacob, I've added it to my OP. – AncientSwordRage Jul 24 '12 at 09:24
  • @Pureferret Do you have more than one ActionListener attached to the first box? If not that, I'm out of ideas - your code both looks right and runs right on my machine. It might help if you could post an [SSCCE](http://sscce.org) . – Jacob Raihle Jul 24 '12 at 11:07
  • one though I'ver just had is thatit starts out with options selected. Is there a way to nullify this behaviour? Would that help? – AncientSwordRage Jul 24 '12 at 11:16
  • You can `setSelectedIndex(-1)`, but I don't think it would help. – Jacob Raihle Jul 24 '12 at 11:32
1

You can use an EnumSet for each group to keep them separate.

Edit: In your enum, you can make a Set for each group like this,

Set<Resolution> peon = EnumSet.of(Role.Coder, Role.Programmer);

Then you can make models out of them,

for (Role r : Role.peon) {
    System.out.println(r.toString());
}

Then just change the models as needed.

Catalina Island
  • 7,027
  • 2
  • 23
  • 42
  • THis sounds good, but how does this work? After some googling it looks like I could feed the model something like `EnumSet.noneOf(/*whatever is currently in the other comboBox*/)`? – AncientSwordRage Jul 18 '12 at 14:26
  • Thanks, but I don't think this is going to work with my comboBoxes. – AncientSwordRage Jul 18 '12 at 14:46
  • +1 For `Set`. See also this related [example](http://stackoverflow.com/a/3191882/230513) showing how to change models dynamically. – trashgod Jul 18 '12 at 19:31