Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Med FXML er det nokså enkelt å lage større figurer, som en sammensetning av enkle figur-elementer som sirkler, rektangler og streker. En enkel strekmann kan se ut som følger med FXML:

Code Block
languagejavafx
    <Group layoutY="50">
        <Circle layoutX="100" layoutY="20" radius="20" stroke="black" fill="white"/>
        <Circle layoutX="112" layoutY="20" radius="2" stroke="black" fill="blue"/>
        <Line layoutX="120" layoutY="20" startX="0" startY="-4" endX="3" endY="0" stroke="black"/>
        <Line layoutX="120" layoutY="20" startX="3" startY="0" endX="0" endY="1" stroke="black"/>
        <Line layoutX="100" layoutY="40" endX="0" endY="30" stroke="black"/>
        <Group layoutX="100" layoutY="50">
            <Line layoutY="0"  endX="-10" endY="10" stroke="black"/>
            <Line layoutY="0"  endX= "10" endY="10" stroke="black"/>
            <Line layoutY="20" endX="-10" endY="15" stroke="black"/>
            <Line layoutY="20" endX= "10" endY="15" stroke="black"/>
        </Group>
    </Group>

Denne figuren er laget med FXML-koden til venstre.

...

Merk at for å vise frem strekmann-figuren, så trengs det litt mer FXML-kode over/rundt og litt Java-kode for å laste inn FXML-koden og vise frem figuren. Den komplette FXML- og Java-koden er vist under.

Code Block
languagejavafx
collapsetrue
<?xml version="1.0" encoding="UTF-8"?>
 
<?import javafx.scene.text.Text?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.HBox?>

<?import javafx.scene.layout.Region?>
<?import javafx.scene.Group?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.shape.Line?>

<Pane xmlns:fx="http://javafx.com/fxml"
     minWidth="400" minHeight="600">
    <Group layoutY="50">
        <Circle layoutX="100" layoutY="20" radius="20" stroke="black" fill="white"/>
        <Circle layoutX="112" layoutY="20" radius="2" stroke="black" fill="blue"/>
        <Line layoutX="120" layoutY="20" startX="0" startY="-4" endX="3" endY="0" stroke="black"/>
        <Line layoutX="120" layoutY="20" startX="3" startY="0" endX="0" endY="1" stroke="black"/>
        <Line layoutX="100" layoutY="40" endX="0" endY="30" stroke="black"/>
        <Group layoutX="100" layoutY="50" visible="true">
            <Line layoutY="0"  endX="-10" endY="10" stroke="black"/>
            <Line layoutY="0"  endX= "10" endY="10" stroke="black"/>
            <Line layoutY="20" endX="-10" endY="15" stroke="black"/>
            <Line layoutY="20" endX= "10" endY="15" stroke="black"/>
        </Group>
    </Group>
</Pane>

Code Block
languagejava
collapsetrue
package trinn2;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class StickMan1 extends Application {
    @Override
    public void start(Stage primaryStage) throws IOException {
        Parent root = FXMLLoader.load(this.getClass().getResource("StickMan1.fxml"));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

Den komplette FXML-koden er vist til venstre. Import-linjene øverst trengs for å kunne bruke navn tilsvarende Java-klasser lenger ned i fila. F.eks. vil Circle egentlig referere til java-klassen javafx.scene.shape.Circle. Java-koden antar her at FXML-fila ligger i samme mappe som java-fila.

...

Her er eksempel-kode som viser dette i praksis (komplett kode er vist lengre ned):

Code Block
languagejava
public class StickMan2 extends Application {
    @Override
    public void start(Stage primaryStage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setController(this);
        Parent root = (Parent) fxmlLoader.load(this.getClass().getResourceAsStream("StickMan2.fxml"));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
	...
    @FXML Node stickMan, armsAndLegs1, armsAndLegs2;
    @FXML Shape eye;
	...
}

...

Standard-teknikken for å håndtering av interaktive elementer er bruk av såkalte lyttere, som er (ofte egne) objekter med metoder som kalles når noe bestemt skjer, f.eks. at en bruker trykker en knapp. Denne teknikken er litt omstendelig (vi viser ikke eksempler her), så også her tilbyr FXML litt automatisering. Tanken er at det samme kontroller-objektet som settes med setController-metoden, også brukes som lytter, dvs. inneholder metoder som automatisk skal kalles ved gitte hendelser, som musklikk og tastetrykk. Denne automatikken ligner på bruken av FXML-id-er og feltlitt på teknikken beskrevet over, ved at den også er en kombinasjon av FXML-attributter og @FXML-annotering av Java-elementer:

 

...

  • I Java-koden lager en metoder for å håndtere bruker-input, og disse annoteres ed @FXML, f.eks. @FXML void handleButtonClick() { ... }. Disse metodene kan (men må ikke) deklarere et hendelse-argument for å ta imot mer detaljert informasjon om hva brukeren gjorde. Typen til argumentet er avhengig av typen hendelse, f.eks. vil et trykk på en Button ha typen ActionEvent.
  • I FXML-koden angis at disse metoden skal kalles ved å bruke on-attributter med verdien #metodenavn, f.eks. <Button onAction="#handleButtonClick"/>. Akkurat hvilke on-attributter en kan bruke, er avhengig av typen element, f.eks. støtter Button flere bl.a. onAction, onKeyPressed og onMouseClicked.

Her er eksempel-kode som viser dette i praksis, med Java-kode til venstre og FXML-kode til høyre (komplett kode er vist lengre ned):

Code Block
languagejava
    @FXML
    void walk() {
        step = ! step;
        stickMan.setLayoutX(stickMan.getLayoutX() + 5);
        update();
    }

@FXML angir at walk-metoden deltar i håndtering av hendelser vha. FXML-automatikken

 

Code Block
languagejavafx
        <HBox>
            <Button text="Walk!" onAction="#walk"/>
        </HBox> 

onAction="#walk" angir at knappens action-hendelse skal trigge walk-metoden

Her er komplett Java- og FXML-kode:

Code Block
languagejava
collapsetrue
package trinn2;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
public class StickMan2 extends Application {
    @Override
    public void start(Stage primaryStage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setController(this);
        Parent root = (Parent) fxmlLoader.load(this.getClass().getResourceAsStream("StickMan2.fxml"));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
    @FXML Node stickMan, armsAndLegs1, armsAndLegs2;
    @FXML Shape eye;
    
    boolean step = true;
    @FXML
    void initialize() {
        update();
    }
    void update() {
        if (step) {
            eye.setFill(Color.BLUE);
        } else {
            eye.setFill(Color.WHITE);
        }
        armsAndLegs1.setVisible(step);
        armsAndLegs2.setVisible(! step);
    }
    @FXML
    void walk() {
        step = ! step;
        stickMan.setLayoutX(stickMan.getLayoutX() + 5);
        update();
    }
    public static void main(String[] args) {
        launch(args);
    }
}
Code Block
languagejavafx
collapsetrue
<?xml version="1.0" encoding="UTF-8"?>
 
<?import javafx.scene.text.Text?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.HBox?>

<?import javafx.scene.layout.Region?>
<?import javafx.scene.Group?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.shape.Line?>

<BorderPane xmlns:fx="http://javafx.com/fxml"
     minWidth="400">
    <top>
        <HBox>
            <Button text="Walk!" onAction="#walk"/>
        </HBox>
    </top>
    <center>
        <Pane minWidth="400" minHeight="600">
            <Group fx:id="stickMan">
                <Circle layoutX="100" layoutY="20" radius="20" stroke="black" fill="white"/>
                <Circle fx:id="eye" layoutX="112" layoutY="20" radius="2" stroke="black" fill="blue"/>
                <Line layoutX="120" layoutY="20" startX="0" startY="-4" endX="3" endY="0" stroke="black"/>
                <Line layoutX="120" layoutY="20" startX="3" startY="0" endX="0" endY="1" stroke="black"/>
                <Line layoutX="100" layoutY="40" endX="0" endY="30" stroke="black"/>
                <Group fx:id="armsAndLegs1" layoutX="100" layoutY="50" visible="true">
                    <Line layoutY="0"  endX= "-5" endY="10" stroke="black"/>
                    <Line layoutY="0"  endX= "10" endY="10" stroke="black"/>
                    <Line layoutY="20" endX="-10" endY="15" stroke="black"/>
                    <Line layoutY="20" endX=  "5" endY="15" stroke="black"/>
                </Group>
                <Group fx:id="armsAndLegs2" layoutX="100" layoutY="50" visible="false">
                    <Line layoutY="0"  endX="-10" endY="10" stroke="black"/>
                    <Line layoutY="0"  endX=  "5" endY="10" stroke="black"/>
                    <Line layoutY="20" endX= "-5" endY="15" stroke="black"/>
                    <Line layoutY="20" endX= "10" endY="15" stroke="black"/>
                </Group>
            </Group>
        </Pane>
    </center>
</BorderPane>