Chuleta de Desarrollo de Interfaces
JavaFX con FXML, propiedades y bindings, componentes propios, informes, empaquetado, usabilidad y pruebas.
Esqueleto JavaFX
public class App extends Application { @Override public void start(Stage stage) throws IOException { FXMLLoader l = new FXMLLoader(App.class.getResource("principal.fxml")); Scene scene = new Scene(l.load(), 800, 600); scene.getStylesheets().add(App.class.getResource("estilos.css").toExternalForm()); stage.setTitle("Gestor"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(); }}Tema: Generación de Interfaces Gráficas FXML y controlador
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="app.PrincipalController"> <center> <TableView fx:id="tabla"/> </center> <bottom> <Button text="Añadir" onAction="#onAnadir"/> </bottom></BorderPane>En el controlador: @FXML private TableView<Cliente> tabla; @FXML void onAnadir(ActionEvent e) { … } y @FXML void initialize().
Tema: Generación de Interfaces GráficasContenedores
| VBox · HBox | Columna · fila (spacing, alignment) |
|---|---|
| BorderPane | top, bottom, left, right, center |
| GridPane | Rejilla: add(nodo, columna, fila) |
| StackPane | Capas superpuestas |
| AnchorPane | Anclas a los bordes |
| VBox.setVgrow(n, Priority.ALWAYS) | Que el nodo crezca |
Propiedades y bindings
private final StringProperty nombre = new SimpleStringProperty("");public StringProperty nombreProperty() { return nombre; } boton.disableProperty().bind(campo.textProperty().isEmpty());etiqueta.textProperty().bind(Bindings.format("%d elementos", Bindings.size(lista)));nombre.addListener((obs, viejo, nuevo) -> validar(nuevo)); ObservableList<Cliente> datos = FXCollections.observableArrayList();FilteredList<Cliente> filtrados = new FilteredList<>(datos);tabla.setItems(filtrados);colNombre.setCellValueFactory(c -> c.getValue().nombreProperty());Tema: Creación de Componentes Visuales Componente propio
public class Valoracion extends HBox { private final IntegerProperty valor = new SimpleIntegerProperty(0); public Valoracion() { for (int i = 1; i <= 5; i++) { int n = i; Label estrella = new Label("★"); estrella.setOnMouseClicked(e -> valor.set(n)); getChildren().add(estrella); } getStyleClass().add("valoracion"); } public IntegerProperty valorProperty() { return valor; }}Se usa en FXML con <?import app.Valoracion?> y aparece en Scene Builder si está en el classpath.
Tema: Creación de Componentes VisualesHilos en la interfaz
Task<List<Cliente>> t = new Task<>() { @Override protected List<Cliente> call() throws Exception { return dao.listar(); // fuera del hilo de JavaFX }};t.setOnSucceeded(e -> datos.setAll(t.getValue()));progreso.progressProperty().bind(t.progressProperty());new Thread(t).start();Platform.runLater(() -> etiqueta.setText("Listo"));Tema: Generación de Interfaces Gráficas Usabilidad y accesibilidad
| Heurísticas de Nielsen | Estado visible, lenguaje del usuario, control, consistencia, prevención de errores… |
|---|---|
| Ley de Fitts | Botones importantes grandes y cerca |
| Ley de Hick | Menos opciones, decisiones más rápidas |
| Contraste | 4,5:1 para texto normal (WCAG AA) |
| Teclado | Orden de tabulación lógico, mnemónicos _Archivo y foco visible |
| setAccessibleText | Descripción para lectores de pantalla |
Informes con JasperReports
JasperReport r = JasperCompileManager.compileReport("factura.jrxml");Map<String, Object> params = Map.of("CLIENTE", "Ana López");JRDataSource ds = new JRBeanCollectionDataSource(lineas);JasperPrint print = JasperFillManager.fillReport(r, params, ds);JasperExportManager.exportReportToPdfFile(print, "factura.pdf");Bandas: Title, Page Header, Column Header, Detail, Column Footer, Page Footer, Summary. $F{campo}, $P{param}, $V{variable}.
Tema: InformesDistribución
| mvn javafx:run | Ejecutar con el plugin de OpenJFX |
|---|---|
| jlink | Crear un runtime de Java a medida |
| jpackage --type msi|deb|dmg | Instalador nativo con el runtime incluido |
| Firma de código | Evita avisos de origen desconocido |
| Versionado semántico | MAYOR.MENOR.PARCHE |
Pruebas de interfaz
@ExtendWith(ApplicationExtension.class)class LoginTest { @Start void start(Stage s) throws IOException { /* cargar la escena */ } @Test void botonDesactivadoSinUsuario(FxRobot robot) { robot.clickOn("#usuario").write(""); assertTrue(robot.lookup("#entrar").queryButton().isDisabled()); }}TestFX para JavaFX. Tipos: funcionales, de regresión, de usabilidad con usuarios reales, de rendimiento y de accesibilidad.
Tema: Pruebas de Interfacesapuntesdam.com/subject/desarrollo-interfaces/chuleta
Chuletas de otras asignaturas
Entornos de DesarrolloProgramaciónLenguajes de MarcasBases de DatosSistemas InformáticosAcceso a DatosProgramación Multimedia y Dispositivos MóvilesProgramación de Servicios y ProcesosSistemas de Gestión EmpresarialDesarrollo Web en Entorno ClienteDesarrollo Web en Entorno ServidorDespliegue de Aplicaciones WebDiseño de Interfaces Web