Introduktion til JavaFx

1. Introduktion

JavaFX er et bibliotek til opbygning af rige klientapplikationer med Java. Det giver en API til design af GUI-applikationer der kører på næsten alle enheder med Java-support.

I denne vejledning vil vi fokusere på og dække nogle af dens nøglefunktioner og funktionalitet.

2. JavaFX API

I Java 8, 9 og 10 er ingen yderligere opsætning nødvendig for at begynde at arbejde med JavaFX-biblioteket. Projektet fjernes fra JDK startende med JDK 11.

2.1. Arkitektur

JavaFX bruger hardware-accelereret grafikrørledning til gengivelsen, kendt som Prisme. Hvad mere er, for fuldt ud at fremskynde grafikanvendelsen udnytter den enten software eller hardware-gengivelsesmekanisme ved internt at bruge DirectX og OpenGL.

JavaFX har en platformafhængig Glas vinduesværktøjslag til at oprette forbindelse til det oprindelige operativsystem. Det bruger operativsystemets begivenhedskø til at planlægge trådbrug. Det håndterer også asynkront vinduer, begivenheder, timere.

Det Medier og Internettet motorer muliggør medieafspilning og HTML / CSS-understøttelse.

Lad os se, hvordan hovedstrukturen i en JavaFX-applikation ser ud:

Her bemærker vi to hovedcontainere:

  • Scene er hovedbeholderen og startpunktet for applikationen. Det repræsenterer hovedvinduet og sendes som et argument fra Start() metode.
  • Scene er en beholder til at holde UI-elementerne, såsom billedvisninger, knapper, gitre, tekstbokse.

Det Scene kan udskiftes eller skiftes til en anden Scene. Dette repræsenterer en graf med hierarkiske objekter, der er kendt som en Scene Kurve. Hvert element i dette hierarki kaldes en node. En enkelt knude har sit ID, stil, effekter, begivenhedshåndterere, tilstand.

Derudover er Scene indeholder også layoutbeholdere, billeder, medier.

2.2. Tråde

På systemniveau JVM opretter separate tråde til kørsel og gengivelse af applikationen:

  • Prisme rendering thread - ansvarlig for gengivelse af Scenegraf separat.
  • Applikationstråd - er hovedtråden i ethvert JavaFX-program. Alle de levende noder og komponenter er knyttet til denne tråd.

2.3. Livscyklus

Det javafx.application.Application klasse har følgende livscyklusmetoder:

  • i det() - kaldes, når applikationsinstansen er oprettet. På dette tidspunkt er JavaFX API ikke klar endnu, så vi kan ikke oprette grafiske komponenter her.
  • start (scenetrin) - alle de grafiske komponenter oprettes her. Også, hovedtråden til de grafiske aktiviteter starter her.
  • hold op() - kaldes inden applikationslukningen for eksempel når en bruger lukker hovedvinduet. Det er nyttigt at tilsidesætte denne metode til en vis oprydning inden applikationens afslutning.

Det statiske lancering () metoden starter JavaFX-applikationen.

2.4. FXML

JavaFX bruger et specielt FXML-markeringssprog til at oprette visningsgrænsefladerne.

Dette giver en XML-baseret struktur til at adskille visningen fra forretningslogikken. XML er mere egnet her, da det er i stand til naturligt at repræsentere en Scenegraf hierarki.

Endelig for at indlæse .fxml fil, bruger vi FXMLLoader klasse, hvilket resulterer i objektgrafen for scenehierarkiet.

3. Kom godt i gang

For at blive praktisk, og lad os bygge et lille program, der giver mulighed for at søge gennem en liste over mennesker.

Lad os først tilføje en Person model klasse - til at repræsentere vores domæne:

