You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDK10下JavaFX复选框选中样式滚动后失效问题求助

Fixing Checkbox Background Style for Scrolled List Items in JavaFX (JDK 10)

Ah, this is a classic gotcha with JavaFX's virtualized controls like ListView. The problem occurs because JavaFX only creates enough cells to fill the visible viewport; when you scroll, it reuses existing cells for new items instead of creating fresh ones. If you set the background style only once (like on initial creation), those reused cells won't update their style to match the new item's selected state.

Here's how to fix this properly:

1. Use a Data Model with Observable State

First, create a simple model class that exposes an observable selected property. This lets your cells react when the selection state changes (including when you trigger "select all"):

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;

public class SelectableItem {
    private final String label;
    private final BooleanProperty selected = new SimpleBooleanProperty(false);

    public SelectableItem(String label) {
        this.label = label;
    }

    // Getters and property accessors
    public String getLabel() {
        return label;
    }

    public boolean isSelected() {
        return selected.get();
    }

    public void setSelected(boolean selected) {
        this.selected.set(selected);
    }

    public BooleanProperty selectedProperty() {
        return selected;
    }
}

2. Customize the ListCell to Dynamically Update Styles

Instead of relying on static styling, create a custom ListCell that updates its style every time it's assigned a new item (or the item's selection state changes). This ensures reused cells get the correct style:

import javafx.scene.control.CheckBox;
import javafx.scene.control.ListCell;

public class CheckBoxListCell extends ListCell<SelectableItem> {
    private final CheckBox checkBox = new CheckBox();
    private static final String SELECTED_STYLE_CLASS = "selected-checkbox-cell";

    public CheckBoxListCell() {
        super();
        // Bind checkbox state to the item's selected property
        checkBox.selectedProperty().addListener((obs, oldVal, newVal) -> {
            if (getItem() != null) {
                getItem().setSelected(newVal);
            }
        });
        setGraphic(checkBox);
        setContentDisplay(ContentDisplay.RIGHT);
    }

    @Override
    protected void updateItem(SelectableItem item, boolean empty) {
        super.updateItem(item, empty);

        if (empty || item == null) {
            // Reset cell for empty state
            setText(null);
            checkBox.setSelected(false);
            getStyleClass().remove(SELECTED_STYLE_CLASS);
        } else {
            setText(item.getLabel());
            
            // Sync checkbox state with the item (unbind first to avoid issues)
            checkBox.selectedProperty().unbind();
            checkBox.setSelected(item.isSelected());
            checkBox.selectedProperty().bind(item.selectedProperty());

            // Update style based on current selection state
            updateCellStyle(item.isSelected());

            // Listen for future selection changes to update style
            item.selectedProperty().addListener((obs, oldVal, newVal) -> {
                updateCellStyle(newVal);
            });
        }
    }

    private void updateCellStyle(boolean isSelected) {
        if (isSelected) {
            getStyleClass().add(SELECTED_STYLE_CLASS);
        } else {
            getStyleClass().remove(SELECTED_STYLE_CLASS);
        }
    }
}

3. Define Your Style in CSS

Use a CSS class instead of inline styles for cleaner, more maintainable code. Create a styles.css file in your resources folder:

.selected-checkbox-cell {
    -fx-background-color: #cceeff; /* Replace with your desired background color */
}

4. Wire It All Together in Your Dialog

Set up the ListView, "Select All" button, and dialog, making sure to apply the custom cell factory and load the CSS:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;

public class CheckBoxDialogExample {
    public static void showDialog() {
        // Create sample items
        ObservableList<SelectableItem> items = FXCollections.observableArrayList(
            new SelectableItem("Item 1"),
            new SelectableItem("Item 2"),
            new SelectableItem("Item 3"),
            // Add as many items as you need to test scrolling
            new SelectableItem("Item 4"),
            new SelectableItem("Item 5"),
            new SelectableItem("Item 6"),
            new SelectableItem("Item 7"),
            new SelectableItem("Item 8"),
            new SelectableItem("Item 9"),
            new SelectableItem("Item 10")
        );

        // Set up ListView with custom cell factory
        ListView<SelectableItem> listView = new ListView<>(items);
        listView.setCellFactory(param -> new CheckBoxListCell());

        // Select All button logic
        Button selectAllBtn = new Button("Select All");
        selectAllBtn.setOnAction(e -> {
            items.forEach(item -> item.setSelected(true));
        });

        // Build dialog
        Dialog<Void> dialog = new Dialog<>();
        dialog.setTitle("Checkbox List Dialog");
        dialog.getDialogPane().setContent(new VBox(10, selectAllBtn, listView));
        dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);

        // Load CSS styles
        dialog.getDialogPane().getStylesheets().add(
            CheckBoxDialogExample.class.getResource("/styles.css").toExternalForm()
        );

        dialog.showAndWait();
    }
}

Why This Works

  • Virtualization Awareness: The custom updateItem method runs every time a cell is reused, ensuring it always reflects the current item's state.
  • Observable State: By binding the checkbox to the item's selectedProperty, any change (including from the "Select All" button) triggers an automatic update to the cell's style.
  • CSS Class Management: Adding/removing the style class instead of setting inline styles ensures clean state reset when cells are reused.

This solution is fully compatible with JDK 10, as all JavaFX APIs used here are available in that version.

内容的提问来源于stack exchange,提问作者TrackerSB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:23:20