JavaFX - 改变FlowPane中子项的顺序

时间:2013-09-06 22:07:20

标签: java javafx-2 javafx

我有一个JavaFX 2.2 FlowPane,希望它的孩子能够按需更改订单。

我发现了

Collections.sort( getChildren(), new Comparator(){...} );

导致异常

java.lang.IllegalArgumentException: Children: duplicate children added: parent = ...

我还尝试使用子节点toFront()方法进行排序(如How to change order of children in JavaFX所示),但这似乎不会影响列表顺序。

还有什么我可以尝试的,或者是场景图中的孩子,他们的订单是不可变的吗?

1 个答案:

答案 0 :(得分:6)

更新:勘误

由于JavaFX 2.x中的错误,此答案的示例解决方案在JavaFX 2.x中不起作用。感谢assylias识别JavaFX 2.x错误:

  

当我运行程序时,列表不会更新,直到我水平调整窗口大小(垂直不做任何操作) - jdk 7u25 / Windows 7 x64。

该错误已在Java 8中修复,因此如果您使用Java 8,示例解决方案将起作用。

解决方案策略

  1. 根据流动窗格子项创建新集合。
  2. 对新系列进行排序。
  3. 将流窗格的子项设置为已排序集合的内容。
  4. 代码段

    ObservableList<Node> workingCollection = FXCollections.observableArrayList(
        flow.getChildren()
    );
    
    Collections.sort(workingCollection, new NodeComparator());
    
    flow.getChildren().setAll(workingCollection);
    

    示例输出

    排序前的示例输出:

    unsorted

    排序后的示例输出:

    sorted

    示例应用

    import javafx.application.Application;
    import javafx.collections.*;
    import javafx.event.*;
    import javafx.geometry.Pos;
    import javafx.scene.*;
    import javafx.scene.control.*;
    import javafx.scene.layout.*;
    import javafx.stage.Stage;
    
    import java.util.*;
    
    public class FlowGo extends Application {
        private final ObservableList<Label> labels = FXCollections.observableArrayList(
            createLabel("oranges"),
            createLabel("apples"),
            createLabel("pears"),
            createLabel("peaches"),
            createLabel("bananas")
        );
    
        @Override public void start(Stage stage) {
            FlowPane flow = createFlow();
    
            VBox layout = new VBox(10);
            layout.getChildren().setAll(
                flow,
                createActionButtons(flow)
            );
            layout.setAlignment(Pos.CENTER);
            layout.setStyle("-fx-padding: 10px; -fx-background-color: cornsilk;");
    
            stage.setScene(new Scene(layout));
            stage.show();
        }
    
        private HBox createActionButtons(final FlowPane flow) {
            Button sort = new Button("Sort");
            sort.setOnAction(new EventHandler<ActionEvent>() {
                @Override public void handle(ActionEvent actionEvent) {
                    ObservableList<Node> workingCollection = FXCollections.observableArrayList(
                        flow.getChildren()
                    );
    
                    Collections.sort(workingCollection, new NodeComparator());
    
                    flow.getChildren().setAll(workingCollection);
                }
            });
    
            Button reset = new Button("Reset");
            reset.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent actionEvent) {
                    flow.getChildren().setAll(labels);
                }
            });
    
            HBox buttonBar = new HBox(10);
            buttonBar.getChildren().addAll(
                sort,
                reset
            );
            buttonBar.setAlignment(Pos.CENTER);
    
            return buttonBar;
        }
    
        private FlowPane createFlow() {
            FlowPane flow = new FlowPane();
            flow.setHgap(10);
            flow.setVgap(10);
            flow.getChildren().setAll(labels);
            flow.setAlignment(Pos.CENTER);
            flow.setStyle("-fx-padding: 10px; -fx-background-color: lightblue; -fx-font-size: 16px;");
    
            return flow;
        }
    
        private Label createLabel(String text) {
            Label label = new Label(text);
            label.setUserData(text);
    
            return label;
        }
    
        public static void main(String[] args) { launch(args); }
    
        private static class NodeComparator implements Comparator<Node> {
            @Override
            public int compare(Node o1, Node o2) {
                String s1 = (String) o1.getUserData();
                String s2 = (String) o2.getUserData();
    
                return s1.compareTo(s2);
            }
        }
    }