Changes for src/java/uf5/ud3.md: 21 added lines, 6 removed lines.
Original line number
Diff line number
Diff line
# Interfícies gràfiques
Una aplicació amb interfície gràfica no s'executa de dalt a baix: espera. El flux el marquen les accions de l'usuari, i el programa es converteix en un conjunt de respostes a esdeveniments. Aquesta unitat explica aquest model i el construeix amb **JavaFX**, la llibreria gràfica de Java.
-[Programació orientada a esdeveniments](./ud3/poe.md): el bucle d'esdeveniments, el patró observador i els callbacks.
-[JavaFX](./ud3/javafx.md): què és, com afegir-la al projecte i el model Stage, Scene i Node.
-[Tipus de nodes](./ud3/tipus_nodes.md): controls, contenidors, figures i el dibuix amb `Canvas`.
-[Aplicació](./ud3/aplicacio.md): l'estructura mínima d'una aplicació i el seu cicle de vida.
-[Scene Graph](./ud3/scene_graph.md): l'arbre de nodes i els layouts que els col·loquen.
-[FXML](./ud3/fxml.md): definir la interfície en un fitxer XML i connectar-la amb un controlador.
-[Múltiples finestres](./ud3/multi_finestres.md): obrir finestres, modalitat i diàlegs.
-[Gestió d'esdeveniments](./ud3/esdeveniments.md): com viatja un esdeveniment pel graf i com se'l captura.
-[Patró de disseny UI](./ud3/patro_ui.md): MVC i MVP, i com separar la vista del model.
-[Concurrència](./ud3/concurrencia.md): per què la interfície es congela i com evitar-ho amb `Task`.
-[Binding de propietats](./ud3/binding.md): mantenir sincronitzats el model i la interfície.
Hi són les tres peces de què parlàvem: el `Stage` és la finestra, la `Scene` el contenidor del graf, i el `Label` és, en aquest cas, tot el graf.
## Què passa quan s'engega
El `main()` només crida `launch()`, i a partir d'aquí mana JavaFX. El mètode `launch()` engega el sistema gràfic, crea el **JavaFX Application Thread**, instancia la teva classe i li crida els mètodes del cicle de vida:
| Mètode | Quan es crida | On s'executa |
| --- | --- | --- |
| `init()` | Un cop, abans de la interfície | Al fil que ha cridat `launch()` |
| `start(Stage)` | Un cop, amb la finestra principal ja creada | Al JavaFX Application Thread |
| `stop()` | En tancar l'última finestra o cridar `Platform.exit()` | Al JavaFX Application Thread |
Només `start()` és obligatori. Els altres dos es redefineixen quan cal:
```java
@Override
publicvoidinit(){
// preparar dades o carregar configuració, encara sense interfície
}
@Override
publicvoidstop(){
// tancar connexions, desar l'estat
}
```
**A `init()` no es pot tocar la interfície**, perquè encara no existeix i perquè no s'executa al fil de JavaFX. Tot el que construeixi nodes va a `start()`.
`launch()` és bloquejant: no retorna fins que l'aplicació acaba. Per això no hi ha res després de la seva crida al `main()`.
## El main que no cal
Amb la configuració de Maven que hem vist, el plugin ja sap quina és la classe principal i el `main()` no és estrictament necessari. Es continua escrivint per dos motius: perquè molts IDE l'esperen per oferir el botó d'executar, i perquè permet passar arguments.
Els arguments es recuperen des de dins de l'aplicació amb `getParameters()`:
```java
List<String>args=getParameters().getRaw();
```
## Tancar l'aplicació
Per defecte, l'aplicació acaba quan es tanca l'última finestra. Es pot forçar amb `Platform.exit()`, que crida `stop()` i allibera el sistema gràfic. Convé evitar `System.exit()`, que talla el procés sense passar per `stop()`.
Changes for src/java/uf5/ud3/concurrencia.md: 55 added lines, 7 removed lines.
Original line number
Diff line number
Diff line
@@ -2,19 +2,67 @@
<!-- toc -->
Les aplicacions GUI (interfície gràfica d'usuari) de Java (inclosa JavaFX) són inherentment multifil. Diversos fils realitzen tasques diferents per mantenir la interfície d'usuari en sincronització amb les accions de l'usuari. JavaFX utilitza **un únic fil**, anomenat **JavaFX Application Thread**, per processar tots els esdeveniments de la interfície d'usuari. Els nodes que representen la interfície d'usuari d'una gràfica d'escena no són segurs. El disseny de nodes que no són segurs per a fils presenta avantatges i inconvenients. Són més ràpids, ja que no hi ha cap sincronització. L’inconvenient és que s’han d’accedir des d’un mateix fil per evitar estar en un estat il·legal. JavaFX posa una restricció a la qual s’ha d’accedir a un gràfic d’escena en directe des d’un únic fil, el fil d’aplicacions JavaFX. Aquesta restricció imposa indirectament una altra restricció que un esdeveniment d’UI **no ha de processar una tasca de llarga durada**, ja que farà que l’aplicació no respongui.
JavaFX processa tots els esdeveniments de la interfície en un únic fil, el **JavaFX Application Thread**. Aquest fil és el que crida els teus gestors d'esdeveniments i el que repinta la pantalla.

D'aquí surten les dues regles que governen tota aplicació gràfica:
Si un altre fil vol modificar la GUI, cal que utilitzi la següent construcció per afegir la tasca a la cua d'esdeveniments:
***Només aquest fil pot tocar un graf d'escena que ja es mostra.** Els nodes no són thread-safe, i és una decisió deliberada: sense sincronització, el dibuix és molt més ràpid. El preu és que accedir-hi des d'un altre fil deixa la interfície en un estat inconsistent, sovint amb una excepció.
***Aquest fil no pot fer feina llarga.** Mentre executa el teu codi no processa esdeveniments ni repinta, de manera que l'aplicació es queda congelada. Una consulta a una base de dades o una descàrrega dins d'un gestor de botó és exactament això.

La sortida és la de sempre: la feina llarga va a un altre fil, i el resultat torna al fil de JavaFX per mostrar-lo. Els conceptes de fons són els de [Processos i fils](../../../m9/uf2.md).
## Platform.runLater
`Platform.runLater()` posa una tasca a la cua del fil de JavaFX. És el mecanisme bàsic per actualitzar la interfície des d'un fil de fons:
```java
newThread(()->{
Stringresultat=consultaLlarga();// fil de fons
Platform.runLater(()->label.setText(resultat));// fil de JavaFX
}).start();
```
Funciona, però deixa la feina de coordinació a les teves mans: saber si la tasca ha acabat, mostrar el progrés, cancel·lar-la o recollir l'excepció que hagi llançat.
## Task
El paquet `javafx.concurrent` resol precisament això. Un [`Task<V>`](https://openjfx.io/javadoc/25/javafx.graphics/javafx/concurrent/Task.html) és una feina que s'executa en un fil de fons i que exposa el seu estat com a **propietats observables**, ja preparades per lligar-les a la interfície.
El mètode `call()` s'executa al fil de fons. La resta ja el gestiona JavaFX:
*`updateProgress()`, `updateMessage()` i `updateValue()` es poden cridar des de `call()` i publiquen el valor al fil de JavaFX. **No cal `runLater()`.**
* Els gestors `setOnSucceeded()`, `setOnFailed()` i `setOnCancelled()` s'executen al fil de JavaFX, de manera que hi pots tocar la interfície directament.
*`cancel()` marca la tasca, i el `call()` ho ha de comprovar amb `isCancelled()` per aturar-se de veritat.
Un `Task` és d'un sol ús. Si la feina s'ha de poder repetir, com un refresc periòdic, el que vols és un [`Service`](https://openjfx.io/javadoc/25/javafx.graphics/javafx/concurrent/Service.html): fabrica un `Task` nou cada vegada i es pot arrencar i reiniciar amb `start()` i `restart()`.
Changes for src/java/uf5/ud3/fxml.md: 1 added line, 1 removed line.
Original line number
Diff line number
Diff line
@@ -2,7 +2,7 @@
<!-- toc -->
A l'hora de crear elements gràfics tenim dues opcions: crear-los programàticament o bé amb un arxiu de tipus XML anomenat FXML. El format FXML facilita el dibuix mitjançant eines de disseny com el [Scene Builder](https://www.oracle.com/java/technologies/javase/javafxscenebuilder-info.html). A més, permet associar el codi XML amb el codi Java:
A l'hora de crear elements gràfics tenim dues opcions: crear-los programàticament o bé amb un arxiu de tipus XML anomenat FXML. El format FXML facilita el dibuix mitjançant eines de disseny com el [Scene Builder](https://gluonhq.com/products/scene-builder/). A més, permet associar el codi XML amb el codi Java:
* Cal definir un controlador, un objecte Java que serà el nexe de comunicació del món XML i el món Java. Aquest ha d'implementar la interfície javafx.fxml.Initializable.
* Defineix associacions entre objectes al FXML (propietat `fx:id` dels elements) i objectes Java del controlador.