offentlig klasse person {privat SimpleIntegerProperty id; privat SimpleStringProperty navn; privat SimpleBooleanProperty isEm Employed; // getters, setters}

Læg mærke til, hvordan man pakker op int, String og boolsk værdier, vi bruger SimpleIntegerProperty, SimpleStringProperty, SimpleBooleanProperty klasser i javafx.bønner. ejendom pakke.

Lad os derefter oprette Vigtigste klasse, der udvider Ansøgning abstrakt klasse:

public class Main udvider Application {@Override public void start (Stage primaryStage) kaster Undtagelse {FXMLLoader loader = ny FXMLLoader (Main.class.getResource ("/ SearchController.fxml")); AnchorPane-side = (AnchorPane) loader.load (); Scene scene = ny scene (side); primaryStage.setTitle ("Titel går her"); primaryStage.setScene (scene); primaryStage.show (); } offentlig statisk ugyldig hoved (String [] args) {launch (args); }}

Vores hovedklasse tilsidesætter Start() metode, som er startpunktet for programmet.

Derefter FXMLLoader indlæser objektgrafhierarkiet fra SearchController.fxml ind i Ankerrude.

Efter start af en ny Scene, satte vi det til det primære Scene. Vi indstiller også titlen til vores vindue og at vise() det.

Bemærk, at det er nyttigt at medtage hoved () metode til at kunne køre JAR-filen uden JavaFX Launcher.

3.1. FXML-visning

Lad os nu dykke dybere ned i SearchController XML-fil.

Til vores søgeapplikation tilføjer vi et tekstfelt for at indtaste nøgleordet og søgeknappen:

Ankerrude er rodbeholderen her og den første knude i grafhierarkiet. Når du ændrer størrelsen på vinduet, placerer det barnet igen til dets forankringspunkt. Det fx: controller attribut ledes Java-klassen med markeringen.

Der er nogle andre indbyggede layout tilgængelige:

  • BorderPane - opdeler layoutet i fem sektioner: top, højre, bund, venstre, center
  • HBox - anbring de underordnede komponenter i et vandret panel
  • VBox - underordnede noder er arrangeret i en lodret søjle
  • GridPane - nyttigt til oprettelse af et gitter med rækker og kolonner

I vores eksempel inde i det vandrette HBox panel, brugte vi en Etiket at placere tekst, Tekstfelt til input, og a Knap. Med fx: id vi markerer elementerne, så vi kan bruge dem senere i Java-koden.

Det VBox panelet er, hvor vi viser søgeresultaterne.

For at kortlægge dem til Java-felterne bruger vi derefter @FXML kommentar:

offentlig klasse SearchController {@FXML privat TextField searchField; @FXML privat knap searchButton; @FXML privat VBox dataContainer; @FXML privat TableView tableView; @FXML privat ugyldighed initialiseres () {// søgepanel searchButton.setText ("Søg"); searchButton.setOnAction (begivenhed -> loadData ()); searchButton.setStyle ("- fx-baggrundsfarve: # 457ecd; -fx-tekst-fyld: #ffffff;"); initTable (); }}

Efter at have udfyldt @FXML kommenterede felter, initialisere () kaldes automatisk op. Her er vi i stand til at udføre yderligere handlinger over UI-komponenterne - som at registrere begivenhedslyttere, tilføje stil eller ændre tekstegenskaben.

I initTable () metode opretter vi den tabel, der indeholder resultaterne, med 3 kolonner og føjer den til dataContainer VBox:

privat ugyldigt initTable () {tableView = ny TableView (); TableColumn id = ny TableColumn ("ID"); TableColumn name = new TableColumn ("NAME"); TableColumn ansat = ny TableColumn ("ANSATT"); tableView.getColumns (). addAll (id, navn, ansat); dataContainer.getChildren (). tilføj (tableView); }

Endelig vil al denne logik, der er beskrevet her, producere følgende vindue:

4. Bindende API

Nu hvor de visuelle aspekter håndteres, lad os begynde at se på bindende data.

Den bindende API giver nogle grænseflader, der underretter objekter, når der sker en værdiskift af et andet objekt.

Vi kan binde en værdi ved hjælp af binde() metode eller ved at tilføje lyttere.

Envejsbinding giver kun en binding til en retning:

searchLabel.textProperty (). bind (searchField.textProperty ());

Her opdaterer enhver ændring i søgefeltet etikettens tekstværdi.

Til sammenligning synkroniserer tovejsbinding værdierne for to egenskaber i begge retninger.

Den alternative måde at binde felterne på er ChangeListeners:

searchField.textProperty (). addListener ((observerbar, oldValue, newValue) -> {searchLabel.setText (newValue);});

Det Observerbar interface giver mulighed for at observere objektets værdi for ændringer.

For at eksemplificere dette er den mest anvendte implementering javafx.collections.ObservableList grænseflade:

ObservableList masterData = FXCollections.observableArrayList (); ObservableList results = FXCollections.observableList (masterData);

Her underretter enhver modelændring som indsættelse, opdatering eller fjernelse af elementerne UI-kontrollerne med det samme.

Det masterData listen indeholder den oprindelige liste over Person objekter, og resultatlisten vil være den liste, vi viser ved søgning.

Vi er også nødt til at opdatere initTable () metode til at binde dataene i tabellen til den oprindelige liste og til at forbinde hver kolonne til Person klasse felter:

privat ugyldigt initTable () {tableView = ny TableView (FXCollections.observableList (masterData)); TableColumn id = ny TableColumn ("ID"); id.setCellValueFactory (ny PropertyValueFactory ("id")); TableColumn name = new TableColumn ("NAME"); name.setCellValueFactory (ny PropertyValueFactory ("navn")); TableColumn ansat = ny TableColumn ("ANSATT"); employed.setCellValueFactory (ny PropertyValueFactory ("erEm Employed")); tableView.getColumns (). addAll (id, navn, ansat); dataContainer.getChildren (). tilføj (tableView); }

5. Samtidighed

Arbejde med UI-komponenterne i en scenediagram er ikke trådsikker, da det kun er adgang til det fra applikationstråden. Det javafx.concurrent pakken er her for at hjælpe med multithreading.

Lad os se, hvordan vi kan udføre datasøgningen i baggrundstråden:

privat ugyldigt loadData () {String searchText = searchField.getText (); Opgave opgave = ny opgave() {@Override-beskyttet ObservableList-opkald () kaster Exception {updateMessage ("Indlæser data"); returner FXCollections.observableArrayList (masterData .stream () .filter (værdi -> value.getName (). toLowerCase (). indeholder (searchText)) .collect (Collectors.toList ())); }}; }

Her opretter vi en engangsopgave javafx.concurrent.Task gøre indsigelse og tilsidesætte opkald() metode.

Det opkald() metoden kører udelukkende på baggrundstråden og returnerer resultatet til applikationstråden. Dette betyder, at enhver manipulation af UI-komponenterne inden for denne metode vil kaste en undtagelse for runtime.

Imidlertid, updateProgress (), updateMessage () kan kaldes for at opdatere Application thread-emner. Når opgavetilstanden overgår til SUCCEEDED-tilstand, onSucceeded () event handler kaldes fra applikationstråden:

task.setOnSucceeded (event -> {results = task.getValue (); tableView.setItems (FXCollections.observableList (results));}); 

I samme tilbagekald har vi opdateret tabelvisning data til den nye liste over resultater.

Det Opgave er Kan køres, så for at starte det skal vi bare starte et nyt Tråd med opgave parameter:

Tråd th = ny tråd (opgave); th.setDaemon (sand); th.start ();

Det setDaemon (sand) flag angiver, at tråden afsluttes, når arbejdet er afsluttet.

6. Håndtering af begivenheder

Vi kan beskrive en begivenhed som en handling, der kan være interessant for applikationen.

For eksempel håndteres eller underrettes brugerhandlinger som museklik, tastetryk, vinduestørrelse javafx.event.Event klasse eller nogen af ​​dens underklasser.

Vi skelner også mellem tre typer begivenheder:

  • InputEvent - alle typer nøgle- og mushandlinger som f.eks KEY_PRESSED, KEY_TYPED, KEY_RELEASED eller MOUSE_PRESSES, MOUSE_RELEASED
  • ActionEvent - repræsenterer en række handlinger som fyring a Knap eller efterbehandling af en KeyFrame
  • WindowEventWINDOW_SHOWING, WINDOW_SHOWN

At demonstrere, kodefragmentet nedenfor fanger begivenheden ved at trykke på Gå ind nøgle over searchField:

searchField.setOnKeyPressed (begivenhed -> {hvis (event.getCode (). er lig med (KeyCode.ENTER)) {loadData ();}});

7. Stil

Vi kan ændre brugergrænsefladen til JavaFX-applikationen ved at anvende et brugerdefineret design til det.

Som standard bruger JavaFX modena.css som en CSS-ressource for hele applikationen. Dette er en del af jfxrt.jar.

For at tilsidesætte standardstil kan vi tilføje et typografiark til scenen:

scene.getStylesheets (). tilføj ("/ search.css");

Vi kan også bruge inline-stil; for eksempel at indstille en typegenskab for en bestemt node:

searchButton.setStyle ("- fx-baggrund-farve: slateblue; -fx-tekst-fyld: hvid;");

8. Konklusion

Denne korte opskrivning dækker det grundlæggende i JavaFX API. Vi gennemgik den interne struktur og introducerede nøglefunktioner i dens arkitektur, livscyklus og komponenter.

Som et resultat lærte vi og er nu i stand til at oprette en simpel GUI-applikation.

Og som altid er den fulde kildekode til vejledningen tilgængelig på GitHub.