请看下面的图片,您就会了解我的应用程序的布局。
我希望能够动态选择有多少个CheckBox
(启用下拉菜单)可供选择(固定数量)。我想用这 3 个 RadioButton
来实现这一点。
在垂直模式下,必须选择所有 4 个 CheckBox
(不少于)。在混合模式下,只有 2 个 CheckBox
必须可用(不能多也不能少)。在水平模式下,只需选择 1 个 CheckBox
(不能选择更多)。重要的是,用户能够选择特定的组合ComboBox
(例如:我们处于混合模式,选择 1 和 2 与选择 1 和 3 不同)。
解决方案
public class ConfigurationEditDialogController {
// Data Acquisition Tab
private ObservableList<String> options =
FXCollections.observableArrayList(
"ciao",
"hello",
"halo"
);
@FXML
private PrefixSelectionComboBox<String> testBus1ComboBox = new PrefixSelectionComboBox<>();
@FXML
private PrefixSelectionComboBox<String> testBus2ComboBox = new PrefixSelectionComboBox<>();
@FXML
private PrefixSelectionComboBox<String> testBus3ComboBox = new PrefixSelectionComboBox<>();
@FXML
private PrefixSelectionComboBox<String> testBus4ComboBox = new PrefixSelectionComboBox<>();
@FXML
private CheckBox checkbox1;
@FXML
private CheckBox checkbox2;
@FXML
private CheckBox checkbox3;
@FXML
private CheckBox checkbox4;
private ObservableSet<CheckBox> selectedCheckBoxes = FXCollections.observableSet();
private ObservableSet<CheckBox> unselectedCheckBoxes = FXCollections.observableSet();
private IntegerBinding numCheckBoxesSelected = Bindings.size(selectedCheckBoxes);
private int maxNumSelected = 2;
@FXML
private RadioButton verticalMode;
@FXML
private RadioButton horizontalMode;
@FXML
private RadioButton hybridMode;
private Stage dialogStage;
private Configuration configuration;
private boolean okClicked = false;
/**
* Initializes the controller class. This method is automatically called
* after the fxml file has been loaded.
*/
@FXML
private void initialize() {
testBus1ComboBox.setItems(options);
testBus2ComboBox.setItems(options);
testBus3ComboBox.setItems(options);
testBus4ComboBox.setItems(options);
configureCheckBox(checkbox1);
configureCheckBox(checkbox2);
configureCheckBox(checkbox3);
configureCheckBox(checkbox4);
numCheckBoxesSelected.addListener((obs, oldSelectedCount, newSelectedCount) -> {
if (newSelectedCount.intValue() >= maxNumSelected) {
unselectedCheckBoxes.forEach(cb -> cb.setDisable(true));
} else {
unselectedCheckBoxes.forEach(cb -> cb.setDisable(false));
}
});
testBus1ComboBox.disableProperty().bind(checkbox1.selectedProperty().not());
testBus2ComboBox.disableProperty().bind(checkbox2.selectedProperty().not());
testBus3ComboBox.disableProperty().bind(checkbox3.selectedProperty().not());
testBus4ComboBox.disableProperty().bind(checkbox4.selectedProperty().not());
}
private void configureCheckBox(CheckBox checkBox) {
if (checkBox.isSelected()) {
selectedCheckBoxes.add(checkBox);
} else {
unselectedCheckBoxes.add(checkBox);
}
checkBox.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
unselectedCheckBoxes.remove(checkBox);
selectedCheckBoxes.add(checkBox);
} else {
selectedCheckBoxes.remove(checkBox);
unselectedCheckBoxes.add(checkBox);
}
});
}
FXML
文件选项卡
我想在此选项卡中实现 fabian 解决方案,但是不需要像我一样使用 fxml。
<Tab closable="false" text="Data Acquisition">
<content>
<GridPane prefHeight="254.0" prefWidth="404.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="218.0" minWidth="10.0" prefWidth="111.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="519.0" minWidth="10.0" prefWidth="490.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="316.0" minWidth="10.0" prefWidth="71.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Test Bus 1" GridPane.rowIndex="2" />
<Label text="Test Bus 2" GridPane.rowIndex="3" />
<Label text="Test Bus 3" GridPane.rowIndex="4" />
<Label text="Test Bus 4" GridPane.rowIndex="5" />
<PrefixSelectionComboBox fx:id="testBus1ComboBox" prefHeight="31.0" prefWidth="300.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
<PrefixSelectionComboBox fx:id="testBus2ComboBox" prefWidth="300.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
<PrefixSelectionComboBox fx:id="testBus3ComboBox" prefWidth="300.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
<PrefixSelectionComboBox fx:id="testBus4ComboBox" prefWidth="300.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="5" />
<CheckBox fx:id="checkbox1" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<CheckBox fx:id="checkbox2" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<CheckBox fx:id="checkbox3" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<CheckBox fx:id="checkbox4" mnemonicParsing="false" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<Label text="Sample Mode" GridPane.rowIndex="1" />
<RadioButton fx:id="verticalMode" mnemonicParsing="false" selected="true" text="Vertical " GridPane.columnIndex="1" GridPane.rowIndex="1">
<toggleGroup>
<ToggleGroup fx:id="SampleModeGroup" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="hybridMode" mnemonicParsing="false" text="Hybrid" toggleGroup="$SampleModeGroup" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
<RadioButton fx:id="horizontalMode" mnemonicParsing="false" text="Horizontal" toggleGroup="$SampleModeGroup" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.rowIndex="1" />
</children>
</GridPane>
</content>
</Tab>
我只能使用 private int maxNumSelected = 2;
手动设置允许的最大(但不是最小)数字。不过我想通过 RadioButton
来操作它们。
最佳答案
您可以在所有 RadioButton
上设置监听器选择其中之一后,禁用或启用每个 ComboBox
的容器/CheckBox
节点。
这是一个演示这一点的示例应用程序。我使用纯 Java(无 FXML)构建了 UI,只是为了将所有内容都保存在一篇文章中。重要的部分是添加到RadioButtons
中的三个监听器。 .
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
// Root layout
VBox root = new VBox(5);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// Radio buttons
HBox hbRadios = new HBox(10);
hbRadios.setAlignment(Pos.CENTER);
ToggleGroup tglRadioSelections = new ToggleGroup();
RadioButton rdoVertical = new RadioButton("Vertical");
RadioButton rdoHybrid = new RadioButton("Hybrid");
RadioButton rdoHorizontal = new RadioButton("Horizontal");
tglRadioSelections.getToggles().addAll(rdoVertical, rdoHybrid, rdoHorizontal);
hbRadios.getChildren().addAll(rdoVertical, rdoHybrid, rdoHorizontal);
// ComboBoxes and CheckBoxes
VBox vbSelections = new VBox(10);
ComboBox cbo1 = new ComboBox();
ComboBox cbo2 = new ComboBox();
ComboBox cbo3 = new ComboBox();
ComboBox cbo4 = new ComboBox();
CheckBox chk1 = new CheckBox();
CheckBox chk2 = new CheckBox();
CheckBox chk3 = new CheckBox();
CheckBox chk4 = new CheckBox();
// Create the containers for each selection group
HBox hbSelection1 = new HBox(10);
hbSelection1.getChildren().addAll(cbo1, chk1);
HBox hbSelection2 = new HBox(10);
hbSelection2.getChildren().addAll(cbo2, chk2);
HBox hbSelection3 = new HBox(10);
hbSelection3.getChildren().addAll(cbo3, chk3);
HBox hbSelection4 = new HBox(10);
hbSelection4.getChildren().addAll(cbo4, chk4);
// Add listeners for each radio button to enable appropriate selections
rdoVertical.selectedProperty().addListener((observableValue, oldValue, newValue) -> {
hbSelection1.setDisable(!newValue);
hbSelection2.setDisable(!newValue);
hbSelection3.setDisable(!newValue);
hbSelection4.setDisable(!newValue);
});
rdoHybrid.selectedProperty().addListener((observableValue, oldValue, newValue) -> {
hbSelection1.setDisable(!newValue);
hbSelection2.setDisable(!newValue);
hbSelection3.setDisable(!newValue);
hbSelection4.setDisable(newValue);
});
rdoHorizontal.selectedProperty().addListener((observableValue, oldValue, newValue) -> {
hbSelection1.setDisable(!newValue);
hbSelection2.setDisable(newValue);
hbSelection3.setDisable(newValue);
hbSelection4.setDisable(newValue);
});
// Build the scene
vbSelections.getChildren().addAll(hbSelection1, hbSelection2, hbSelection3, hbSelection4);
root.getChildren().addAll(hbRadios, vbSelections);
stage.setScene(new Scene(root));
stage.show();
}
}
有几点需要注意。您将需要命名容器来启用/禁用适当的选择区域。这里他们被称为hbSelection#
,这是我们添加复选框和组合框的地方。
在监听器中,您会看到我基本上只是根据 newValue
设置每个 HBox 的禁用属性。这是 true
如果RadioButton
被选中并 false
如果不是。
可能有一种更有效的方法来处理这个问题,但这绝对是一种方法。
关于java - 如何通过 JavaFX 中的单选按钮对最大可选复选框进行限制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50970771/