Apuntes DAM

Chuleta de Desarrollo de Interfaces

JavaFX con FXML, propiedades y bindings, componentes propios, informes, empaquetado, usabilidad y pruebas.

Ponte a prueba con un simulacro

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áficas

Contenedores

VBox · HBoxColumna · fila (spacing, alignment)
BorderPanetop, bottom, left, right, center
GridPaneRejilla: add(nodo, columna, fila)
StackPaneCapas superpuestas
AnchorPaneAnclas a los bordes
VBox.setVgrow(n, Priority.ALWAYS)Que el nodo crezca
Tema: Generación de Interfaces Gráficas

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 Visuales

Hilos 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 NielsenEstado visible, lenguaje del usuario, control, consistencia, prevención de errores…
Ley de FittsBotones importantes grandes y cerca
Ley de HickMenos opciones, decisiones más rápidas
Contraste4,5:1 para texto normal (WCAG AA)
TecladoOrden de tabulación lógico, mnemónicos _Archivo y foco visible
setAccessibleTextDescripción para lectores de pantalla
Tema: Usabilidad y Accesibilidad

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: Informes

Distribución

mvn javafx:runEjecutar con el plugin de OpenJFX
jlinkCrear un runtime de Java a medida
jpackage --type msi|deb|dmgInstalador nativo con el runtime incluido
Firma de códigoEvita avisos de origen desconocido
Versionado semánticoMAYOR.MENOR.PARCHE
Tema: Distribución de Aplicaciones

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 Interfaces

Chuletas de otras asignaturas