[英]JavaFX Boolean Binding Based on Selected Items in a TableView
我試圖根據TableView
選定行中的屬性值的集合來啟用JavaFX Button
。 以下是演示該問題的示例應用程序:
package test;
import java.util.Random;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.MultipleSelectionModel;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(final String[] args) throws Exception {
launch(args);
}
private static class Row {
private final BooleanProperty myProp;
public Row(final boolean value) {
myProp = new SimpleBooleanProperty(value);
}
public BooleanProperty propProperty() { return myProp; }
}
@Override
public void start(final Stage window) throws Exception {
// Create a VBox to hold the table and button
final VBox root = new VBox();
root.setMinSize(200, 200);
// Create the table, and enable multi-select
final TableView<Row> table = new TableView<>();
final MultipleSelectionModel<Row> selectionModel = table.getSelectionModel();
selectionModel.setSelectionMode(SelectionMode.MULTIPLE);
root.getChildren().add(table);
// Create a column based on the value of Row.propProperty()
final TableColumn<Row, Boolean> column = new TableColumn<>("Value");
column.setCellValueFactory(p -> p.getValue().propProperty());
table.getColumns().add(column);
// Add a button below the table
final Button button = new Button("Button");
root.getChildren().add(button);
// Populate the table with true/false values
final ObservableList<Row> rows = table.getItems();
rows.addAll(new Row(false), new Row(false), new Row(false));
// Start a thread to randomly modify the row values
final Random rng = new Random();
final Thread thread = new Thread(() -> {
// Flip the value in a randomly selected row every 10 seconds
try {
do {
final int i = rng.nextInt(rows.size());
System.out.println("Flipping row " + i);
Thread.sleep(10000);
final BooleanProperty prop = rows.get(i).propProperty();
prop.set(!prop.get());
} while (true);
} catch (final InterruptedException e) {
System.out.println("Exiting Thread");
}
}, "Row Flipper Thread");
thread.setDaemon(true);
thread.start();
// Bind the button's disable property such that the button
// is only enabled if one of the selected rows is true
final ObservableList<Row> selectedRows = selectionModel.getSelectedItems();
button.disableProperty().bind(Bindings.createBooleanBinding(() -> {
for (int i = 0; i < selectedRows.size(); ++i) {
if (selectedRows.get(i).propProperty().get()) {
return false;
}
}
return true;
}, selectedRows));
// Show the JavaFX window
final Scene scene = new Scene(root);
window.setScene(scene);
window.show();
}
}
要進行測試,請啟動上述應用程序,然后選擇由文本“翻轉行N”指示的行,其中N在[0,2]中。 當所選行的值更改為true時...
“觀察到的行為” button
保持禁用狀態。
所需行為 button
啟用。
有誰知道如何創建表現出所需行為的BooleanBinding
?
如果所選行的任何propProperty
更改,則需要使綁定無效。 當前,綁定僅觀察選定的項目列表,當列表內容更改(即,項目變為選中或未選中)時,它將觸發事件,而當屬於該列表中項目的屬性更改值時,則不會觸發事件。
為此,請使用提取器創建一個列表:
final ObservableList<Row> selectedRows =
FXCollections.observableArrayList(r -> new Observable[]{r.propProperty()});
添加或刪除項目時,或列表中任何項目的propProperty()
更改時,此列表都會觸發事件。 (如果需要觀察多個值,可以通過將它們包括在Observable
數組中來實現。)
當然,您仍然需要此列表以包含表中的選定項目。 您可以通過將列表的內容綁定到選擇模型的selectedItems
來確保這一點:
Bindings.bindContent(selectedRows, selectionModel.getSelectedItems());
這是使用此功能的MCVE版本:
import java.util.Random;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.MultipleSelectionModel;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(final String[] args) throws Exception {
launch(args);
}
private static class Row {
private final BooleanProperty myProp;
public Row(final boolean value) {
myProp = new SimpleBooleanProperty(value);
}
public BooleanProperty propProperty() { return myProp; }
}
@Override
public void start(final Stage window) throws Exception {
// Create a VBox to hold the table and button
final VBox root = new VBox();
root.setMinSize(200, 200);
// Create the table, and enable multi-select
final TableView<Row> table = new TableView<>();
final MultipleSelectionModel<Row> selectionModel = table.getSelectionModel();
selectionModel.setSelectionMode(SelectionMode.MULTIPLE);
root.getChildren().add(table);
// Create a column based on the value of Row.propProperty()
final TableColumn<Row, Boolean> column = new TableColumn<>("Value");
column.setCellValueFactory(p -> p.getValue().propProperty());
table.getColumns().add(column);
// Add a button below the table
final Button button = new Button("Button");
root.getChildren().add(button);
// Populate the table with true/false values
final ObservableList<Row> rows = table.getItems();
rows.addAll(new Row(false), new Row(false), new Row(false));
// Start a thread to randomly modify the row values
final Random rng = new Random();
final Thread thread = new Thread(() -> {
// Flip the value in a randomly selected row every 10 seconds
try {
do {
final int i = rng.nextInt(rows.size());
System.out.println("Flipping row " + i);
Thread.sleep(10000);
final BooleanProperty prop = rows.get(i).propProperty();
Platform.runLater(() -> prop.set(!prop.get()));
} while (true);
} catch (final InterruptedException e) {
System.out.println("Exiting Thread");
}
}, "Row Flipper Thread");
thread.setDaemon(true);
thread.start();
// Bind the button's disable property such that the button
// is only enabled if one of the selected rows is true
final ObservableList<Row> selectedRows =
FXCollections.observableArrayList(r -> new Observable[]{r.propProperty()});
Bindings.bindContent(selectedRows, selectionModel.getSelectedItems());
button.disableProperty().bind(Bindings.createBooleanBinding(() -> {
for (int i = 0; i < selectedRows.size(); ++i) {
if (selectedRows.get(i).propProperty().get()) {
return false;
}
}
return true;
}, selectedRows));
// Show the JavaFX window
final Scene scene = new Scene(root);
window.setScene(scene);
window.show();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.