When I have clicked a button, it changes its position.
But when I move the mouse, the button comes back to the center of the scene, why?
I have the following code:
public class HolaMundo extends Application {
Button btn;
Scene scene;
@Override
public void start(Stage primaryStage) {
btn = new Button();
btn.setText("Hola Mundo");
StackPane root = new StackPane();
root.getChildren().add(btn);
scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
scene.setOnMouseMoved(new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent t) {
btn.setText(String.valueOf(t.getX() ));
}
});
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
btn.setLayoutX(Math.random() * (300 - btn.getWidth()));
btn.setLayoutY(Math.random() * (250 - btn.getHeight()));
}
});
}
public static void main(String[] args) {
launch(args);
}
}
Suggested approach
For your particular code snippet, perhaps using a Pane instead of a StackPane is the best approach.
Why your code doesn't do what you want
If you are going to manually set layout values, don't use a layout pane (such as a StackPane) which automatically sets layout values for you. If you use a layout pane, then the layout values you explicitly set will be overridden automatically the next time layout pane performs a layout pass (e.g. it is resized or some its content or location in the scene graph becomes dirty).
Options for explicitly laying out nodes
If you want to explicitly layout items in JavaFX do one of the following:
Related advice on node positioning
If you want to have automatically laid out components using the predefined layout managers but you want to adjust or temporarily modify the locations of some of the components from their default positions, you can adjust the translateX/Y values rather than layoutX/Y values. According to the definition of translateX:
The node's final translation will be computed as layoutX + translateX, where layoutX establishes the node's stable position and translateX optionally makes dynamic adjustments to that position. This variable can be used to alter the location of a node without disturbing its layoutBounds, which makes it useful for animating a node's location.
This means that the layout manager can compute a child's default position using layoutX
, and you can adjust the position from the default using translateX
.
Not having deeply investigated the current case, I see a difference when I use an AnchorPane instead of the StackPane to place the Button on.
By changing the label text of the Button by the mouseMoved-Event the Pane is rendered (layout is requested). With a StackPane placing all it's children in the center of itself the Button's position is reset to the center of the Pane. When you have a look into the layoutChildren method of StackPane you'll see a call to resizeRelocate. So layoutX and layoutY are reset and the button moves back to the center position (or whatever you set the alignment of the StackPane to).
So I think this is a correct behavior of the StackPane and I recommend to use another Pane, e.g. AnchorPane.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With