我正在使用JavaFx开发一个应用程序,在其中我在GridPane中创建动态TextFields,并且有一个按钮最初被禁用,如下所示:
所以我想要的是,如果列1文本字段值小于列3文本字段值,按钮应该像这样启用:
但是,假设第3列TextField值中的任何一个小于同一行的第1列TextField值,它应该禁用按钮并以红色显示特定的TextField边框,并且当将鼠标悬停在该字段上时,应该显示一些警告:
我是这样创建TextField的:
public static GridPane table(int rows){
GridPane table = new GridPane();
for(int i=0; i<rows; i++){
TextField textField1 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
TextField textField2 = new JFXTextField();
textField2.setAlignment(Pos.CENTER);
TextField textField3 = new JFXTextField();
textField3.setAlignment(Pos.CENTER);
//add them to the GridPane
table.add(textField1, 0, i+1);
table.add(textField2, 1, i+1);
table.add(textField3, 2, i+1);
}
return table;
}
之后,我创建了另一个方法来返回表中特定行和列的组件,如下所示:
public static Node getComponent (int row, int column, GridPane table) {
for (Node component : table.getChildren()) { // loop through every node in the table
if(GridPane.getRowIndex(component) == row &&
GridPane.getColumnIndex(component) == column) {
return component;
}
}
return null;
}
我尝试这样做,但没有成功(这里我将值转换为字符串并进行比较,只是为了检查):
private boolean isTextEqual(GridPane table, Button button){
for(Node node : table.getChildren()){
if(node instanceof TextField){
for(int i=1 ; i<=ComboBox().getValue(); i++){
String str = ((TextField)DynamicGridpanes.getComponent (i, 0, table)).getText();
((TextField)DynamicGridpanes.getComponent (i, 2, table)).textProperty().addListener((obs, old, newV)->{
if(newV.toString()==str){
button.setDisable(false);
}
else{
button.setDisable(true);
}
});
}
}
}
return true;
}
您可以创建在创建文本字段时执行验证的绑定。这将避免在网格窗格的子节点中导航的需要,这似乎不是很可靠。
声明一个布尔绑定数组(每行将有一个):
private BooleanBinding[] rowValidationBindings ;
那你可以做
public static GridPane table(int rows){
GridPane table = new GridPane();
rowValidationBindings = new BooleanBinding[rows];
for(int i=0; i<rows; i++){
TextField textField1 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
TextField textField2 = new JFXTextField();
textField2.setAlignment(Pos.CENTER);
TextField textField3 = new JFXTextField();
textField3.setAlignment(Pos.CENTER);
rowValidationBindings[i] = Bindings.createBooleanBinding(
() -> {
if (textField1.getText().matches("\\d+") &&
textField3.getText().matches("\\d+")) {
int value1 = Integer.parseInt(textField1.getText());
int value3 = Integer.parseInt(textFIeld3.getText());
return value3 > value1 ;
} else {
return false ;
}
}, textField1.textProperty(), textField2.textProperty()
);
//add them to the GridPane
table.add(textField1, 0, i+1);
table.add(textField2, 1, i+1);
table.add(textField3, 2, i+1);
}
button.disableProperty().bind(Bindings.createBooleanBinding(
() -> ! Stream.of(rowValidationBindings).allMatch(BooleanBinding::get),
rowValidationBindings
));
return table;
}
您也可以在< code>for循环中直接将样式添加到文本字段:
textField3.styleProperty().bind(Bindings
.when(rowValidationBindings[i])
.then("")
.otherwise("-fx-border-color: red")); // or whatever you are using for style
对于工具提示:
Tooltip tooltip = new Tooltip();
tooltip.textProperty().bind(Bindings.concat("Value must be greater than ",textField1.textProperty()));
textField3.tooltipProperty().bind(Bindings
.when(rowValidationBindings[i])
.then((Tooltip)null)
.otherwise(tooltip));
实际上,做你想做的事情并不容易,因为你拥有的代码需要重构(代码不是为了满足如此高级的需求,但对于你拥有的基本需求来说是可以的)。但是,你可以这样做:
首先,定义一个全局变量,用无效TextField
的最后一行索引
来更新(从这里可以得出结论,这将一次更改一个无效
public static int textFieldIndex = -1;
现在,借助您已经拥有的 getComponent 方法(整型行、整型列、GridPane 表),
创建另一个静态方法来检查所有文本字段
是否同时具有有效值:
/**
* This method to check at run time with every change in any TextField
* if the corresponding TextField has a valid value(i.e contains number and
* the first TextField value is less than the second)
* @param table
* @param numRows
*/
private static boolean hasValidValue(GridPane table, int numRows){
// cycle through every row in the table
// and compare every two TextFields
for(int i=0; i<numRows; i++){
try{ // try because user may enters a non-number input (to avoid crash)
// the first TextField is always at column index 0 , the second at column index 3
if(Integer.parseInt(((TextField)(getComponent (i, 0, table))).getText())>
Integer.parseInt(((TextField)(getComponent (i, 3, table))).getText())){
// before returning false
textFieldIndex = i; // update at which row the TextField is less
return false;
}
}catch(NumberFormatException e){ // if it contains invalid input(non-digit)
return false;
}
}
return true;
}
现在,您需要在 validateTable()
方法中使用上述方法并进行一些调整:
// pass the comboBox.getValue() to the third parameter
private void validateTable(GridPane table, Button button, int numRows) {
for(Node textField : table.getChildren()){
if(textField instanceof TextField){
((TextField)textField).textProperty().addListener((obs, old, newV)->{
// first of all remove the red border from the invalid TextField (if any)
// we know that via textFieldIndex which should be -1 if there is no lesser
// actually it's a pain
if(textFieldIndex!=-1){
((TextField) getComponent(textFieldIndex, 3, table)).setStyle("");
}
if(isAllFilled(table)){ // if all filled ( you already have this method)
if(hasValidValue(table,numRows)){ // check for validity
button.setDisable(false); // then make the button active again
}
else{// if it's not a valid value
// re-style the TextField which has lesser value
((TextField) getComponent(textFieldIndex, 3, table)).
setStyle("-fx-border-color: red;");
button.setDisable(true);
}
}
else{
button.setDisable(true);
}
});
}
}
}
现在在您的tabPane ChangeListener
中将第三段添加到方法中(因为您已经拥有它,所以您只需要添加ComboBox
的值:
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>(){
....
....
....
// I think you have here anchorPane not containerB in the original code
validateTable((GridPane) containerB.getChildren().get(0), test, comboBox.getValue());
}
测试
我真的很感谢你帮我解决问题。 我正在使用JavaFX和NetBeans IDE。我正在为桌面客户端制作一个非常简单的启动窗口。窗口当前与此图像类似。 当前外观: null 我有一个GridPane作为根。不知道为什么JavaFX选择使用(col,row),但这就是我在下面表示我的设置的方式: @GridPane(0,0)->“欢迎”文本 @GridPane(0,1)->VBox(此VBox包含上图
我是JavaFx新手,我在FXMl中创建了两个gridPane,我想用JavaFx做同样的事情。 我想创建一个扩展GridPane的类,所以当我调用我的类时,我将得到与fxml PS中相同的结果:如果您使用的是SceneBuilder,请检查网格线是否可见,以便可以看到所有GridPane谢谢
我想知道是否可以制作实现比较器接口的非静态内部类。 例如:。 我想使用比较器类非静态,因为我想使用非静态字段“num”并想修改它的值。有非静态比较器内部类可以吗? 附加信息 对于每个对象,我都在计算内部的分数,并进行相应的比较和排序。我需要将这些分数保存在我在comparator内计算的地图中,并希望在外部类中使用该地图进行进一步计算。
我对JavaFX相对较新,我很困惑为什么我下面的代码没有产生预期的结果,即添加到网格中的标签。 我想做的是运行一个测试,将JavaFX标签添加到我的FXML GridPane,因为我想在不久的将来构建一个方法,允许用户选择一个文件,然后在用户选择文件时生成一个标签并将该标签添加到GridPane。 提前感谢, 代码: FXML代码是一个标准文件,其中定义了一个网格窗格,上面列出了fx:id。
问题内容: 我想创建一个内部类的Spring Bean。如果我有以下内部类: 我想在我的XML配置文件中创建bean实例。 问题答案: 您不能使用点()表示法访问公共静态内部类,而应使用货币()。一个例子: 这将起作用。