【问题标题】:How can I fill a combobox with the selection from another combobox? JavaFX如何用另一个组合框的选择填充组合框? JavaFX
【发布时间】:2019-10-20 15:01:49
【问题描述】:

我已经开始为 March Madness bracket 生成器创建一个 GUI,将第 1 轮的所有 64 支球队显示为 Labels,现在我正在尝试为每场比赛创建一个 ComboBox 下拉菜单。

我已经为 2 个匹配项创建了一个 ComboBox,现在我想创建一个新的 ComboBox,它从之前的其他两个 ComboBox 中提取其选项。所以在下面的示例图中,新的ComboBox 应该有Duke 和VCU 选项供用户选择。

           (2 combo boxes)        (new combo box)

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

                                        X

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

我该怎么做?

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

}

【问题讨论】:

    标签: java javafx arraylist combobox


    【解决方案1】:

    使用我的previous answer 中发布的方法将ComboBoxes 成对组合,直到剩下一个ComboBox

    以下代码也以类似于树结构的方式对节点进行布局,但您可以通过将每一轮保持在数据结构中而不是覆盖单个数组的值来轻松解耦布局。 (因为您要访问数据,所以无论如何您都应该将组合存储在适当的数据结构中。)

    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(); 
    }
    

    【讨论】:

    • 谢谢。我马上试试。我知道在数据结构中存储组合是正确的,但我之前没有使用数据结构的经验,所以我不知道该怎么做
    • @user128912901 teams 数组将包含实际应用程序中的团队名称。这里我没有硬编码任何团队名称,而是简单地使用包含数字 0、...、63 的字符串来简化代码。
    【解决方案2】:

    您的问题的结构是一棵树。因此,您可能希望您的解决方案支持该结构。要么使用Binary Tree data structure 来模拟锦标赛,要么通过例如创建这样的结构。有这样的类:

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

    然后,您可以从该结构派生必要的 gui 组件以使选择动态化,并让 GUI 组件从 Tournament、Match 和 Team 类中获取它们的值。

    【讨论】:

    • selectWinner 方法应该做什么?我希望用户选择方法的获胜者,而不是方法。
    • 这只是为了说明原理。例如。您可以简单地返回一个实例变量 Team 获胜者,如果它为空,则允许使用按钮选择它,如果它不为空,则将其显示为标签。这个想法是您可能希望采用 MVC 方法并将问题的模型/结构与带有标签和组合框的 gui 表示分离。从 Match 中导出标签并从 Match 中导出组合框非常简单……您需要解决即将到来的匹配的情况。为此,一个团队暂时可以成为“...的赢家”,并且需要涵盖这种情况。
    • 感谢您的评论,但我正在寻找一种从组合框中提取值并将其用作另一个组合框的选项的基本方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多