简体   繁体   中英

How can I fill a combobox with the selection from another combobox? JavaFX

I've started creating a GUI for a March Madness bracket generator by displaying all 64 teams for round1 as Labels and now I'm trying to create a ComboBox dropdown menu for each match.

I've created a ComboBox for 2 matches and now I want to create a new ComboBox that pulls its options from the other two ComboBox 's before it. So in the example diagram below, the new ComboBox should have the options Duke and VCU for the user to choose from.

           (2 combo boxes)        (new combo box)

Duke------
               Duke ---   
ND St. ---

                                        X

VCU -----
               VCU ---
UCF -----  

How can I do so?

public class ControlPanel extends Application
{

    @Override
    public void start(Stage primaryStage) {

        primaryStage.setTitle("March Madness 2019 Generator");

        BorderPane componentLayout = new BorderPane();
        componentLayout.setPadding(new Insets(20,0,20,20));

        final FlowPane choicePane = new FlowPane();
        choicePane.setHgap(100);
        Label choiceLbl = new Label("Match1");

        ArrayList<Team> round1 = new ArrayList<Team>();

        round1.add(new Team("Duke", 0.670, 1));                    //0
        round1.add(new Team("North Dakota St", 0.495, 16));
        round1.add(new Team("VCU", 0.609, 8));
        round1.add(new Team("UCF", 0.606, 9));


        //The choicebox is populated from an observableArrayList
        ChoiceBox r2Match1 = new ChoiceBox(FXCollections.observableArrayList(  match(round1, 0, 1)   ));

        //Add the label and choicebox to the flowpane
        choicePane.getChildren().add(choiceLbl);
        choicePane.getChildren().add(r2Match1);

        //put the flowpane in the top area of the BorderPane
        componentLayout.setTop(choicePane);

        //Add the BorderPane to the Scene
        Scene appScene = new Scene(componentLayout,500,500);
        //Add the Scene to the Stage
        primaryStage.setScene(appScene);
        primaryStage.show();
    }

    private ArrayList<Team> match(ArrayList<Team> roundPullFrom, int team1, int team2) {
        ArrayList<Team> temp = new ArrayList<Team>();
        temp.add(roundPullFrom.get(team1));
        temp.add(roundPullFrom.get(team2));
        return temp;
    }

}

The structure of your problem is a tree. So you might want to have your solution support that structure. Either you use a Binary Tree data structure to resemble the tournament or you create such a structure by eg having classes like:

class Team {
   String name;
}

class Match {
   Team teamA;
   Team teamB;
   String where;
   Date when;

   public Team selectWinner() { 
     ...
   }
}

class Tournament {
   List<Team> teams;
   List<Match> getMatches(int round,List<Team> teams) {
     List<Match> matches=new ArrayList<Match>)();
     if (round==1) {
       for (teamIndex=1;teamIndex<=teams.size();teamIndex+=2) {
         Match match=new Match(teams[teamIndex-1],teams(teamIndex)];
         matches.add(match);
       }
     } else { 
       List<Team> winners=new ArrayList<Team>();
       for (Match match:getMatches(round-1)) {
         winners.add(match.selectWinner());
       }
       return getMatches(1,winners);
     }
   }
}

From this structure you can then derive the necessary gui components to make the selection dynamic and let the GUI components take their values from the Tournament, Match and Team classes.

Combine ComboBox es pairwise using the approach posted in my previous answer until you're left with a single ComboBox .

The following code layouts the nodes in something that resembles a tree structure too, but you could easily decouple the layout by keeping every round in a data structure instead of overwriting the values of a single array. (Since you'll want to access the data, you should store the combos in a proper data structure anyways.)

private static ComboBox<String> createCombo(double x, double y, double width) {
    ComboBox<String> comboBox = new ComboBox<>();
    comboBox.setLayoutX(x);
    comboBox.setLayoutY(y);
    comboBox.setMaxWidth(Region.USE_PREF_SIZE);
    comboBox.setMinWidth(Region.USE_PREF_SIZE);
    comboBox.setPrefWidth(width);

    return comboBox;
}

private static Label createLabel(String text, double maxWidth) {
    Label label = new Label(text);
    label.setMaxWidth(maxWidth);
    return label;
}

@Override
public void start(Stage primaryStage) {
    String[] teams = new String[64];
    for (int i = 0; i < teams.length; i++) {
        teams[i] = Integer.toString(i);
    }
    final double offsetY = 30;
    final double offsetX = 100;
    final double width = 90;

    Pane root = new Pane();

    // array storing the comboboxes
    // combos for previous round are at the lowest indices
    ComboBox<String>[] combos = new ComboBox[teams.length / 2];

    // create initial team labels & comboboxes
    for (int i = 0, offsetTeams = 0; i < combos.length; i++, offsetTeams += 2) {
        Label label = createLabel(teams[offsetTeams], width);
        double y = offsetTeams * offsetY;
        label.setLayoutY(y);
        root.getChildren().add(label);

        label = createLabel(teams[offsetTeams+1], width);
        label.setLayoutY(y+offsetY);

        ComboBox<String> comboBox = createCombo(offsetX, y + offsetY / 2, width);
        comboBox.getItems().addAll(teams[offsetTeams], teams[offsetTeams+1]);
        combos[i] = comboBox;

        root.getChildren().addAll(label, comboBox);
    }

    double x = 2 * offsetX;
    int count = combos.length / 2; // combos still left for the next round

    for (; count > 0; count /= 2, x += offsetX) { // for each round
        // create comboboxes combining the combos from previous round pairwise
        for (int i = 0, ci = 0; i < count; i++, ci+=2) {
            // get combos pairwise
            ComboBox<String> c1 = combos[ci];
            ComboBox<String> c2 = combos[ci+1];

            ComboBox<String> combo = createCombo(x, (c1.getLayoutY() + c2.getLayoutY()) / 2, width) ;

            // combine data from previous round
            ChangeListener<String> listener = (o, oldValue, newValue) -> {
                final List<String> items = combo.getItems();
                int index = items.indexOf(oldValue);
                if (index >= 0) {
                    if (newValue == null) {
                        items.remove(index);
                    } else {
                        items.set(index, newValue);
                    }
                } else if (newValue != null) {
                    items.add(newValue);
                }
            };
            c1.valueProperty().addListener(listener);
            c2.valueProperty().addListener(listener);

            root.getChildren().add(combo);
            combos[i] = combo;
        }
    }

    primaryStage.setScene(new Scene(new ScrollPane(root), 600, 400));
    primaryStage.show(); 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM