Göm menyn

TDDE10 Objektorienterad programmering i Java

JavaFX - Referens för projekt och Lab4

Magnus Nielsen © 2023

Installera JavaFX på egen dator

Dessa instruktioner låter dig köra samma version av JavaFX som finns på LiU's maskiner för att säkerställa att ditt program fungerar likadant om du jobbar hemifrån.

Linux

Till att börja med:
Ladda hem zip-filen.
  • Skapa en lämplig mapp, exempelvis Libs på lämplig plats. Vårt förslag är något i stil med: /home/dinanvändare/Libs. Du kan göra detta genom att i terminalen köra:
    mkdir ~/Libs
  • Flytta zip-filen du nyss laddade hem till denna mapp:
    mv ~/Downloads/openjfx-21.0.2*.zip ~/Libs
    Beroende på din installation kan du behöva ersätta Downloads med Hämtningar.
  • Gå till mappen och extrahera filerna:
    cd ~/Libs && unzip openjfx-21.0.2*.zip
    Detta bör skapa en mapp som heter javafx-sdk-21.0.2, och installationen är klar. Du kan nu ta bort zip-filen.

MacOS

Till att börja med:
Ladda hem zip-filen för x64 (mest sannolikt) eller aarch64 beroende på vilken arkitektur du har. Du kan avgöra arkitektur genom att öppna en terminal och köra:
uname -m
Om du får svar med något arm eller aarch väljer du aarch64, annars x64 ovan.
  • Skapa en lämplig mapp, exempelvis Libs på lämplig plats. Vårt förslag är något i stil med: /Users/dinanvändare/Libs. Du kan göra detta genom att i terminalen köra:
    mkdir ~/Libs
  • Flytta zip-filen du nyss laddade hem till denna mapp:
    mv ~/Downloads/openjfx-21.0.2*.zip ~/Libs
    Beroende på din installation kan du behöva ersätta Downloads med Hämtningar.
  • Gå till mappen och extrahera filerna:
    cd ~/Libs && unzip openjfx-21.0.2*.zip
    Detta bör skapa en mapp som heter javafx-sdk-21.0.2, och installationen är klar. Du kan nu ta bort zip-filen.

Windows

Till att börja med:
Ladda hem zip-filen.
  • Skapa en lämplig mapp, exempelvis Libs på lämplig plats. Vårt förslag är något i stil med: C:\användare\dinUser\Libs. Du kan göra detta genom att i gå in i filhanteraren, navigera fram till Den här datorn -> C:\ -> användare (eller users) -> din användare, högerklicka och skapa mapp: Libs
  • Flytta zip-filen du nyss laddade hem till denna mapp (klipp ut eller kopiera och klistra in).
  • Gå till mappen och extrahera filerna:
    Dubbeklicka på filen, och klicka på "Extrahera alla".

    Detta bör skapa en mapp som heter javafx-sdk-21.0.2, och installationen är klar. Du kan nu ta bort zip-filen.

Förbered ditt JavaFX-projekt

I Eclipse skapar du ditt nya projekt, exempelvis TDDE10-Lab4, och skapa sedan din "main-fil", exempelvis Main.java. Observera att det, i denna "main-fil", måste finnas en "main-metod" (public static void main(String[] args)) för att det ska räknas som en "main-fil" i Java. Om du fick en module-info.java på köpet av Eclipse, tag bort denna.

