JavaFX列表视图元素中的奇怪行为

1aaf6o9v  于 2023-04-10  发布在  Java
关注(0)|答案(1)|浏览(112)

我有2个列表视图,在右边的一个我有三个“卡”(名称和值),每个都有一个按钮,当点击时会将该卡添加到中心列表中。我也可以点击中心列表中该卡的相同按钮来删除它。我的问题是,如果我添加两个或更多的卡到中心列表中,然后我继续删除它们,界面会变得奇怪,不删除它们或只删除一两个。

public class DeckManagement implements Initializable {
    private final SceneHandler sceneHandler = SceneHandler.getInstance();
@FXML
    private ListView<Card> rightList;

    @FXML
    private ListView<Card> centerList;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        rightList.setCellFactory(param -> new ListCell<Card>() {
            @Override
            protected void updateItem(Card card, boolean empty) {
                super.updateItem(card, empty);
                if (empty || card == null) {
                    setText(null);
                } else {
                    VBox container = new VBox();
                    Button cardButton = new Button("Add");
                    cardButton.setOnAction(event -> {
                        if (!card.isMoved()) {
                            centerList.getItems().add(card);
                            //rightList.getItems().remove(card);
                            card.setMoved(true);
                        }
                    });
                    container.getChildren().addAll(new javafx.scene.control.Label(card.toString()), cardButton);
                    setGraphic(container);
                }
            }
        });
        rightList.getItems().addAll(
            new Card("Card 1", 10),
            new Card("Card 2", 5),
            new Card("Card 3", 8)
        );
        centerList.setCellFactory(param -> new ListCell<Card>() {
            @Override
            protected void updateItem(Card card, boolean empty) {
                super.updateItem(card, empty);
                if (empty || card == null) {
                    setText(null);
                } else {
                    VBox container = new VBox();
                    Button cardButton = new Button("Remove");
                    cardButton.setOnAction(event -> {
                        card.setMoved(false);
                        centerList.getItems().remove(card);
                    });
                    container.getChildren().addAll(new javafx.scene.control.Label(card.toString()), cardButton);
                    setGraphic(container);
                }
            }
        });
    }
}
fdbelqdn

fdbelqdn1#

如果你的列表单元格变成非空的,它的updateItem(...)方法将被调用,其中Card为非空值,empty的值为false。在这种情况下,你将该单元格的图形设置为VBox
如果随后从ListView中删除了该单元格中显示的Card示例,并且该单元格变为空,则将调用updateItem(null, true)。但是,在本例中,updateItem(...)实现不会删除图形,因此图形仍然显示。
下面是一个应该可以工作的实现。我对它进行了重构,以避免重复创建新控件(这是非常低效的),并删除了不必要的重复代码。

public class DeckManagement implements Initializable {
    private final SceneHandler sceneHandler = SceneHandler.getInstance();
    @FXML
    private ListView<Card> rightList;

    @FXML
    private ListView<Card> centerList;

    private static class DeckCell extends ListCell<Card> {
 
        private final VBox container;
        private final Button cardButton ;
        private final Label label;

        DeckCell(String buttonText) {
            label = new Label();
            cardButton = new Button(buttonText);
            container = new VBox(label, cardButton);

            cardButton.setOnAction(e -> {
                Card card = getItem();
                if (card.isMoved()) {
                    centerList.getItems().remove(card);
                } else {
                    centerList.getItems().add(card);
                    // rightList.getItems().remove(card);
                }
                card.setMoved(! card.isMoved());
            });
        }

        @Override
        protected void updateItem(Card card, boolean empty) {
            super.updateItem(card, empty);
            if (empty || card == null) {
                setGraphic(null);
            } else {
                label.setText(card.toString());
                setGraphic(container);
            }
        }
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        rightList.setCellFactory(param -> new DeckCell("Add")); 
        rightList.getItems().addAll(
            new Card("Card 1", 10),
            new Card("Card 2", 5),
            new Card("Card 3", 8)
        );
        centerList.setCellFactory(param -> new DeckCell("Remove"));
    }
}

请注意,如果您使用JavaFX属性来实现Card类以表示“moved”,则您的操作处理程序只需更新该属性,列表就可以自行处理:

public class Card {

    private final BooleanProperty moved = new SimpleBooleanProperty(false);

    public BooleanProperty movedProperty() {
        return moved ;
    }

    public final boolean isMoved() {
        return movedProperty().get();
    }

    public final void setMoved(boolean moved) {
        movedProperty().set(moved);
    }

    private final String name ;
    private final int value ;

    public Card(String name, int value) {
        this.name = name ;
        this.value = value ;
    }

    public String getName() {
        return name ;
    }

    public int getValue() {
        return value;
    }
}

然后

public class DeckManagement implements Initializable {
    private final SceneHandler sceneHandler = SceneHandler.getInstance();
    @FXML
    private ListView<Card> rightList;

    @FXML
    private ListView<Card> centerList;

    private static class DeckCell extends ListCell<Card> {
 
        private final VBox container;
        private final Button cardButton ;
        private final Label label;

        private final boolean movedValue;

        DeckCell(String buttonText, boolean movedValue) {
            this.movedValue = movedValue;

            label = new Label();
            cardButton = new Button(buttonText);
            container = new VBox(label, cardButton);

            cardButton.setOnAction(e -> {
                Card card = getItem();
                card.setMoved(movedValue);
            });
        }

        @Override
        protected void updateItem(Card card, boolean empty) {
            super.updateItem(card, empty);
            if (empty || card == null) {
                setGraphic(null);
            } else {
                label.setText(card.toString());
                setGraphic(container);
            }
        }
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        ObservableList<Card> allCards = FXCollections.observableArrayList(card -> new Observable[] { card.movedProperty() });
        rightList.setItems(allCards);
        rightList.setCellFactory(param -> new DeckCell("Add", true)); 

        allCards.addAll(
            new Card("Card 1", 10),
            new Card("Card 2", 5),
            new Card("Card 3", 8)
        );

        // List that fires updates if any moved properties change:
        centerList.setItems(new FilteredList<>(allCards, card::isMoved));
        centerList.setCellFactory(param -> new DeckCell("Remove", false));
    }
}

相关问题