JavaFX es la biblioteca gráfica actual de Java, la sucesora de Swing. Una aplicación es una clase que extiende Application y rellena una ventana; lo que más despista hoy no es el código, sino que JavaFX ya no forma parte del JDK.
También te puede interesar
package javafx.application does not exist, no es que esté mal: es que faltan los módulos. Con Maven o Gradle se añaden como dependencia; a mano, se bajan y se pasan en el module path.La dependencia
<dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>27</version> </dependency>
El artefacto trae el clasificador de la plataforma automáticamente. Si compilas a mano, hacen falta javafx-base, javafx-graphics y javafx-controls.
Una ventana con un botón
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class HolaFx extends Application {
@Override
public void start(Stage ventana) {
Label saludo = new Label("Escribe tu nombre y pulsa el botón");
TextField nombre = new TextField();
nombre.setPromptText("tu nombre");
Button boton = new Button("Saludar");
boton.setOnAction(e -> {
String n = nombre.getText().isBlank() ? "mundo" : nombre.getText().strip();
saludo.setText("¡Hola, " + n + "!");
});
VBox raiz = new VBox(12, saludo, nombre, boton);
raiz.setPadding(new Insets(20));
raiz.setAlignment(Pos.CENTER);
ventana.setTitle("Hola JavaFX");
ventana.setScene(new Scene(raiz, 360, 180));
ventana.show();
}
public static void main(String[] args) {
launch(args);
}
}

Compilar y ejecutar
javac --module-path /ruta/javafx --add-modules javafx.controls -d . HolaFx.java
java --module-path /ruta/javafx --add-modules javafx.controls \
--enable-native-access=javafx.graphics HolaFx
Con Maven, el plugin javafx-maven-plugin lo hace solo y basta mvn javafx:run. El --enable-native-access no es obligatorio: sin él, Java 25 imprime un aviso porque JavaFX carga bibliotecas nativas, y desaparecerá cuando OpenJFX lo declare por su cuenta.
Las cuatro piezas
| Pieza | Qué es |
|---|---|
Application |
la clase de la que heredas; launch() la arranca |
start(Stage) |
se llama una vez, con la ventana ya creada |
Stage |
la ventana del sistema: título, tamaño, iconos |
Scene |
lo que hay dentro de la ventana; se le pasa el nodo raíz |
| Contenedores | VBox, HBox, GridPane, BorderPane |
| Controles | Label, Button, TextField, TableView… |
La jerarquía es siempre la misma: un Stage contiene una Scene, que contiene un árbol de nodos. Los contenedores colocan a sus hijos solos —el VBox los apila con 12 píxeles de separación— y por eso casi nunca hay que dar coordenadas.
Responder a los eventos
boton.setOnAction(e -> saludo.setText("¡Hola!"));
nombre.textProperty().addListener((obs, viejo, nuevo) -> boton.setDisable(nuevo.isBlank()));
setOnAction recibe una lambda porque EventHandler tiene un solo método. Y lo segundo es lo que distingue a JavaFX de Swing: las propiedades observables. En vez de preguntar, te suscribes; con bind puedes incluso atar el estado de un control al de otro sin escribir ningún manejador.
Platform.runLater(() -> …) o, mejor, con un Task, que ya trae propiedades de progreso y de mensaje. Tocar un control desde otro hilo lanza IllegalStateException: Not on FX application thread.Y si la ventana es grande, FXML
Para interfaces de más de una pantalla, la disposición se escribe en un archivo FXML —un XML— y se diseña con Scene Builder, que es visual. El código queda solo con la lógica, en una clase controladora. Es el equivalente de separar el HTML del JavaScript.
Más información en inglés: Create a graphic interface with JavaFX.
Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.