Posicionamiento explícito de nodos en JavaFX

Cuando he hecho clic en un botón, cambia su posición.

Pero cuando muevo el mouse, el botón regresa al centro de la escena, ¿por qué?

Tengo el siguiente código:

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(){ @Override public void handle(MouseEvent t) { btn.setText(String.valueOf(t.getX() )); } }); btn.setOnAction(new EventHandler() { @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); } } 

Enfoque sugerido

Para su fragmento de código particular, quizás usar el Panel en lugar de un Panel de Astackmiento es el mejor enfoque.

Por qué tu código no hace lo que quieres

Si va a configurar manualmente los valores de diseño, no use un panel de diseño (como un StackPane) que establezca automáticamente los valores de diseño. Si utiliza un panel de diseño, los valores de diseño que establece explícitamente se anularán automáticamente la próxima vez que el panel de diseño realice un pase de diseño (por ejemplo, se redimensiona o su contenido o ubicación en el gráfico de escena se ensucia).

Opciones para establecer explícitamente nodos

Si desea diseñar elementos de forma explícita en JavaFX, realice una de las siguientes acciones:

  1. Subclase Región y anulación layoutChildren .
  2. Coloque su contenido en un Panel si necesita que el contenedor tenga un estilo con CSS o implemente funciones de cambio de tamaño.
  3. Coloque su contenido en un grupo si no necesita que el contenedor tenga un estilo con CSS o implementar funciones de cambio de tamaño.

Consejos relacionados sobre el posicionamiento del nodo

Si desea tener componentes distribuidos automáticamente utilizando los administradores de diseño predefinidos pero desea ajustar o modificar temporalmente las ubicaciones de algunos de los componentes desde sus posiciones predeterminadas, puede ajustar los valores de translateX / Y en lugar de layoutX / Y. De acuerdo con la definición de translateX :

La traducción final del nodo se computará como layoutX + translateX, donde layoutX establece la posición estable del nodo y translateX opcionalmente realiza ajustes dynamics en esa posición. Esta variable se puede usar para alterar la ubicación de un nodo sin alterar su layoutBounds, lo que lo hace útil para animar la ubicación de un nodo.

Esto significa que el administrador de diseño puede calcular la posición predeterminada de un niño usando layoutX , y puede ajustar la posición desde el valor predeterminado utilizando translateX .

Al no haber investigado en profundidad el caso actual, veo una diferencia cuando uso un AnchorPane en lugar del StackPane para colocar el botón.

Al cambiar el texto de la etiqueta del Botón por el mouse Evento modificado, se representa el Panel (se solicita el diseño). Con un StackPane colocando todos sus niños en el centro de sí mismo, la posición del Botón se restablece al centro del Panel. Cuando eche un vistazo al método layoutChildren de StackPane, verá una llamada para redimensionarRelocate. Entonces layoutX y layoutY se reinician y el botón regresa a la posición central (o lo que sea que establezca la alineación del StackPane).

Así que creo que este es un comportamiento correcto del StackPane y recomiendo usar otro Panel, por ejemplo, AnchorPane.