簡體   English   中英

JavaFX CheckBoxTableCell 拒絕綁定到值

[英]JavaFX CheckBoxTableCell refuses to bind to value

我有一個 TableView,其中有一列應該是 boolean 值(JavaFX 16,Java 11)的復選框,但由於某種原因,該復選框拒絕實際綁定到 ZA8CFDE6331BD59EB21AC96F9666.B98 的字段嘗試使用專門為 boolean 列制作的 forTableColumn static 方法已經失敗,我嘗試擴展 CheckBoxTableColumn 並在其中進行綁定無濟於事(盡管我不需要為基本綁定這樣做。

在我的 FXML 的 controller 中,我調用ascColumn.setCellFactory(CheckBoxTableCell.forTableColumn(ascColumn)); ,我的專欄是

<TableColumn fx:id="ascColumn" text="Asc" prefWidth="$SHORT_CELL_WIDTH">
    <cellValueFactory>
        <PropertyValueFactory property="ascension"/>
    </cellValueFactory>
</TableColumn>

它當然有效,因為復選框出現了,但是檢查和取消檢查實際上並沒有到達源 object。 沒有其他列需要該字段是 ObservableValue,所有其他列都可以自己處理它,所以我正在尋找一種解決方案來處理它,源值只是一個普通的 boolean。 我還嘗試將 selectedStateCallback 設置為返回一個 BooleanProperty,然后我添加了一個偵聽器,但偵聽器永遠不會被調用。

最終我想要實現的是復選框僅在行的 object 滿足某些條件時出現,為此我制作了一個擴展 CheckBoxTableCell 的新 class,但是因為我無法讓默認的第一個工作地方,我也不能讓它工作,所以我需要先解決這個問題。

編輯:因為我猜這不足以證明問題,這里有一個示例。

Controller:

public class Controller {
    @FXML
    private TableColumn<TestObject, Boolean> checkColumn;

    @FXML
    private TableView<TestObject> table;

    public void initialize() {
        List<TestObject> items = new ArrayList<>();
        items.add(new TestObject("test1", false));
        items.add(new TestObject("test2", false));
        items.add(new TestObject("test3", true));
        table.setItems(FXCollections.observableArrayList(items));
        checkColumn.setCellFactory(CheckBoxTableCell.forTableColumn(checkColumn));
    }
}

FXML:

<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.GridPane?>
<GridPane fx:controller="Controller"
          xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <TableView fx:id="table" editable="true">
        <columns>
            <TableColumn text="Name">
                <cellValueFactory>
                    <PropertyValueFactory property="name"/>
                </cellValueFactory>
            </TableColumn>
            <TableColumn text="Check" fx:id="checkColumn">
                <cellValueFactory>
                    <PropertyValueFactory property="check"/>
                </cellValueFactory>
            </TableColumn>
        </columns>
    </TableView>
</GridPane>

主class:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }

    @Override
    public void stop() throws Exception {
        super.stop();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

build.gradle:

plugins {
    id 'java'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.9'
}

group 'org.example'
version '1.0-SNAPSHOT'

mainClassName = 'Main'

repositories {
    mavenCentral()
}

test {
    useJUnitPlatform()
}

javafx {
    version = "16"
    modules = [ 'javafx.controls', 'javafx.fxml' ]
}

正如我所說,其他一切都有效,無需依賴已經是屬性的輸入值,forTableColumn 方法的文檔字面上說該列必須是 Boolean (不可觀察),所以除非我嚴重誤解了某些東西,它應該工作

[...] 所以我正在尋找一種解決方案,它的源值只是一個普通的 boolean。 [...]

那么據我所知,您不能使用CheckBoxTableCell.forTableColumn() 您可以使用CheckBox定義自己的自定義表格單元格,如下所示:

package org.example;

import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.stream.IntStream;

public class App extends Application {

    @Override
    public void start(Stage stage) {

        // Create table and column:
        TableView<Item> table = new TableView<>();

        TableColumn<Item, Item> // Do not use <Item, Boolean> here!
                checkBoxCol = new TableColumn<>("checkBoxCol");

        table.getColumns().add(checkBoxCol);

        // Some styling:
        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        checkBoxCol.setStyle("-fx-alignment: center;");

        // Set cell value with the use of SimpleObjectProperty:
        checkBoxCol.setCellValueFactory(cellData -> new SimpleObjectProperty<>(cellData.getValue()));

        // Create custom cell with the check box control:
        checkBoxCol.setCellFactory(tc -> new TableCell<>() {

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

                if (item == null || empty) {
                    setGraphic(null);
                } else {
                    CheckBox checkBox = new CheckBox();

                    // Set starting value:
                    checkBox.setSelected(item.isSelected());

                    // Add listener!!!:
                    checkBox.selectedProperty().addListener((observable, oldValue, newValue) ->
                            item.setSelected(newValue));

                    setGraphic(checkBox);
                }
            }
        });

        // Print items to see if the selected value gets updated:
        Button printBtn = new Button("Print Items");
        printBtn.setOnAction(event -> {
            System.out.println("---");
            table.getItems().forEach(System.out::println);
        });

        // Add test data:
        IntStream.range(0, 3).forEach(i -> table.getItems().add(new Item()));

        // Prepare and show stage:
        stage.setScene(new Scene(new VBox(table, printBtn), 100, 200));
        stage.show();
    }

    /**
     * Simple class with just one "regular boolean" property.
     */
    public class Item {

        private boolean selected = false;

        @Override
        public String toString() {
            return Item.class.getSimpleName()
                    + "[selected=" + selected + "]";
        }

        // Getters & Setters:
        public boolean isSelected() {
            return selected;
        }

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

    public static void main(String[] args) {
        launch();
    }
}

最終我想要實現的是復選框僅在行的 object 滿足某些條件時才會出現 [...]

然后,您可以在updateItem()方法中添加一個 if 條件,例如:

                [...]
                if (item == null || empty) {
                    setGraphic(null);
                } else {
                    if (showCheckBox) {
                        CheckBox checkBox = new CheckBox();
                        [...]
                        setGraphic(checkBox);
                    } else
                        setGraphic(null);
                }
                [...]

但我認為最好使用可觀察的屬性。 如果您不想接觸原始 class,您可以創建一個包裝器 class。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM