JavaFX 8 双重绑定单向验证
JavaFX 8 Double binding one way validation
在我的应用程序中,TextField 双向绑定到窗格的 layoutXProperty。文本字段中的任何更改都会立即更新窗格的 layoutX。
例如,如果 layoutX 为 500 并且删除了最后一个零,则窗格的位置会立即跳到 x = 50。同样,如果围绕 texfield 中的值拖动窗格,则会反映窗格的 layoutX 值。
'dragging' 绑定很好,但现在我想在更新窗格的 layoutX 之前等待文本字段中的 RETURN 键(我想先检查有效的边界值)。我已经尝试过 ChangeListeners 和低级绑定,但无法令人满意地工作。
有没有人对如何实现这个有任何想法。在我看来,这将是一个常见的动作,但书籍或网络上关于此的信息非常少。可以更改监听器 'consume a binding event' 吗?
我找到了 'a' 解决方案,但它似乎更像是一个拼凑。
我将 onMouseClicked 和 onActon 处理程序附加到文本字段。
在文本字段 onMouseClicked 中,我取消绑定文本字段并等待 RETURN 键被按下。在 onAction 中,我用新的文本字段值更新先前绑定的值,然后再次双向绑定它。瞧......它有效。
我可以检查 onAction 处理程序中的有效值。
但就像我说的那样,这似乎有点创可贴的解决方案。有人愿意发表评论吗?
只需向更新文本字段的 layoutX
属性 添加一个侦听器,然后向执行验证并更新 TextField
的操作事件添加一个处理程序 layoutX
属性。如果用户按下 Enter,处理程序将被触发,但之前不会。由于您不希望 layoutX
在文本更新时得到更新,因此绑定在这里并不合适。
SSCCE:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class PaneCoordinatesInTextField extends Application {
@Override
public void start(Stage primaryStage) {
Label draggingLabel = createDraggingLabel();
TextField textField = new TextField();
draggingLabel.layoutXProperty().addListener((obs, oldLayoutX, newLayoutX) ->
textField.setText(newLayoutX.toString()));
textField.setOnAction(e -> {
try {
double x = Double.parseDouble(textField.getText());
if (x < 0) {
x = 0 ;
}
if (x > 400) {
x = 400 ;
}
draggingLabel.setLayoutX(x);
} catch (NumberFormatException exc) {
textField.setText(Double.toString(draggingLabel.getLayoutX()));
}
});
Pane pane = new Pane(draggingLabel);
pane.setMinSize(600, 600);
BorderPane root = new BorderPane(pane, textField, null, null, null);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private Label createDraggingLabel() {
Label label = new Label("Drag me", new Rectangle(200, 200, Color.CORNFLOWERBLUE));
label.setContentDisplay(ContentDisplay.CENTER);
label.setTextFill(Color.WHITE);
label.setAlignment(Pos.CENTER);
ObjectProperty<Point2D> mouseLocation = new SimpleObjectProperty<>();
label.setOnDragDetected(e -> mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY())));
label.setOnMouseReleased(e -> mouseLocation.set(null));
label.setOnMouseDragged(e -> {
if (mouseLocation.get() == null) {
return ;
}
double deltaX = e.getSceneX() - mouseLocation.get().getX();
double deltaY = e.getSceneY() - mouseLocation.get().getY();
label.setLayoutX(label.getLayoutX() + deltaX);
label.setLayoutY(label.getLayoutY() + deltaY);
mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY()));
});
return label;
}
public static void main(String[] args) {
launch(args);
}
}
在我的应用程序中,TextField 双向绑定到窗格的 layoutXProperty。文本字段中的任何更改都会立即更新窗格的 layoutX。
例如,如果 layoutX 为 500 并且删除了最后一个零,则窗格的位置会立即跳到 x = 50。同样,如果围绕 texfield 中的值拖动窗格,则会反映窗格的 layoutX 值。
'dragging' 绑定很好,但现在我想在更新窗格的 layoutX 之前等待文本字段中的 RETURN 键(我想先检查有效的边界值)。我已经尝试过 ChangeListeners 和低级绑定,但无法令人满意地工作。
有没有人对如何实现这个有任何想法。在我看来,这将是一个常见的动作,但书籍或网络上关于此的信息非常少。可以更改监听器 'consume a binding event' 吗?
我找到了 'a' 解决方案,但它似乎更像是一个拼凑。
我将 onMouseClicked 和 onActon 处理程序附加到文本字段。
在文本字段 onMouseClicked 中,我取消绑定文本字段并等待 RETURN 键被按下。在 onAction 中,我用新的文本字段值更新先前绑定的值,然后再次双向绑定它。瞧......它有效。
我可以检查 onAction 处理程序中的有效值。
但就像我说的那样,这似乎有点创可贴的解决方案。有人愿意发表评论吗?
只需向更新文本字段的 layoutX
属性 添加一个侦听器,然后向执行验证并更新 TextField
的操作事件添加一个处理程序 layoutX
属性。如果用户按下 Enter,处理程序将被触发,但之前不会。由于您不希望 layoutX
在文本更新时得到更新,因此绑定在这里并不合适。
SSCCE:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class PaneCoordinatesInTextField extends Application {
@Override
public void start(Stage primaryStage) {
Label draggingLabel = createDraggingLabel();
TextField textField = new TextField();
draggingLabel.layoutXProperty().addListener((obs, oldLayoutX, newLayoutX) ->
textField.setText(newLayoutX.toString()));
textField.setOnAction(e -> {
try {
double x = Double.parseDouble(textField.getText());
if (x < 0) {
x = 0 ;
}
if (x > 400) {
x = 400 ;
}
draggingLabel.setLayoutX(x);
} catch (NumberFormatException exc) {
textField.setText(Double.toString(draggingLabel.getLayoutX()));
}
});
Pane pane = new Pane(draggingLabel);
pane.setMinSize(600, 600);
BorderPane root = new BorderPane(pane, textField, null, null, null);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private Label createDraggingLabel() {
Label label = new Label("Drag me", new Rectangle(200, 200, Color.CORNFLOWERBLUE));
label.setContentDisplay(ContentDisplay.CENTER);
label.setTextFill(Color.WHITE);
label.setAlignment(Pos.CENTER);
ObjectProperty<Point2D> mouseLocation = new SimpleObjectProperty<>();
label.setOnDragDetected(e -> mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY())));
label.setOnMouseReleased(e -> mouseLocation.set(null));
label.setOnMouseDragged(e -> {
if (mouseLocation.get() == null) {
return ;
}
double deltaX = e.getSceneX() - mouseLocation.get().getX();
double deltaY = e.getSceneY() - mouseLocation.get().getY();
label.setLayoutX(label.getLayoutX() + deltaX);
label.setLayoutY(label.getLayoutY() + deltaY);
mouseLocation.set(new Point2D(e.getSceneX(), e.getSceneY()));
});
return label;
}
public static void main(String[] args) {
launch(args);
}
}