ThinLinc eller SU-sal

  • I Eclipse: högerklicka ditt projekt (exempelvis TDDE10-Lab4) och välj "Properties". Du får upp ett fönster med menyer och val. I menyn till vänster väljer du "Java Build Path". Du får nu upp ett delfönster med flikar. Välj fliken "Libraries". Klicka på "Modulepath", och sedan på knappen "Add External JARs...". Detta borde ge en filsystemsdialog. Navigera till mappen:
    /courses/TDDE10/Libs/javafx-sdk-19
    Markera (shift eller ctrl-klicka) samtliga filer som slutar på .jar och klicka på "Open". Klicka på "Apply and Close". Du har nu lagt till så att Eclipse kan hitta JavaFX för detta projekt.

    Om du inte kan se den angivna mappen i ditt Eclipsefönster, öppna en terminal och skriv:
    cd /courses/TDDE10/
    Kursmapparna laddas dynamiskt så ibland kan det se ut som att de inte finns. Laddar du den i terminal bör den synas, både för dig och andra, tills den anses vara inaktiv igen.
  • Vi måste nu berätta för JVM var den ska hitta JavaFX. Vi måste alltså skapa en "Run Configuration" för ditt program. Klicka på "Run"-menyn högst upp i Eclipse, och välj "Run Configurations". Du får upp ett fönster med eventuella gamla konfigurationer, samt lite templates och annat smått och gott. Högst upp till vänster har du en knapp: "New launch configuration". Klicka på den. Du bör få upp ett fönster som ser ut ungefär så här:

    Under project klickar du på "Browse" och väljer ditt projekt. Döp konfigurationen till något lämpligt, ex. Lab4Main. Under Main klickar du också på "Browse" och väljer din main-klass. Klicka på "Arguments". Under VM-arguments, kopiera och klistra in följande två rader:
    --module-path /courses/TDDE10/Libs/javafx-sdk-19/lib
    --add-modules=javafx.controls

    Efteråt bör det se ut ungefär så här:

    (namnen kan skilja beroende på vad du kallar ditt projekt och din "main-fil", samt version av javafx).

Linux

I Eclipse skapar du ditt nya projekt, exempelvis TDDE10-Lab4, och skapa sedan din "main-fil", exempelvis Main.java.
  • I Eclipse: högerklicka på ditt projekt, exempelvis TDDE10-lab3, och välj "Properties". Du får upp ett fönster med menyer och val. I menyn till vänster väljer du "Java Build Path". Du får nu upp ett delfönster med flikar. Välj fliken "Libraries". Klicka på "Modulepath", och sedan på knappen "Add External JARs...". Detta borde ge en filsystemsdialog. Navigera till där du installerade JavaFX (ex: /home/dinanvändare/Libs/javafx-sdk-21.0.2. Markera (shift eller ctrl-klicka) samtliga filer som slutar på .jar och klicka på "Open". Klicka på "Apply and Close". Du har nu lagt till så att Eclipse kan hitta JavaFX för detta projekt.
  • Vi måste nu berätta för JVM var den ska hitta JavaFX. Vi måste alltså skapa en "Run Configuration" för ditt program. Klicka på "Run"-menyn högst upp i Eclipse, och välj "Run Configurations". Du får upp ett fönster med eventuella gamla konfigurationer, samt lite templates och annat smått och gott. Högst upp till vänster har du en knapp: "New launch configuration". Klicka på den. Du bör få upp ett fönster som ser ut ungefär så här:

    Under project klickar du på "Browse" och väljer ditt projekt. Döp konfigurationen till något lämpligt, ex. Lab4Main. Under Main klickar du också på "Browse" och väljer din main-klass. . Klicka på "Arguments". Under VM-arguments, kopiera och klistra in följande två rader, men ersätt dinanvändare med ditt användarnamn, eller ersätt sökvägen med den du valde om du inte följde förslagen vid installation:
    --module-path /home/dinanvändare/Libs/javafx-sdk-21.0.2/lib
    --add-modules=javafx.controls

    Efteråt bör det se ut ungefär så här:

    (namnen kan skilja beroende på vad du kallar ditt projekt och din "main-fil", samt version av javafx).

    Eventuellt behöver du även, på denna sida, avmarkera: Use the -XstartOnFirstThread argument when launching with SWT. Låt detta vara från start, men skulle det inte fungera när du försöker köra (inget händer) avmarkerar du denna checkbox.

MacOS

I Eclipse: högerklicka ditt projekt (exempelvis TDDE10-Lab4) och välj "Properties". Du får upp ett fönster med menyer och val. I menyn till vänster väljer du "Java Build Path". Du får nu upp ett delfönster med flikar. Välj fliken "Libraries". Klicka på "Modulepath", och sedan på knappen "Add External JARs...". Detta borde ge en filsystemsdialog. Navigera till mappen:
/courses/TDDE10/Libs/javafx-sdk-21.0.2
Markera (shift eller ctrl-klicka) samtliga filer som slutar på .jar och klicka på "Open". Klicka på "Apply and Close". Du har nu lagt till så att Eclipse kan hitta JavaFX för detta projekt.
  • Vi måste nu berätta för JVM var den ska hitta JavaFX. Vi måste alltså skapa en "Run Configuration" för ditt program. Klicka på "Run"-menyn högst upp i Eclipse, och välj "Run Configurations". Du får upp ett fönster med eventuella gamla konfigurationer, samt lite templates och annat smått och gott. Högst upp till vänster har du en knapp: "New launch configuration". Klicka på den. Du bör få upp ett fönster som ser ut ungefär så här:

    Under project klickar du på "Browse" och väljer ditt projekt. Döp konfigurationen till något lämpligt, ex. Lab4Main. Under Main klickar du också på "Browse" och väljer din main-klass. Klicka på "Arguments". Under VM-arguments, kopiera och klistra in följande två rader men ersätt dinanvändare med ditt användarnamn, eller ersätt sökvägen med den du valde om du inte följde förslagen vid installation:
    --module-path /Users/dinanvändare/Libs/javafx-sdk-21.0.2/lib
    --add-modules=javafx.controls

    Efteråt bör det se ut ungefär så här:

    (namnen kan skilja beroende på vad du kallar ditt projekt och din "main-fil", samt version av javafx).

    Eventuellt behöver du även, på denna sida, avmarkera: Use the -XstartOnFirstThread argument when launching with SWT. Låt detta vara från start, men skulle det inte fungera när du försöker köra (inget händer) avmarkerar du denna checkbox.

  • Fel: Graphics Device initialization failed for : es2, sw

    När du försöker köra ditt javafx-projekt krashar det direkt och du får, om du scrollar upp i konsolen, högst upp: "Graphics Device initialization failed for : es2, sw". Sannolikt har det med rättigheter att göra.
    • Öppna inställningarna för din dator och gå till "Security & Privacy" (förmodligen Säkerhet & Sekretess eller liknande på svenska). Gå till "General"-tabben (Allmänt, troligtvis, på svenska).
    • Öppna din motsvarighet till utforskaren där du kan navigera dina filer. Gå till mappen där du har installerat javafx, och en i taget försöker du köra (dubbelklicka) alla .jar- och .dylib-filer i lib-mappen. När du klickar på dem väljer du öppna. Vid körning kommer .jar-filen att säga att den inte hittar en runtime, det är helt ok, medan .dylib öppnar en terminal som du kan stänga direkt igen. När du kört en fil kommer det sannolikt (inte garanterat) läggas till en dialog att du kan ge rättigheter åt filen i "säkerhetsfönstret" du öppnade i föregående punkt. Ge filerna de rättigheter som behövs. Repetera för samtliga av dessa filer (bara dessa två filtyper behöver rättigheter satta). Testa sedan att köra projektet igen.
    Stegen ovan ska bara behöva göras en gång, och ska inte behöva repeteras i framtiden.

    Windows

    I Eclipse: högerklicka ditt projekt (exempelvis TDDE10-Lab4) och välj "Properties". Du får upp ett fönster med menyer och val. I menyn till vänster väljer du "Java Build Path". Du får nu upp ett delfönster med flikar. Välj fliken "Libraries". Klicka på "Modulepath", och sedan på knappen "Add External JARs...". Detta borde ge en filsystemsdialog. Navigera till mappen:
    /courses/TDDE10/Libs/javafx-sdk-21.0.2
    Markera (shift eller ctrl-klicka) samtliga filer som slutar på .jar och klicka på "Open". Klicka på "Apply and Close". Du har nu lagt till så att Eclipse kan hitta JavaFX för detta projekt.
  • Vi måste nu berätta för JVM var den ska hitta JavaFX. Vi måste alltså skapa en "Run Configuration" för ditt program. Klicka på "Run"-menyn högst upp i Eclipse, och välj "Run Configurations". Du får upp ett fönster med eventuella gamla konfigurationer, samt lite templates och annat smått och gott. Högst upp till vänster har du en knapp: "New launch configuration". Klicka på den. Du bör få upp ett fönster som ser ut ungefär så här:

    Under project klickar du på "Browse" och väljer ditt projekt. Döp konfigurationen till något lämpligt, ex. Lab4Main. Under Main klickar du också på "Browse" och väljer din main-klass. Klicka på "Arguments". Under VM-arguments, kopiera och klistra in följande två rader men ersätt dinanvändare med ditt användarnamn, eller ersätt sökvägen med den du valde om du inte följde förslagen vid installation (beroende på din installation kan du behöva ersätta "Användare" med "Users" också, kolla vad mappen heter på just din maskin).:
    --module-path "C:\Användare\dinanvändare\Libs\javafx-sdk-21.0.2\lib"
    --add-modules=javafx.controls

    Efteråt bör det se ut ungefär så här:

    (namnen kan skilja beroende på vad du kallar ditt projekt och din "main-fil", samt version av javafx).

    Eventuellt behöver du även, på denna sida, avmarkera: Use the -XstartOnFirstThread argument when launching with SWT. Låt detta vara från start, men skulle det inte fungera när du försöker köra (inget händer) avmarkerar du denna checkbox.

  • Layout och fönster

    Fönstret / Stage

    I JavaFX är vår Stage själva fönstret. Den får vi gratis från start-metoden:

    	public void start(Stage primaryStage) throws Exception {
    	    // jag har valt att kalla min stage för primaryStage, du kan kalla den vad du vill
    	}
          
    Vi kan ändra storleken på fönstret och titeln, på följande vis inuti start-metoden:
    	  primaryStage.setTitle("My fancy JavaFX window!");
    	  primaryStage.setWidth(1000); // Vi sätter bredden till 1000 pixlar
    	  primaryStage.setHeight(600); // Vi sätter höjden till 600 pixlar
    	

    Skapa en layout / organisera innehåll (HBox/VBox)

    Vi kan välja att skapa alla våra komponenter i start-metoden, detta blir dock snabbt kladdigt, rörigt, och svårt att felsöka. Därför rekommenderar vi att ni skapar egna klasser för de olika delar av fönstret. Vi kanske, exempelvis, vill ha en "rityta" som vi kan rita i (inte nödvändigtvis rita i tradidionell bemärkelse, det kan handla om bilder, "spelyta", vad vi nu vill kalla det. Mer om den i Rityta / Canvas nedan.

    Utöver vår "rityta" vill vi förmodliga ha paneler. Om vi vill ha en vertikal panel (trava på höjden) skapar vi en klass som ärver från VBox, om vi vill ha en horisontell panel (stoppa in innehåll från vänster till höger) skapar vi en klass som ärver from HBox. I exemplet väljer vi att illustrera hur den kan fungera med en HBox, men de fungerar likadant frånsett hur de organiserar innehållet vi stoppar in.

    Vi skapar en panelklass som är ärver från HBox:

    	  public class HorizontalPanel extends XBox {
    	      public HorizontalPanel() {
    	          // Vi sätter en bakgrundsfärg, #d4d6d5 är hexkoden för en
    	          // färg. Googla efter colorpicker och välj en färg ni gillar.
                      setStyle("-fx-background-color: #d4d6d5;"); 
    	          setHeight(100); // Sätter höjden på panelen till 100 pixlar 
    	          setWidth(1000); // Sätter bredden till 1000 pixlar
    	      }
    	  }
    	

    När vi sedan lägger till saker i panelen är det ordningen vi lägger till dem som avgör vilken ordning de visas. Använder vi VBox kommer de att läggas till på höjden, använder vi HBox läggs de till på bredden, men i övrigt fungerar det likadant:

    	  public class HorizontalPanel extends XBox {
    	      private Button rightButton, leftButton;
    
    	      public HorizontalPanel() {
    	          // Vi sätter en bakgrundsfärg, #d4d6d5 är hexkoden för en
    	          // färg. Googla efter colorpicker och välj en färg ni gillar.
                      setStyle("-fx-background-color: #d4d6d5;"); 
    	          setHeight(100); // Sätter höjden på panelen till 100 pixlar 
    	          setWidth(1000); // Sätter bredden till 1000 pixlar
    
    	          // Vi initerar knapparna. Mer under Knappar / Buttons om hur de fungerar.
                      rightButton = new Button("Right"); 
    	          leftButton = new Button("Left"); 
    	          // Vi lägger till leftButton först då vi vill ha den vänster.
    	          getChildren().add(leftButton); 
    	          getChildren().add(rightButton);
    	      }
    	  }
    	

    Om vi vill kan vi lägga till HBoxar i VBoxar och vice versa för att få innehållet precis som vi vill.

    Visa upp layouten i fönstret (Scene)

    För att visa upp innehåll i vårt fönster (Stage) behöver vi en scen (Scene). Vi sätter in vår layout i scenen, och stoppar in scenen i fönstret. Sedan säger vi till fönstret att rita ut sig.

    Ponera att vi har gjort tre olika paneler (eventuellt som ovan, någon kanske är ett Canvas, etc. men approachen är densamma) som vi vill stoppa in på höjden i vårt fönster. Vi kan då nyttja en VBox som vi stoppar in våra paneler i, och skapar sedan en scen åt VBoxen:

    	public class Main extends Application {
    	    public static void main(String[] args) {
                    launch(args);
    	    }
    
    	    public void start(Stage primaryStage) throws Exception {
    	        primaryStage.setTitle("My fancy JavaFX window!");
    	        primaryStage.setWidth(1000); // Vi sätter bredden till 1000 pixlar
    	        primaryStage.setHeight(600); // Vi sätter höjden till 600 pixlar
    	
                    TopBar top = new TopBar();
    	        MiddleStuff middle = new MiddleStuff();
    	        BottomBar bot = new BottomBar();
    	
    	        HBox mainLayout = new HBox();
    	        mainLayout.getChildren().add(top); // top först, vi vill ha den högst upp
    	        mainLayout.getChildren().add(middle); // sedan middle
    	        mainLayout.getChildren().add(bot); // sist botten
    
    	        Scene theScene = new Scene(mainLayout); // Vi skapar en scen åt vår layout
    	        primaryStage.setScene(theScene); // Vi sätter scenen i fönstret
    	        primaryStage.show(); // Vi säger till fönstret att rita ut sig.
    	    }
    	}
    	

    De viktigaste komponenterna (Canvas, Button, ...)

    Ritytan, eller canvaset

    Vi vill ibland ha ytor där vi kan rita ut egna bilder, eller rita med hjälp av de inbyggda verktygen. Till vår hjälp har vi klassen Canvas. Den kommer med stöd för att rita olika geometriska figurer, text, bilder, etc. Den är inte en behållare, som VBox och HBox, utan har egen funktionalitet. Sannolikt vill vi göra en egen Canvas-klass så att vi smidigat kan kapsla in den funktionalitet vi vill ha i vårt eget Canvas.

    	  public class MyCanvas extends Canvas {
    	      public MyCanvas() {
    	          // Precis som andra "paneler" kan vi sätta bredd och höjd på vårt canvas
    	          setHeight(400); 
    	          setWidth(1000);
     	          // Vi kan även sätta bakgrundsfärg om vi vill 
    	          setStyle("-fx-background-color: #00f241;"); 
    
    	          // Vi kan säga vad som ska hända när vi klickar i vårt canvas.
    	          setOnMouseClicked(event -> {
    	              System.out.println("Ojojoj, vi klicka i Canvas. Tvärtufft!");
    	          });
    	      } 
    	  }
    	

    Vår "pensel", GraphicsContext2D

    Var som helst i vår Canvas kan vi plocka fram vår "pensel" och arbeta med den, eller skicka den till andra klasser och låta dem rita ut sig i vårt Canvas genom att använder vårt GraphicsContext2D-objekt. Vi kan även byta färg på "penseln".

    	  GraphicsContext context = getGraphicsContext2D();
    	  // Vi sätter "fill"-färgen till djup rosa.
    	  context.setFill(Color.DEEPPINK);
    	  // Vi ritar ut en 100 gånger 100 pixlar stor kvadrat som startar
    	  // i övre vänstra hörnet (koordinat 0,0).
    	  context.fillRect(0, 0, 100, 100); 
    	  // Det finns mängder av utritningsmetoder. Testa att, i Eclipse,
    	  // köra context.fill och titta på listan av metoder.
    	  
    	  // Vi kan även rita ut former utan att fylla dem med en färg:
    	  g.setStroke(Color.GREEN); // Vi kan sätta färg på "pennan", alltså strecken som ritas 
    	  g.setLineWidth(5); // Vi sätter tjockleken på "pennan"
    	  g.strokeRect(0, 0, getWidth(), getHeight()); // och ritar ut en kvadrat
    	  
    	  // Vi kan även rita ut bilder med vårt GraphicsContext2D:
    	  String imagePath = "/home/username/bildnamn.png"; // format på filnamn / path i Linux,
    	  // i macOS ersätt home med Users. 
    	  // String imagePath = "C:\\Användare\\username\\bildnamn.png"; // format för Windows.
    	  // Ersätt med platsen där din bild finns, samt namnet på bilden.
    	  Image image = new Image((new FileInputStream(imagePath)); // Ladda in bilden.
    	  // ritar ut bilden med start i koordinat 10,10 med bredd och höjd 200.
    	  getGraphicsContext2D().drawImage(image, 10, 10, 200, 200);
    	  // ritar ut bilden på koordinat 250,250 med sin egen bredd och höjd
    	  getGraphicsContext2D().drawImage(image, 250, 250, image.getWidth(), image.getHeight()); 
    	  
    	  // Vi har en "bil-klass" som själv vet hur den ritar ut sig, men behöver låna vårt
    	  // GraphicsContext2D-objekt för att kunna rita ut sig i vårt Canvas:
    	  Car myCar = new Car();
    	  // Vi skickar vårt context-objekt till bilens drawYourself-metod och den kan
    	  // då jobba med contextobjektet precis som vi gjort ovan.
    	  myCar.drawYourself(context); 
    
    	  // Sist men inte minst kanske vi vill sudda fönstret, eller delar av det.
    	  // Vi rensar från koordinat 0,0 lika brett och högt som vår canvas.
    	  context.clearRect(0, 0, getWidth(), getHeight()); 
    	

    Den inbyggda knappklassen (Button)

    Det kan i många fall vara användbart att snabbt kunna skapa knappar efter en färdig mall. Speciellt om vi bara vill ha en generisk knapp, utan speciellt utseende:

    	  Button clear = new Button("MinKnapp"); // Vi skapar en knapp med texten MinKnapp
    	  clear.setOnAction(value -> { // Vi säger till knappen vilken funktionalitet den ska ha
    	      // Vi kan göra vad som helst här, behöver inte vara utskrifter.
    	      System.out.println("Vi tryckte på knappen! Det går bra nu!"); 
    	  });
    	


    Sidansvarig: Magnus Nielsen
    Senast uppdaterad: 2024-02-02