JavaFX-Studiennotizen

Hinweise zum Studium von JavaFX

Umgebung

OS Windows 10

Java

>java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

Scene Builder JavaFX Scene Builder 8.4.1

Die von [Gluon] entwickelte (http://gluonhq.com/products/scene-builder/)

JavaFX-Eigenschaften

JavaFX verwendet ** JavaFX-Eigenschaften **, eine Erweiterung von JavaBeans, um die Eigenschaften eines Objekts darzustellen.

Die JavaFX-Eigenschaft implementiert die Eigenschaft des Objekts wie folgt.

package sample.javafx.property;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class MyClass {
    private DoubleProperty value = new SimpleDoubleProperty();
    
    public final double getValue() {
        return this.value.get();
    }
    
    public final void setValue(double value) {
        this.value.set(value);
    }

    public DoubleProperty valueProperty() {
        return this.value;
    }
}
  1. Definieren Sie die Eigenschaft (value) mit private
  1. Definieren Sie Getter und Setter
  1. Definieren Sie eine Methode namens "Eigenschaftsname Eigenschaft" --Dies gibt den Wrapper-Typ unverändert zurück

Viele der von JavaFX bereitgestellten Klassen implementieren diese JavaFX-Eigenschaft. Beispielsweise sind die Methoden aufgeführt, die der Eigenschaft "text" der Klasse Label entsprechen. (Die eigentliche Definition ist die Klasse Labeled.)

Observable JavaFX-Eigenschaften bestimmen nicht nur Methodendeklarationen, sondern bieten auch einige spezielle Funktionen, die in JavaBeans nicht enthalten sind. Eine davon ist Observable.

Klassen, die "Observable" implementieren, bieten die Möglichkeit, auf ungültige Inhalte zu überwachen.

Die in der obigen JavaFX-Eigenschaft verwendete DoubleProperty erbt ebenfalls von Observable.

Diese "Observable" hat eine Methode namens "addListener (InvalidationListener)", mit der Sie einen Listener registrieren können, der benachrichtigt wird, wenn der Inhalt ungültig wird.

package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty();

        a.addListener(observable -> {
            System.out.println("observable=" + observable);
        });

        a.set(1.0);
        a.set(2.0);
    }
}

Ausführungsergebnis


observable=DoubleProperty [value: 1.0]
observable=DoubleProperty [value: 2.0]

Das modifizierte "Observable" selbst wird als Argument an den Listener übergeben.

Deaktivieren und ändern

Einige Klassen, die "Observable" implementieren, werden nicht sofort berechnet, wenn Inhaltsänderungen angefordert werden (z. B. die Setter-Methode wird aufgerufen), und werden nur berechnet, wenn der Inhalt das nächste Mal angefordert wird. Es gibt so etwas wie (Verzögerungsberechnung).

Mit anderen Worten, es kann einen Zeitraum geben, in dem der Inhalt zwischen dem Zeitpunkt, zu dem die Inhaltsänderung angefordert wird, und dem Zeitpunkt, zu dem der Inhalt tatsächlich berechnet wird, nicht abgeschlossen ist.

Wenn dieser Inhalt nicht finalisiert ist, wird er als ** ungültig ** ausgedrückt. Wenn die Berechnung tatsächlich durchgeführt und der Inhalt bestätigt wird, wird dies als ** Änderung ** ausgedrückt.

InvalidationListener wird jetzt zurückgerufen, wenn der Inhalt ungültig wird.

Abhängig von der Implementierungsklasse kann der Inhalt sofort berechnet werden. In diesem Fall erfolgt die Ungültigmachung und Änderung gleichzeitig (nach der Ungültigmachung wird der Inhalt sofort bestätigt (geändert)).

ObservableValue

package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty();

        a.addListener((observableValue, oldValue, newValue) -> {
            System.out.println("observableValue=" + observableValue + ", oldValue=" + oldValue + ", newValue=" + newValue);
        });
        
        a.set(1.0);
        a.set(2.0);
    }
}

Ausführungsergebnis


observableValue=DoubleProperty [value: 1.0], oldValue=0.0, newValue=1.0
observableValue=DoubleProperty [value: 2.0], oldValue=1.0, newValue=2.0

Als Schnittstelle, die "Observable" erbt, gibt es eine [ObservableValue] -Schnittstelle (https://docs.oracle.com/javase/jp/8/javafx/api/javafx/beans/value/ObservableValue.html). Es bietet eine Methode namens "addListener (ChangeListener)", mit der Sie einen Listener registrieren können, der benachrichtigt wird, wenn sich ein Wert ändert. Dem Listener werden der geänderte "ObservableValue" selbst und die Rohwerte vor und nach der Änderung übergeben.

Die von JavaFX bereitgestellten Eigenschaftsklassen, einschließlich "DoubleProperty", implementieren "ObservableValue", sodass sowohl die Listener "InvalidationListener" als auch "ChangeListener" registriert werden können.

Binding Bindung existiert als Schnittstelle, die "ObservableValue" erbt.

"Bindung" repräsentiert das Berechnungsergebnis, das mehrere Werte kombiniert. Die aggregierten Werte werden durch "Bindung" überwacht, so dass die Ergebnisse automatisch neu berechnet werden, wenn sich die Werte ändern.

package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty(1.0);
        DoubleProperty b = new SimpleDoubleProperty(2.0);

        DoubleBinding sum = a.add(b);

        System.out.println("sum=" + sum.get());
        
        a.set(3.0);

        System.out.println("sum=" + sum.get());
    }
}

Ausführungsergebnis


sum=3.0
sum=5.0

In diesem Beispiel erstellen wir eine "DoubleBinding", die die Summe von zwei "DoubleProperty" darstellt. Wenn Sie den Wert einer der "DoubleProperty" ändern und den Wert von "DoubleBinding" erneut erhalten, ist die Summe der neu berechnete Wert.

Auf diese Weise bietet "Bindung" einen Mechanismus zum Sammeln mehrerer Werte, zum Überwachen von Änderungen an jedem Wert und zum automatischen Aktualisieren der Berechnungsergebnisse.

Die durch "Bindung" gesammelten Werte werden als ** Quelle ** oder ** Abhängigkeit ** bezeichnet. Die "Bindung" selbst begrenzt nicht den Typ der Quelle, aber in Wirklichkeit ist es normalerweise "Observable" oder "ObservableValue".

Verzögerungsberechnung

package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty(1.0);
        DoubleProperty b = new SimpleDoubleProperty(2.0);

        DoubleBinding sum = a.add(b);

        System.out.println("sum=" + sum);
        System.out.println("sum.get()=" + sum.get());
        System.out.println("sum=" + sum);
        
        a.set(3.0);

        System.out.println("sum=" + sum);
        System.out.println("sum.get()=" + sum.get());
        System.out.println("sum=" + sum);
    }
}

Ausführungsergebnis


sum=DoubleBinding [invalid]
sum.get()=3.0
sum=DoubleBinding [value: 3.0]

sum=DoubleBinding [invalid]
sum.get()=5.0
sum=DoubleBinding [value: 5.0]

Wenn Sie ChangeListener registrieren, wird die Verzögerung nicht berechnet.

package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty(1.0);
        DoubleProperty b = new SimpleDoubleProperty(2.0);

        DoubleBinding sum = a.add(b);
        sum.addListener((observableValue, oldValue, newValue) -> {
            System.out.println("Geändert(oldValue=" + oldValue + ", newValue=" + newValue + ")");
        });

        System.out.println("sum=" + sum);
        System.out.println("sum.get()=" + sum.get());
        System.out.println("sum=" + sum);
        
        a.set(3.0);

        System.out.println("sum=" + sum);
        System.out.println("sum.get()=" + sum.get());
        System.out.println("sum=" + sum);
    }
}

Ausführungsergebnis


sum=DoubleBinding [value: 3.0]
sum.get()=3.0
sum=DoubleBinding [value: 3.0]

Geändert(oldValue=3.0, newValue=5.0)

sum=DoubleBinding [value: 5.0]
sum.get()=5.0
sum=DoubleBinding [value: 5.0]

--Wenn der Listener für Änderungsbenachrichtigungen bei "ObservableValue.addListener (ChangeListener)" registriert ist, wird die Verzögerungsberechnung nicht durchgeführt.

High-Level-API

Es gibt zwei Arten von APIs zum Erstellen von "Bindung": ** High-Level-API ** und ** Low-Level-API **.

Die übergeordnete API ist in ** Fluent API ** und ** Bindings Class Factory-Methode ** unterteilt.

Fluent API

package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty(2.0);

        DoubleBinding binding = a.add(3).multiply(2).subtract(4.0).divide(3.0);

        System.out.println("((2.0 + 3) * 2 - 4.0) / 3.0 = " + binding.get());
        
        a.set(5.0);

        System.out.println("((5.0 + 3) * 2 - 4.0) / 3.0 = " + binding.get());
    }
}

Ausführungsergebnis


((2.0 + 3) * 2 - 4.0) / 3.0 = 2.0
((4.0 + 3) * 2 - 4.0) / 3.0 = 4.0

javafx.png

Fabrikmethode der Bindungsklasse

package sample.javafx.property;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty(2.0);

        DoubleBinding binding =
                Bindings.divide(
                    Bindings.subtract(
                        Bindings.multiply(
                            Bindings.add(a, 3)
                            ,2
                        )
                        ,4.0
                    )
                    ,3.0
                );  

        System.out.println("((2.0 + 3) * 2 - 4.0) / 3.0 = " + binding.get());
        
        a.set(5.0);

        System.out.println("((5.0 + 3) * 2 - 4.0) / 3.0 = " + binding.get());
    }
}

Ausführungsergebnis


((2.0 + 3) * 2 - 4.0) / 3.0 = 2.0
((5.0 + 3) * 2 - 4.0) / 3.0 = 4.0

-Die Klasse Bindings verfügt über eine große Anzahl von Binding-Factory-Methoden. Ist gewesen

Low-Level-API

MyBinding.java


package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;

public class MyBinding extends DoubleBinding {
    private final DoubleProperty source;

    public MyBinding(DoubleProperty source) {
        this.bind(source);
        this.source = source;
    }

    @Override
    protected double computeValue() {
        return ((this.source.get() + 3) * 2 - 4.0) / 3.0;
    }
}
package sample.javafx.property;

import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty(2.0);
        
        DoubleBinding binding = new MyBinding(a);

        System.out.println("((2.0 + 3) * 2 - 4.0) / 3.0 = " + binding.get());
        
        a.set(5.0);

        System.out.println("((5.0 + 3) * 2 - 4.0) / 3.0 = " + binding.get());
    }
}

Ausführungsergebnis


((2.0 + 3) * 2 - 4.0) / 3.0 = 2.0
((5.0 + 3) * 2 - 4.0) / 3.0 = 4.0

Verknüpfen Sie eine Eigenschaft mit Bindung

package sample.javafx.property;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

public class Main {
    public static void main(String[] args) {
        DoubleProperty a = new SimpleDoubleProperty();
        DoubleProperty b = new SimpleDoubleProperty();
        
        System.out.println("a=" + a + ", b=" + b);

        a.bind(b);

        System.out.println("a=" + a + ", b=" + b);
        
        b.set(3.0);

        System.out.println("a=" + a + ", b=" + b);
        System.out.println("a=" + a.get() + ", b=" + b);
    }
}

Ausführungsergebnis


a=DoubleProperty [value: 0.0], b=DoubleProperty [value: 0.0]
a=DoubleProperty [bound, invalid], b=DoubleProperty [value: 0.0]
a=DoubleProperty [bound, invalid], b=DoubleProperty [value: 3.0]
a=3.0, b=DoubleProperty [value: 3.0]

Schreibgeschützte Eigenschaften

MyClass.java


package sample.javafx.property;

import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;

public class MyClass {
    private ReadOnlyDoubleWrapper value = new ReadOnlyDoubleWrapper();
    
    public final double getValue() {
        return this.value.getValue();
    }
    
    public final ReadOnlyDoubleProperty valueProperty() {
        return this.value.getReadOnlyProperty();
    }
    
    public void updateValue() {
        this.value.set(99.9);
    }
}

Main.java


package sample.javafx.property;

public class Main {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();

        System.out.println(myClass.valueProperty());
        
        myClass.updateValue();

        System.out.println(myClass.valueProperty());
    }
}

Ausführungsergebnis


ReadOnlyDoubleProperty [value: 0.0]
ReadOnlyDoubleProperty [value: 99.9]

Bidirektionale Bindung

javafx.jpg

package sample.javafx;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private TextField textField;
    
    private StringProperty value = new SimpleStringProperty();

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.textField.textProperty().bindBidirectional(this.value);
    }
    
    @FXML
    public void checkValue() {
        System.out.println("value=" + value.getValue());
    }
    
    @FXML
    public void resetValue() {
        this.value.set("reset!!");
    }
}

** Ausführungsergebnis **

javafx.gif

Zweiwege-Bindung für StringProperty

Die bidirektionale Bindungsmethode für "Eigenschaft " kann nur bidirektional an eine Eigenschaft desselben "Eigenschaft " - Typs gebunden werden.

Auf der anderen Seite verfügt StringProperty über die folgenden zwei Methoden für die bidirektionale Bindung. Wurde hinzugefügt.

--Formatenspezifikation

Formatspezifikation

package sample.javafx;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;

import java.net.URL;
import java.text.DecimalFormat;
import java.text.Format;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private TextField textField;
    
    private DoubleProperty value = new SimpleDoubleProperty();

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Format format = new DecimalFormat("#,##0.00");
        this.textField.textProperty().bindBidirectional(this.value, format);
    }
    
    @FXML
    public void checkValue() {
        System.out.println("value=" + value.getValue());
    }
    
    @FXML
    public void resetValue() {
        this.value.set(9876.54);
    }
}

** Ausführungsergebnis **

javafx.gif

Konverterbezeichnung

package sample.javafx;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.util.StringConverter;

import java.net.URL;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private TextField textField;
    
    private ObjectProperty<LocalDate> value = new SimpleObjectProperty<>(LocalDate.of(2017, 1, 1));

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu/MM/dd");
        
        this.textField.textProperty().bindBidirectional(this.value, new StringConverter<LocalDate>() {
            @Override
            public String toString(LocalDate date) {
                if (date == null) {
                    return "";
                }
                
                try {
                    return formatter.format(date);
                } catch (DateTimeException e) {
                    return "";
                }
            }

            @Override
            public LocalDate fromString(String text) {
                try {
                    return LocalDate.parse(text, formatter);
                } catch (DateTimeParseException e) {
                    return null;
                }
            }
        });
    }
    
    @FXML
    public void checkValue() {
        System.out.println("value=" + value.getValue());
    }
    
    @FXML
    public void resetValue() {
        this.value.set(LocalDate.of(2017, 1, 1));
    }
}

** Ausführungsergebnis **

javafx.gif

Sammlung

JavaFX bietet eine eigene Auflistungsklasse, die eine Erweiterung der Standardauflistung ("Liste" oder "Karte") darstellt.

Überwachbare Liste

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list = FXCollections.observableArrayList("fizz", "buzz");
        
        list.addListener((Change<? extends String> change) -> {
            System.out.println("Liste hat Änderung geändert=" + change);
        });
        
        list.add("foo");
        list.remove("buzz");
        FXCollections.sort(list);
    }
}

Ausführungsergebnis


Liste hat Änderung geändert={ [foo] added at 2 }
Liste hat Änderung geändert={ [buzz] removed at 1 }
Liste hat Änderung geändert={ permutated by [0, 1] }

Überprüfen Sie die Änderungen

Wenn sich die Liste ändert, wird dem Listener das Objekt Change (https://docs.oracle.com/javase/jp/8/javafx/api/javafx/collections/ListChangeListener.Change.html) übergeben.

Das Objekt "Ändern" enthält Informationen darüber, wie die Liste geändert wurde.

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list = FXCollections.observableArrayList("one", "two", "three");
        
        list.addListener((Change<? extends String> change) -> {
            System.out.println("==========================================");
            while (change.next()) {
                System.out.println("list=" + change.getList());
                if (change.wasAdded()) {
                    System.out.println("hinzufügen: " + change);
                }
                if (change.wasRemoved()) {
                    System.out.println("Löschen: " + change);
                }
                if (change.wasPermutated()) {
                    System.out.println("Bestellung ändern: " + change);
                }
                if (change.wasReplaced()) {
                    System.out.println("Ersatz: " + change);
                }
            }
        });

        list.add("FOO");
        list.remove("one");
        FXCollections.sort(list);
        list.set(1, "hoge");
    }
}

Ausführungsergebnis


==========================================
list=[one, two, three, FOO]
hinzufügen: { [FOO] added at 3 }
==========================================
list=[two, three, FOO]
Löschen: { [one] removed at 0 }
==========================================
list=[FOO, three, two]
Bestellung ändern: { permutated by [2, 1, 0] }
==========================================
list=[FOO, hoge, two]
hinzufügen: { [three] replaced by [hoge] at 1 }
Löschen: { [three] replaced by [hoge] at 1 }
Ersatz: { [three] replaced by [hoge] at 1 }

Überprüfen Sie die hinzugefügten Elemente

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list = FXCollections.observableArrayList("one", "two", "three");

        list.addListener((Change<? extends String> change) -> {
            System.out.println("==========================================");
            while (change.next()) {
                System.out.println("list=" + change.getList());
                System.out.println("added=" + change.wasAdded());
                System.out.println("from=" + change.getFrom());
                System.out.println("to=" + change.getTo());
                System.out.println("addedSubList=" + change.getAddedSubList());
                System.out.println("addedSize=" + change.getAddedSize());
            }
        });

        list.add("FOO");
        list.addAll(Arrays.asList("hoge", "fuga"));
    }
}

Ausführungsergebnis


==========================================
list=[one, two, three, FOO]
added=true
from=3
to=4
addedSubList=[FOO]
addedSize=1
==========================================
list=[one, two, three, FOO, hoge, fuga]
added=true
from=4
to=6
addedSubList=[hoge, fuga]
addedSize=2

Suchen Sie nach gelöschten Elementen

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list
            = FXCollections.observableArrayList(
                    "one", "two", "three", "four", "five", "six", "seven");
        
        list.addListener((Change<? extends String> change) -> {
            System.out.println("==========================================");
            System.out.println("list=" + change.getList());
            while (change.next()) {
                System.out.println("----------------------------------");
                System.out.println("removed=" + change.wasRemoved());
                System.out.println("from=" + change.getFrom());
                System.out.println("to=" + change.getTo());
                System.out.println("removed=" + change.getRemoved());
                System.out.println("removedSize=" + change.getRemovedSize());
            }
        });

        list.remove("three");
        list.removeAll("two", "seven");
        list.retainAll("one", "six");
    }
}

Ausführungsergebnis


==========================================
list=[one, two, four, five, six, seven]
----------------------------------
removed=true
from=2
to=2
removed=[three]
removedSize=1
==========================================
list=[one, four, five, six]
----------------------------------
removed=true
from=1
to=1
removed=[two]
removedSize=1
----------------------------------
removed=true
from=4
to=4
removed=[seven]
removedSize=1
==========================================
list=[one, six]
----------------------------------
removed=true
from=1
to=1
removed=[four, five]
removedSize=2

--wasRemoved () gibt true zurück, wenn das Element entfernt wird

Überprüfen Sie die Sortierreihenfolge auf Änderungen

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list
            = FXCollections.observableArrayList("aaa", "ccc", "bbb", "eee", "ddd", "fff");
        
        list.addListener((Change<? extends String> change) -> {
            System.out.println("==========================================");
            System.out.println("new list=" + change.getList());
            while (change.next()) {
                System.out.println("permutated=" + change.wasPermutated());
                for (int oldIndex=change.getFrom(); oldIndex<change.getTo(); oldIndex++) {
                    int newIndex = change.getPermutation(oldIndex);
                    System.out.println("old(" + oldIndex + ") -> new(" + newIndex + ")");
                }
            }
        });

        System.out.println("old list=" + list);
        list.sort(String::compareTo);
    }
}

Ausführungsergebnis


old list=[aaa, ccc, bbb, eee, ddd, fff]
==========================================
new list=[aaa, bbb, ccc, ddd, eee, fff]
permutated=true
old(0) -> new(0)
old(1) -> new(2)
old(2) -> new(1)
old(3) -> new(4)
old(4) -> new(3)
old(5) -> new(5)

--wasPermutated () gibt true zurück, wenn die Liste neu angeordnet wird

Überprüfen Sie das ausgetauschte Element

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list = FXCollections.observableArrayList("one", "two", "three");

        list.addListener((Change<? extends String> change) -> {
            System.out.println("==========================================");
            while (change.next()) {
                System.out.println("list=" + change.getList());
                
                System.out.println("replaced=" + change.wasReplaced());
                System.out.println("added=" + change.wasAdded());
                System.out.println("removed=" + change.wasRemoved());
                
                System.out.println("from=" + change.getFrom());
                System.out.println("to=" + change.getTo());
                System.out.println("addedSubList=" + change.getAddedSubList());
                System.out.println("addedSize=" + change.getAddedSize());
                System.out.println("removed=" + change.getRemoved());
                System.out.println("removedSize=" + change.getRemovedSize());
            }
        });

        list.set(1, "FOO");
    }
}

Ausführungsergebnis


==========================================
list=[one, FOO, three]
replaced=true
added=true
removed=true
from=1
to=2
addedSubList=[FOO]
addedSize=1
removed=[two]
removedSize=1

--wasReplaced () gibt true zurück, wenn ein Element durch ein anderes Element ersetzt wird

Sortierte Liste

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;

import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list = FXCollections.observableArrayList("one", "two", "three");
        SortedList<String> sortedList = list.sorted();

        System.out.println("list=" + list);
        System.out.println("sortedList=" + sortedList);

        list.addAll("four", "five", "six");

        System.out.println("list=" + list);
        System.out.println("sortedList=" + sortedList);
        
        sortedList.setComparator(Comparator.reverseOrder());

        System.out.println("list=" + list);
        System.out.println("sortedList=" + sortedList);
    }
}

Ausführungsergebnis


list=[one, two, three]
sortedList=[one, three, two]

list=[one, two, three, four, five, six]
sortedList=[five, four, one, six, three, two]

list=[one, two, three, four, five, six]
sortedList=[two, three, six, one, four, five]

Gefilterte Liste

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;

public class Main {
    public static void main(String[] args) {
        ObservableList<String> list = FXCollections.observableArrayList("one", "two", "three");
        FilteredList<String> filteredList = list.filtered(e -> e.contains("e"));

        System.out.println("list=" + list);
        System.out.println("filteredList=" + filteredList);
        
        list.addAll("four", "five");

        System.out.println("list=" + list);
        System.out.println("filteredList=" + filteredList);

        filteredList.setPredicate(e -> e.contains("f"));

        System.out.println("list=" + list);
        System.out.println("filteredList=" + filteredList);
    }
}

Ausführungsergebnis


list=[one, two, three]
filteredList=[one, three]

list=[one, two, three, four, five]
filteredList=[one, three, five]

list=[one, two, three, four, five]
filteredList=[four, five]

Überwachbare Karte

package sample.javafx.property;

import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener.Change;
import javafx.collections.ObservableMap;

public class Main {
    public static void main(String[] args) {
        ObservableMap<String, String> map = FXCollections.observableHashMap();
        map.put("foo", "FOO");
        map.put("bar", "BAR");
        
        map.addListener((Change<? extends String, ? extends String> change) -> {
            System.out.println("==============================");
            System.out.println("map=" + change.getMap());
            System.out.println("key=" + change.getKey());
            System.out.println("added=" + change.wasAdded());
            System.out.println("valueAdded=" + change.getValueAdded());
            System.out.println("removed=" + change.wasRemoved());
            System.out.println("valueRemoved=" + change.getValueRemoved());
        });
        
        map.put("fizz", "FIZZ");
        map.put("bar", "BARBAR");
        map.remove("foo");
    }
}

Ausführungsergebnis


==============================
map={bar=BAR, foo=FOO, fizz=FIZZ}
key=fizz
added=true
valueAdded=FIZZ
removed=false
valueRemoved=null
==============================
map={bar=BARBAR, foo=FOO, fizz=FIZZ}
key=bar
added=true
valueAdded=BARBAR
removed=true
valueRemoved=BAR
==============================
map={bar=BARBAR, fizz=FIZZ}
key=foo
added=false
valueAdded=null
removed=true
valueRemoved=FOO

--ObservableMapwird als überwachbareMapbereitgestellt --Verwenden SieFXCollections.observableHashMap ()`, um eine Instanz zu erstellen

Stylesheet

Basic

Ordnerstruktur


`-src/main/
  |-java/sample/javafx/
  | |-Main.java
  | `-MainController.java
  |
  `-resources/
    |-main.fxml
    `-my-style.css

main.fxml

javafx.jpg

my-style.css


.label {
    -fx-background-color: skyblue;
}

Main.java


package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.net.URL;

public class Main extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = this.getClass().getResource("/main.fxml");
        FXMLLoader loader = new FXMLLoader(url);
        Parent root = loader.load();
        
        Scene scene = new Scene(root);
        scene.getStylesheets().add("my-style.css");
        primaryStage.setScene(scene);

        primaryStage.show();
    }
}

** Ausführungsergebnis **

javafx.jpg

Stylesheet wird geladen

Main.java


        Scene scene = new Scene(root);
        scene.getStylesheets().add("my-style.css");

--Stylesheet-Dateien können mithilfe von "Scene.getStylesheets ()" hinzugefügt werden, um eine Liste mit den Stylesheet-URLs zu erhalten, und anschließend "add ()".

Wie schreibe ich CSS

my-style.css


.label {
    -fx-background-color: skyblue;
}

Klassenauswahl

Die auf dem Knoten festgelegte Standard-Stilklasse

Label.java


...
public class Label extends Labeled {

    public Label() {
        initialize();
    }

...

    private void initialize() {
        getStyleClass().setAll("label");
        ...
    }

--initialzie () wird im Konstruktor aufgerufen, und die Zeichenfolge label wird an die Eigenschaft styleClass übergeben ( styleClass, die automatisch aus dem Klassennamen konvertiert wird, wird nicht festgelegt). --So hat die Label-Klasseninstanz standardmäßig eine styleClass von label, die in der CSS-Datei mit einem Selektor mit . ( angegeben wird. .label)

Immobilieneinheit

my-style.css


.my-class {
    -fx-background-color: pink;
    -fx-padding: 10px;
    
    -fx-border-color: black;
    -fx-border-width: 1px;
    -fx-border-style: solid;
    
    -fx-underline: true;
}

** Ausführungsergebnis **

javafx.jpg

Legen Sie ein beliebiges styleClass-Attribut fest

In Scene Builder einstellen

javafx.jpg

main.fxml


<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.text.Font?>

<Label fx:id="label" alignment="CENTER" prefHeight="200.0" prefWidth="300.0"
       styleClass="my-class"
       text="CSS Test" xmlns="http://javafx.com/javafx/8.0.151" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.javafx.MainController">
   <font>
      <Font size="30.0" />
   </font>
</Label>

my-style.css


.my-class {
    -fx-font-weight: bold;
    -fx-underline: true;
    -fx-text-fill: red;
}

** Ausführungsergebnis **

javafx.jpg

Aus dem Programm einstellen

MainContoller.java


package sample.javafx;

import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @FXML
    private Label label;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        ObservableList<String> styleClass = label.getStyleClass();
        styleClass.add("my-class");
        System.out.println("styleClass=" + styleClass);
    }
}

Laden Sie eine lokale Stylesheet-Datei

Ordnerstruktur


|-my-styles.css
`-src/main/java/
  `-sample/javafx/
    |-Main.java
    :

my-style.css


.my-class {
    -fx-background-color: green;
}

Main.java


package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.net.URL;

public class Main extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = this.getClass().getResource("/main.fxml");
        FXMLLoader loader = new FXMLLoader(url);
        Parent root = loader.load();
        
        Scene scene = new Scene(root);
        scene.getStylesheets().add("file:./my-style.css"); //★ Geben Sie die lokale Datei an
        primaryStage.setScene(scene);

        primaryStage.show();
    }
}

** Ausführungsergebnis **

javafx.jpg

Hintergrundbildeinstellungen

Wie man -fx-Hintergrundbild einstellt

Ordnerstruktur


|-image.jpg
`-src/main/
  |-resources/
  | |-img/
  | | `-image.jpg
  | |-my-style.css
  | `-main.fxml
  :

Geben Sie eine Datei im Klassenpfad an

my-style.css


.my-class {
    -fx-background-image: url('/img/image.jpg');
}

Geben Sie eine lokale Datei an

my-style.css


.my-class {
    -fx-background-image: url('file:./image.jpg');
}

--Wenn Sie eine lokale Datei angeben, verwenden Sie file: [path]

Ereigniserfassung, Ereignisblasen

javafx.jpg

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private Pane bluePane;
    @FXML
    private Pane yellowPane;
    @FXML
    private Button button;
    @FXML
    private TextField textField;
    @FXML
    private Label label;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.registerHandlers(this.bluePane, "bluePane");
        this.registerHandlers(this.yellowPane, "yellowPane");
        this.registerHandlers(this.button, "button");
        this.registerHandlers(this.textField, "textField");
        this.registerHandlers(this.label, "label");
    }
    
    private void registerHandlers(Node node, String name) {
        this.registerEventFilter(node, name);
        this.registerEventHandler(node, name);
    }

    private void registerEventFilter(Node node, String name) {
        node.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> System.out.println("filter " + name));
    }

    private void registerEventHandler(Node node, String name) {
        node.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("handler " + name));
    }
}

** Ausführungsergebnis **

javafx.jpg

Klicken Sie auf den blauen Bereich


filter bluePane
handler bluePane

Klicken Sie auf den gelben Bereich


filter bluePane
filter yellowPane
handler yellowPane
handler bluePane

Drück den Knopf


filter bluePane
filter yellowPane
filter button
handler button

Klicken Sie auf das Textfeld


filter bluePane
filter yellowPane
filter textField
handler textField

Klicken Sie auf das Etikett


filter bluePane
filter yellowPane
filter label
handler label
handler yellowPane
handler bluePane

Erläuterung

Wenn ein Ereignis eintritt, wird die Verarbeitung in der folgenden Reihenfolge ausgeführt

  1. Zielauswahl
  2. Bestimmung der Route [^ 2]
  3. Ereigniserfassungsphase
  4. Ereignisblasenphase

[^ 2]: Im offiziellen japanischen Dokument wird es als "root" beschrieben, aber es wird als "route" geschrieben, weil es mit "root" verwechselt zu werden scheint.

Zielauswahl

Routenbestimmung

javafx.jpg

Ereigniserfassungsphase

Klicken Sie auf das Textfeld


filter bluePane
filter yellowPane
filter textField
...

MainController.java


    private void registerEventFilter(Node node, String name) {
        node.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> System.out.println("filter " + name));
    }

Ereignisblasenphase

Klicken Sie auf das Etikett


...
handler label
handler yellowPane
handler bluePane

MainController.java


    private void registerEventHandler(Node node, String name) {
        node.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("handler " + name));
    }

--Event-Handler können mit addEventHandler (EventType, EventHandler ) registriert werden

Verbrauchen Sie die Veranstaltung

MainController.java


package sample.javafx;

...

public class MainController implements Initializable {
    ...

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.registerHandlers(this.bluePane, "bluePane");
        
        this.registerEventFilter(this.yellowPane, "yellowPane");
        this.yellowPane.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> {
            System.out.println("handler yellowPane");
            e.consume();
        });
        
        this.registerHandlers(this.button, "button");
        this.registerHandlers(this.textField, "textField");
        this.registerHandlers(this.label, "label");
    }
    
    ...
}

** Ausführungsergebnis **

Klicken Sie auf den gelben Bereich


filter bluePane
filter yellowPane
filter label
handler label
handler yellowPane

Einige UI-Steuerelemente unterbrechen das Sprudeln von Ereignissen

Drück den Knopf


filter bluePane
filter yellowPane
filter button
handler button

Klicken Sie auf das Textfeld


filter bluePane
filter yellowPane
filter textField
handler textField

Klicken Sie auf das Etikett


filter bluePane
filter yellowPane
filter label
handler label
handler yellowPane
handler bluePane

--Label führt ein normales Ereignisblasen durch, aber Button und TextField werden unterbrochen.

Derzeit heißt es im offiziellen Dokument wie folgt.

Standardhandler für JavaFX-UI-Steuerelemente verwenden im Allgemeinen die meisten Eingabeereignisse.

1 Ereignisverarbeitung (Release 8) | JavaFX: Ereignisverarbeitung

Ich bin mir jedoch nicht sicher, wo genau überprüft werden soll, welche Klasse das Ereignis verwendet.

Drag & Drop

fallen

Basic

javafx.jpg

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;

public class MainController {
    
    @FXML
    public void onDragOver(DragEvent e) {
        e.acceptTransferModes(TransferMode.ANY);
        e.consume();
    }
    
    @FXML
    public void onDragDropped(DragEvent e) {
        Dragboard dragboard = e.getDragboard();
        String string = dragboard.getString();
        System.out.println("dropped string = " + string);
        e.consume();
    }
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

Tropfen annehmen

MainController.java


    @FXML
    public void onDragOver(DragEvent e) {
        e.acceptTransferModes(TransferMode.ANY);
        e.consume();
    }

Verarbeitung zum Zeitpunkt des Abwurfs

MainController.java


    @FXML
    public void onDragDropped(DragEvent e) {
        Dragboard dragboard = e.getDragboard();
        String string = dragboard.getString();
        System.out.println("dropped string = " + string);
        e.consume();
    }

--Für die Drop-Verarbeitung registrieren Sie einen Handler im Ereignis "DRAG_DROPPED" des Zielknotens.

Datei löschen

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;

import java.io.File;
import java.util.List;

public class MainController {
    
    @FXML
    public void onDragOver(DragEvent e) {
        Dragboard dragboard = e.getDragboard();
        
        if (dragboard.hasFiles()) {
            e.acceptTransferModes(TransferMode.ANY);
        }

        e.consume();
    }
    
    @FXML
    public void onDragDropped(DragEvent e) {
        System.out.println("onDragDropped()");
        Dragboard dragboard = e.getDragboard();

        List<File> files = dragboard.getFiles();
        files.forEach(file -> System.out.println(file.getName()));

        e.consume();
    }
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

MainController.java


    @FXML
    public void onDragOver(DragEvent e) {
        Dragboard dragboard = e.getDragboard();
        
        if (dragboard.hasFiles()) {
            e.acceptTransferModes(TransferMode.ANY);
        }

        e.consume();
    }

MainController.java


    @FXML
    public void onDragDropped(DragEvent e) {
        System.out.println("onDragDropped()");
        Dragboard dragboard = e.getDragboard();

        List<File> files = dragboard.getFiles();
        files.forEach(file -> System.out.println(file.getName()));

        e.consume();
    }

HTML-Drop

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;

public class MainController {
    
    @FXML
    public void onDragOver(DragEvent e) {
        Dragboard dragboard = e.getDragboard();
        
        if (dragboard.hasHtml()) {
            e.acceptTransferModes(TransferMode.ANY);
        }

        e.consume();
    }
    
    @FXML
    public void onDragDropped(DragEvent e) {
        System.out.println("onDragDropped()");
        Dragboard dragboard = e.getDragboard();

        System.out.println("[html]   = " + dragboard.getHtml());
        System.out.println("[string] = " + dragboard.getString());
        System.out.println("[files]  = " + dragboard.getFiles());

        e.consume();
    }
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

MainController.java


    @FXML
    public void onDragDropped(DragEvent e) {
        System.out.println("onDragDropped()");
        Dragboard dragboard = e.getDragboard();

        System.out.println("[html]   = " + dragboard.getHtml());
        System.out.println("[string] = " + dragboard.getString());
        System.out.println("[files]  = " + dragboard.getFiles());

        e.consume();
    }

Ändern Sie den Stil beim Ablegen

my-style.css


.drag-over {
    -fx-text-fill: red;
}

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;

public class MainController {
    
    @FXML
    private Label dropLabel;
    
    @FXML
    public void onDragEntered() {
        this.dropLabel.getStyleClass().add("drag-over");
    }
    
    @FXML
    public void onDragExited() {
        this.dropLabel.getStyleClass().remove("drag-over");
    }
    
    ...
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

ziehen

javafx.jpg

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;

public class MainController {
    
    @FXML
    private Label dragLabel;
    
    @FXML
    public void onDragDetected(MouseEvent e) {
        Dragboard dragboard = this.dragLabel.startDragAndDrop(TransferMode.ANY);
        
        ClipboardContent content = new ClipboardContent();
        content.putString("Drag Test");
        dragboard.setContent(content);

        e.consume();
    }
    
    @FXML
    public void onDragOver(DragEvent e) {
        e.acceptTransferModes(TransferMode.ANY);
        e.consume();
    }
    
    @FXML
    public void onDragDropped(DragEvent e) {
        System.out.println("onDragDropped()");
        Dragboard dragboard = e.getDragboard();
        System.out.println(dragboard.getString());
        
        e.consume();
    }
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

MainController.java


    @FXML
    private Label dragLabel;
    
    @FXML
    public void onDragDetected(MouseEvent e) {
        Dragboard dragboard = this.dragLabel.startDragAndDrop(TransferMode.ANY);
        
        ClipboardContent content = new ClipboardContent();
        content.putString("Drag Test");
        dragboard.setContent(content);

        e.consume();
    }

--Drag wird gestartet, indem ein Handler im Ereignis DRAG_DETECTED registriert wird.

Referenz

Dialog

Vorbereitung

javafx.jpg

package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.Alert;

public class MainController {
    
    @FXML
    public void showDialog() {
        ...
    }
}

Stellen Sie sicher, dass die Methode showDialog () aufgerufen wird, wenn Sie auf die Schaltfläche klicken.

Basic

Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.showAndWait();

** Ausführungsergebnis **

javafx.jpg

Bestätigen Sie die ausgewählte Schaltfläche

Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
Optional<ButtonType> buttonType = alert.showAndWait();
buttonType.ifPresent(System.out::println);

** Ausführungsergebnis **

Klicken Sie auf die Schaltflächen "OK" und "Abbrechen".

ButtonType [text=OK, buttonData=OK_DONE]
ButtonType [text=stornieren, buttonData=CANCEL_CLOSE]

[^ 1]: ButtonData ist NO oder CANCEL_CLOSE

Stellen Sie eine Nachricht ein

Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Messeji");
alert.showAndWait();

javafx.jpg

Dialogtyp

INFORMATION

javafx.jpg

CONFIRMATION

javafx.jpg

WARNING

javafx.jpg

ERROR

javafx.jpg

Geben Sie die Schaltfläche an

Alert alert = new Alert(
        Alert.AlertType.INFORMATION, 
        "Messeji",
        ButtonType.APPLY,
        ButtonType.CANCEL,
        ButtonType.CLOSE,
        ButtonType.FINISH,
        ButtonType.NEXT,
        ButtonType.NO,
        ButtonType.OK,
        ButtonType.PREVIOUS,
        ButtonType.YES);
alert.showAndWait();

javafx.jpg

--ButtonType kann nach dem dritten Argument des Konstruktors angegeben werden

Reihenfolge der Tastenplatzierung

** ButtonData ** auf eine ButtonType-Konstante gesetzt

ButtonType ButtonData, die eingestellt ist
APPLY APPLY
CANCEL CANCEL_CLOSE
CLOSE CANCEL_CLOSE
FINISH FINISH
NEXT NEXT_FORWARD
NO NO
OK OK_DONE
PREVIOUS BACK_PREVIOUS
YES YES

** Anordnung der Reihenfolge von "ButtonData" nach Betriebssystem **

OS Platzierungsauftrag
Windows L_E+U+FBXI_YNOCAH_R
Mac OS L_HE+U+FBIX_NCYOA_R
Linux L_HE+UNYACBXIO_R

--Diese mysteriöse Zeichenfolge entspricht dem ** Tastensequenzcode **, bei dem jedes Zeichen der Konstante ButtonData zugewiesen ist.

javafx.jpg

Platziere einen beliebigen Knopf

ButtonType myButton = new ButtonType("Taste");
Alert alert = new Alert(Alert.AlertType.INFORMATION, "Messeji", myButton);
alert.showAndWait().ifPresent(System.out::println);

** Ausführungsergebnis **

javafx.jpg

Konsolenausgabe, wenn auf die Schaltfläche "Botan" geklickt wird


ButtonType [text=Taste, buttonData=OTHER]

Beurteilung, wenn durch einen anderen als den Knopf geschlossen

--Der Dialog kann auch mit "ESC", "Alt + F4", der Schaltfläche zum Schließen des Fensters usw. geschlossen werden (für Windows).

Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Messeji", ButtonType.YES);
Optional<ButtonType> buttonType = alert.showAndWait();
String result = buttonType.map(ButtonType::getText).orElse("Keine Auswahl");
System.out.println(result);

** Ausführungsergebnis **

javafx.jpg

Ergebnis beim Schließen mit "ESC"

Keine Auswahl

--Nächste, wenn mehrere Abbrechen-Schaltflächen vorhanden sind

Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Messeji", ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
Optional<ButtonType> buttonType = alert.showAndWait();
String result = buttonType.map(ButtonType::getText).orElse("Keine Auswahl");
System.out.println(result);

** Ausführungsergebnis **

javafx.jpg

1 Tasse" 2. "Nein" 3. "Abbrechen" 4. ESC 5. Alt + F4 6. Schließen Sie das Fenster

Versuchen Sie, den Dialog in der Reihenfolge von zu schließen.

Ja
Nein
stornieren
stornieren
stornieren
stornieren

--Wenn jede Taste gedrückt wird, ist diese Taste der Rückgabewert von showAndWait () --Wenn der Dialog mit einer anderen Methode als der Schaltfläche geschlossen wird, bedeutet dies, dass die Schaltfläche "Abbrechen" gedrückt wurde.

  1. ButtonData ist CANCEL_CLOSE`` ButtonType
  2. ButtonData.isCancelButton () gibt true ButtonType zurück Dies liegt daran, dass der Rückgabewert in der Reihenfolge der Priorität von - bestimmt wird.

Um den Rückgabewert von "showAndWait ()" zusammenzufassen, wenn der Dialog durch eine andere Methode als eine Schaltfläche geschlossen wird,

  1. Wenn keine Abbrechen-Schaltfläche [^ 1] vorhanden ist, wählen Sie "Optional.empty ()"
  2. Wenn es eine Abbrechen-Schaltfläche gibt, diese ButtonType
  3. Wenn zwei oder mehr Abbrechen-Schaltflächen vorhanden sind, wird der Rückgabewert "ButtonType" in der folgenden Prioritätsreihenfolge festgelegt.
  4. ButtonType wobei ButtonData`` CANCEL_CLOSE ist
  5. ButtonData.isCancelButton () gibt true ButtonType zurück

Verschiedene Texteinstellungen

Mit dem Konstruktorargument können Sie nur "contentText" festlegen, aber Sie können den Titel usw. ändern, nachdem Sie "Alert" generiert haben.

Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Nimm es");
alert.setHeaderText("Überschrift");
alert.setContentText("Wenn du hier her kommst");
alert.showAndWait();

javafx.jpg

Jedes kann auch durch Setzen von "null" ausgeschaltet werden.

Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle(null);
alert.setHeaderText(null);
alert.setContentText("Wenn du hier her kommst");
alert.showAndWait();

javafx.jpg

Faden

Die grundlegende Geschichte bei der Verwendung von Threads mit JavaFX

UI-Thread

Die JavaFX-GUI-Verarbeitung wird auf einem dedizierten Thread (** UI-Thread **) ausgeführt, der als "JavaFX-Anwendungsthread" bezeichnet wird.

MainController.java


package sample.javafx;

import javafx.fxml.Initializable;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        System.out.println("thread = " + Thread.currentThread().getName());
    }
}

Ausführungsergebnis


thread = JavaFX Application Thread

Bei normaler Implementierung wird der Prozess auf diesem UI-Thread ausgeführt.

Wenn jedoch eine zeitaufwändige Verarbeitung für diesen UI-Thread ausgeführt wird, wird auf Ereignisverarbeitung wie UI-Aktualisierung und Mausbetrieb gewartet. Dann kann die Anwendung den Vorgang eines Benutzers nicht akzeptieren, und das Erscheinungsbild ändert sich nicht, dh ein sogenannter Festkörper.

Um dies zu vermeiden, muss der zeitaufwändige Prozess in einem vom UI-Thread getrennten Thread ausgeführt werden.

Berühren Sie die Benutzeroberfläche eines Nicht-Benutzeroberflächenthreads

Auf JavaFX-UI-Komponenten kann nur über UI-Threads zugegriffen werden. Ausnahmen werden jetzt ausgelöst, wenn versucht wird, von außerhalb des UI-Threads auf eine UI-Komponente zuzugreifen.

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.Button;

public class MainController {

    @FXML
    private Button button;
    
    @FXML
    public void click() {
        new Thread(() -> {
            System.out.println("thread = " + Thread.currentThread().getName());
            button.setText("hoge");
        }).start();
    }
}

Ausführungsergebnis


thread = Thread-4
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
	at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
	at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
	at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
        ...

Solche Einschränkungen bestehen häufig nicht nur in JavaFX, sondern auch in anderen GUI-bezogenen Frameworks wie Swing.

Die GUI scheint sehr schwierig zu sein, um Thread-sicher zu sein, wenn Multithreading ausgeführt wird. Aus diesem Grund haben die meisten GUI-Frameworks einen dedizierten Thread für UI-Operationen, und auf die UI kann nur von diesem dedizierten Thread aus zugegriffen werden (die Suche nach "GUI, einzelner Thread" enthüllt viele Geschichten darüber. Kommen Sie).

In JavaFX ist Platform.runLater () ein Mittel zum Bedienen von UI-Komponenten von einem anderen als dem UI-Thread. Es gibt eine Methode namens .html # runLater-java.lang.Runnable-).

MainController.java


package sample.javafx;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Button;

public class MainController {

    @FXML
    private Button button;
    
    @FXML
    public void click() {
        new Thread(() -> {
            System.out.println("thread = " + Thread.currentThread().getName());
            
            Platform.runLater(() -> {
                System.out.println("runLater thread = " + Thread.currentThread().getName());
                button.setText("hoge");
            });
        }).start();
    }
}

Ausführungsergebnis


thread = Thread-4
runLater thread = JavaFX Application Thread

Der an "runLater ()" übergebene Lambda-Ausdruck (Typ "Runnable") wird jetzt auf dem UI-Thread ("JavaFx Application Thread") ausgeführt. Daher können Sie den UI-Thread von dem an diesen "runLater ()" übergebenen Prozess sicher berühren.

Einfacher Umgang mit Threads mit JavaFX

JavaFX bietet einen Mechanismus, der die Implementierung der Thread-Verarbeitung vereinfacht.

Worker Die in JavaFX verwendete Thread-Verarbeitung wird als [Worker] abstrahiert (https://docs.oracle.com/javase/jp/8/javafx/api/javafx/concurrent/Worker.html).

Worker definiert eine praktische API, die im regulären Thread nicht zu finden ist. (Dies ist eine Schnittstelle für sich und die spezifische Implementierung ist Task oder Service. (Dies wird realisiert durch: //docs.oracle.com/javase/jp/8/javafx/api/javafx/concurrent/Service.html)

Lebenszyklus der Arbeitnehmer

Arbeiter haben einen Lebenszyklus und der Zustand geht wie folgt über.

javafx.png

READY

SCHEDULED

RUNNING

SUCCEEDED

FAILED

--Dieser Status tritt auf, wenn während der Ausführung eine Ausnahme ausgelöst wird

CANCELLED

Worker hat [stateProperty ()](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/concurrent/Worker.html#", um Informationen zu diesen Zuständen zu erhalten. Eigenschaften wie stateProperty--) und runningProperty () sind verfügbar. ..

Task Eine Klasse mit dem Namen Task wird als Klasse vorbereitet, die "Worker" implementiert.

package sample.javafx;

import javafx.concurrent.Task;
import javafx.fxml.Initializable;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Runnable task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                System.out.println("task.call()");
                System.out.println("thread = " + Thread.currentThread().getName());
                return null;
            }
        };

        new Thread(task).start();
    }
}

Ausführungsergebnis


task.call()
thread = Thread-4

Stornieren

package sample.javafx;

import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    private Worker worker;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                System.out.println("start...");
                final long max = 10000000000000L;
                
                for (long i=0; i<max; i++) {
                    if (this.isCancelled()) {
                        System.out.println("cancelled!!");
                        return null;
                    }
                }

                System.out.println("finished");
                return null;
            }
        };
        
        this.worker = task;
        new Thread(task).start();
    }
    
    @FXML
    public void stop() {
        this.worker.cancel();
    }
}

Die Aufgabe wird mit "initialize ()" gestartet, und die im Ereignishandler der Schaltfläche registrierte Methode "stop ()" ruft die Methode "cancel ()" von "Worker" auf.

Ausführungsergebnis


start...
cancelled!!

Fortschritt

javafx.jpg

package sample.javafx;

import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ProgressBar;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private ProgressBar progressBar;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                final long max = 100000000L;
                
                for (long i=0; i<=max; i++) {
                    this.updateProgress(i, max);
                }
                
                return null;
            }
        };
        
        this.progressBar.progressProperty().bind(task.progressProperty());
        new Thread(task).start();
    }
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

        this.progressBar.progressProperty().bind(task.progressProperty());

--Worker macht eine Eigenschaft namensprogressProperty ()verfügbar

                for (long i=0; i<=max; i++) {
                    this.updateProgress(i, max);
                }

--Verwenden Sie die Methode "updateProgress ()", um den Fortschritt von "Task" zu aktualisieren

Veröffentlichen Sie beliebige Werte

javafx.jpg

package sample.javafx;

import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.Label;

import java.io.IOException;

public class MainController {

    @FXML
    private Label label;

    @FXML
    public void start() throws IOException {
        MyTask task = new MyTask();
        this.label.textProperty().bind(task.valueProperty());
        
        new Thread(task).start();
    }
    
    private static class MyTask extends Task<String> {

        @Override
        protected String call() throws Exception {
            for (int i=0; i<100000000; i++) {
                this.updateValue("i=" + i);
            }
            
            return "finished!!";
        }
    }
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

    private static class MyTask extends Task<String> {

        @Override
        protected String call() throws Exception {
            for (int i=0; i<100000000; i++) {
                this.updateValue("i=" + i);
            }
            
            return "finished!!";
        }
    }

--Task hat eine Eigenschaft namens value

Ereignis-Listener

package sample.javafx;

import javafx.concurrent.Task;
import javafx.fxml.FXML;

import java.io.IOException;

public class MainController {

    @FXML
    public void start() throws IOException {
        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                return null;
            }
        };
        
        task.setOnScheduled(event -> System.out.println("scheduled thread=" + Thread.currentThread().getName()));
        task.setOnRunning(event -> System.out.println("running thread=" + Thread.currentThread().getName()));
        task.setOnSucceeded(event -> System.out.println("succeeded thread=" + Thread.currentThread().getName()));
        
        new Thread(task).start();
    }
}

** Ausführungsergebnis **

scheduled thread=JavaFX Application Thread
running thread=JavaFX Application Thread
succeeded thread=JavaFX Application Thread

Ausnahmeeigenschaft

package sample.javafx;

import javafx.concurrent.Task;
import javafx.fxml.FXML;

import java.io.IOException;

public class MainController {

    @FXML
    public void start() throws IOException {
        Task<Void> task = new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                throw new RuntimeException("test");
            }
        };
        
        task.setOnFailed(event -> {
            Throwable exception = task.getException();
            System.out.println("exception=" + exception);
        });
        
        new Thread(task).start();
    }
}

Ausführungsergebnis


exception=java.lang.RuntimeException: test

Veröffentlichen Sie ObservableList

package sample.javafx;

import javafx.application.Platform;
import javafx.beans.property.ReadOnlyListProperty;
import javafx.beans.property.ReadOnlyListWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.Label;

import java.util.concurrent.TimeUnit;

public class MainController {
    
    @FXML
    private Label label;
    
    @FXML
    public void start() {
        MyTask myTask = new MyTask();
        this.label.textProperty().bind(myTask.listProperty().asString());

        Thread thread = new Thread(myTask);
        thread.setDaemon(true);
        thread.start();
    }
    
    private static class MyTask extends Task<Void> {
        private ReadOnlyListWrapper<String> list = new ReadOnlyListWrapper<>(FXCollections.observableArrayList());

        public final ObservableList<String> getList() {
            return list.get();
        }

        public ReadOnlyListProperty<String> listProperty() {
            return list.getReadOnlyProperty();
        }

        @Override
        protected Void call() throws Exception {
            for (int i=0; i<10; i++) {
                String value = String.valueOf(i);
                Platform.runLater(() -> this.list.add(value));
                
                TimeUnit.SECONDS.sleep(1);
            }
            return null;
        }
    }
}

Service

package sample.javafx;

import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;

import java.io.IOException;

public class MainController {

    private Service<Void> service = new Service<Void>() {
        @Override
        protected Task<Void> createTask() {
            System.out.println("Service.createTask()");
            
            return new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    System.out.println("Task.call()");
                    return null;
                }
            };
        }
    };
    
    @FXML
    public void start() throws IOException {
        if (!this.service.getState().equals(Worker.State.READY)) {
            System.out.println("reset");
            this.service.reset();
        }
        System.out.println("start");
        this.service.start();
    }
}

Weisen Sie dem Aktionsereignis der Schaltfläche die Methode start () zu und führen Sie sie mehrmals aus.

Ausführungsergebnis


start
Service.createTask()
Task.call()

reset
start
Service.createTask()
Task.call()

reset
start
Service.createTask()
Task.call()

--Task soll wegwerfbar sein und nicht dazu verwendet werden, dieselbe Instanz erneut zu verwenden.

Erneut ausführen

Bei der Überprüfung des Status und erneuter Ausführung


    @FXML
    public void start() throws IOException {
        if (!this.service.getState().equals(Worker.State.READY)) {
            System.out.println("reset");
            this.service.reset();
        }
        System.out.println("start");
        this.service.start();
    }

restart()Beim Umschreiben mit


    @FXML
    public void start() throws IOException {
        System.out.println("restart");
        this.service.restart();
    }

Geben Sie den zu verwendenden Thread an

Überprüfen Sie zunächst die Standardoperation.

package sample.javafx;

import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.fxml.FXML;

import java.io.IOException;

public class MainController {

    private Service<Void> service = new Service<Void>() {
        @Override
        protected Task<Void> createTask() {
            return new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    Thread thread = Thread.currentThread();
                    System.out.println("thread.name = " + thread.getName() + ", daemon = " + thread.isDaemon());
                    return null;
                }
            };
        }
    };
    
    @FXML
    public void start() throws IOException {
        this.service.restart();
    }
}

Führen Sie restart () mehrmals aus

Ausführungsergebnis


thread.name = Thread-4, daemon = true
thread.name = Thread-5, daemon = true
thread.name = Thread-6, daemon = true
thread.name = Thread-7, daemon = true

Geben Sie den vom Dienst verwendeten Thread an


package sample.javafx;

import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.fxml.FXML;

import java.io.IOException;
import java.util.concurrent.Executors;

public class MainController {

    private Service<Void> service = new Service<Void>() {
        {
            this.setExecutor(Executors.newFixedThreadPool(3));
        }
        
        @Override
        protected Task<Void> createTask() {
            return new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    Thread thread = Thread.currentThread();
                    System.out.println("thread.name = " + thread.getName() + ", daemon = " + thread.isDaemon());
                    return null;
                }
            };
        }
    };
    
    @FXML
    public void start() throws IOException {
        this.service.restart();
    }
}

Ausführungsergebnis


thread.name = pool-2-thread-1, daemon = false
thread.name = pool-2-thread-2, daemon = false
thread.name = pool-2-thread-3, daemon = false
thread.name = pool-2-thread-1, daemon = false
thread.name = pool-2-thread-2, daemon = false

Verschiedene Eigenschaften

package sample.javafx;

import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.ProgressBar;

import java.io.IOException;

public class MainController {
    @FXML
    private ProgressBar progressBar;

    private Service<Void> service = new Service<Void>() {
        
        @Override
        protected Task<Void> createTask() {
            return new Task<Void>() {
                @Override
                protected Void call() throws Exception {
                    int max = 10000000;
                    for (int i=0; i<max; i++) {
                        this.updateProgress(i, max);
                    }
                    
                    return null;
                }
            };
        }
    };
    
    @FXML
    public void start() throws IOException {
        this.service.restart();
        this.progressBar.progressProperty().bind(this.service.progressProperty());
    }
}

--Service implementiert Worker, bietet also Eigenschaften wie progress wie Task.

Referenz

Visuelle Effekte

So wenden Sie visuelle Effekte wie Beleuchtung und Schlagschatten an.

Als Mechanismus scheint es, dass das Szenendiagramm einmal als Pixelbild gerendert wurde und eine Bildverarbeitung durchgeführt wird, um Schatten zu werfen oder Licht darauf zu werfen.

Versuchen Sie, verschiedene visuelle Effekte auf die folgenden Szenendiagramme anzuwenden, und sehen Sie, was passiert.

javafx.jpg

Blüteeffekt

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.effect.Bloom;
import javafx.scene.layout.Pane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Pane pane;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Bloom bloom = new Bloom();
        this.pane.setEffect(bloom);
    }
}

Unschärfeeffekt

Box Unschärfe

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.effect.BoxBlur;
import javafx.scene.layout.Pane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Pane pane;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        BoxBlur boxBlur = new BoxBlur();
        boxBlur.setWidth(5);
        boxBlur.setHeight(5);
        
        this.pane.setEffect(boxBlur);
    }
}

Bewegungsunschärfe

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.effect.MotionBlur;
import javafx.scene.layout.Pane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Pane pane;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        MotionBlur motionBlur = new MotionBlur();
        motionBlur.setAngle(45.0);
        motionBlur.setRadius(40.0);
        
        this.pane.setEffect(motionBlur);
    }
}

Gaußsche Unschärfe

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.layout.Pane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Pane pane;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        GaussianBlur gaussianBlur = new GaussianBlur();
        gaussianBlur.setRadius(10.0);
        
        this.pane.setEffect(gaussianBlur);
    }
}

Schlagschatteneffekt

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Pane pane;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        DropShadow dropShadow = new DropShadow();
        dropShadow.setOffsetX(5.0);
        dropShadow.setOffsetY(5.0);
        dropShadow.setWidth(20.0);
        dropShadow.setHeight(20.0);
        dropShadow.setColor(Color.valueOf("CACA00"));

        this.pane.setEffect(dropShadow);
    }
}

Innerer Schatteneffekt

Nehmen Sie einige Änderungen am Szenendiagramm vor, um die Anzeige zu erleichtern.

javafx.jpg

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.effect.InnerShadow;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Pane pane;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        InnerShadow innerShadow = new InnerShadow();
        innerShadow.setOffsetX(7.0);
        innerShadow.setOffsetY(7.0);
        innerShadow.setColor(Color.valueOf("500"));
        innerShadow.setRadius(10.0);
        
        this.pane.setEffect(innerShadow);
    }
}

-Wenn Sie [InnerShadow] verwenden (https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/effect/InnerShadow.html), können Sie den inneren Schatten (Schatten, der innen wie eine Mulde aussieht) verwenden. ) Effekt kann angewendet werden

Betrachtung

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.effect.Reflection;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Label label;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Reflection reflection = new Reflection();
        reflection.setTopOffset(-25.0);
        reflection.setTopOpacity(0.8);
        reflection.setFraction(0.8);

        this.label.setEffect(reflection);
    }
}

-Wenn Sie [Reflection] verwenden (https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/effect/Reflection.html), scheint das Objekt auf dem Boden reflektiert zu werden. ) Effekt kann angewendet werden

Kombinieren Sie visuelle Effekte

** Ausführungsergebnis **

javafx.jpg

Implementierung

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Reflection;
import javafx.scene.paint.Color;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    
    @FXML
    private Label label;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Reflection reflection = new Reflection();
        reflection.setTopOffset(-40.0);
        reflection.setTopOpacity(0.8);
        reflection.setFraction(0.8);

        DropShadow dropShadow = new DropShadow();
        dropShadow.setOffsetX(5.0);
        dropShadow.setOffsetY(5.0);
        dropShadow.setColor(Color.valueOf("AA0"));

        reflection.setInput(dropShadow);

        this.label.setEffect(reflection);
    }
}

--Mehrere "Effekte" können kombiniert werden, indem ein anderer "Effekt" mit "setInput ()" angegeben wird.

Referenz

Medien

So funktionieren Mediendateien

Codec-Code

――Wenn die Mediendaten unverändert bleiben, sind selbst einige Minuten Inhalt groß, z. B. Hunderte von MB oder GB.

Container

Von JavaFX unterstützte Codierungsformate und -container

Format codieren

Format codieren Stimme/Video
PCM Stimme
MP3 Stimme
AAC Stimme
H.264/AVC Video
VP6 Video

PCM

** MP3 (codiertes Format) **

--MPEG-1 Abkürzung für Audio Layer-3 --Audio-Codierungsformat, das im MPEG-1-Videocontainer verwendet wird

AAC

H.264/AVC

VP6

Container-Format

Container Format codieren(Video) Format codieren(Stimme)
AIFF - PCM
WAV - PCM
MP3 - MP3
FLV VP6 MP3
MP4 H.264/AVC AAC

AIFF

WAV

** MP3 (Container) **

FLV

MP4

Es scheint, dass die weit verbreiteten Codierungsformate (MP3, ACC, H.264) zumindest unterstützt werden.

Spielen Sie Mediendateien in nicht unterstützten Codierungscontainern ab

Referenz

Mediendatei abspielen

package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

import java.nio.file.Path;
import java.nio.file.Paths;

public class MainController {
    
    private MediaPlayer player;
    
    @FXML
    public void start() {
        Path music = Paths.get("./media/music.m4a");
        Media media = new Media(music.toUri().toString());
        this.player = new MediaPlayer(media);
        this.player.play();
    }
}

--Mediendateien können unabhängig von Audio / Video mit den Klassen Media, MediaPlayer abgespielt werden.

MediaPlayer-Statusübergang

javafx.png

Status Erläuterung
UNKNOWN Unmittelbar nach dem Erstellen und Lesen ist nicht abgeschlossen
READY Bereit zum Laden und Spielen
PLAYING Spielzustand
PAUSED Angehaltener Zustand
PLAYINGWenn Sie zu zurückkehren, wird es dort fortgesetzt, wo es gestoppt wurde.
STOPPED Angehaltener Zustand
PLAYINGSpielen Sie von Anfang an, wenn Sie zu zurückkehren
STALLED Die Streaming-Wiedergabe enthält nicht genügend Informationen, um den Player am Laufen zu halten
HALTED Ein Zustand, in dem der Spieler aufgrund eines Fehlers nicht spielen kann
DIPOSED Spieler werden zerstört und Ressourcen freigesetzt

--MediaPlayer führt einen Zustandsübergang durch, wie in der obigen Abbildung gezeigt.

Ressourcendatei abspielen

Ordnerstruktur


`-src/main/
  |-java/
  | `-sample/javafx/
  |   :
  `-resources/
    |-...
    `-media/
      `-music.mp3
package sample.javafx;

import javafx.fxml.Initializable;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        URL url = MainController.class.getResource("/media/music.mp3");
        Media media = new Media(url.toString());
        MediaPlayer player = new MediaPlayer(media);
        
        player.play();
    }
}

Wiederholen Sie wiederholt

package sample.javafx;

...

public class MainController implements Initializable {
    private MediaPlayer player;
    
    ...

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Path music = Paths.get("./media/music.mp3");
        Media media = new Media(music.toUri().toString());
        this.player = new MediaPlayer(media);

        this.player.setCycleCount(3);
    }
}

--setCycleCount (int) kann verwendet werden, um anzugeben, wie oft eine Mediendatei kontinuierlich abgespielt werden soll.

Wiedergabezeit

package sample.javafx;

...
import javafx.util.Duration;

public class MainController implements Initializable {
    private MediaPlayer player;
    
    ...

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Path music = Paths.get("./media/music.mp3");
        Media media = new Media(music.toUri().toString());
        this.player = new MediaPlayer(media);
        
        this.player.setCycleCount(3);

        Duration cycleDuration = this.player.getCycleDuration();
        System.out.println("cycleDuration=" + cycleDuration);
        Duration totalDuration = this.player.getTotalDuration();
        System.out.println("totalDuration=" + totalDuration);

        this.player.setOnReady(() -> {
            System.out.println("[onReady] cycleDuration=" + this.player.getCycleDuration());
            System.out.println("[onReady] totalDuration=" + this.player.getTotalDuration());
        });
    }
}

Ausführungsergebnis


cycleDuration=UNKNOWN
totalDuration=UNKNOWN
[onReady] cycleDuration=9541.0 ms
[onReady] totalDuration=28623.0 ms

Dauer Klasse

package sample.javafx.property;

import javafx.util.Duration;

public class Main {
    public static void main(String[] args) {
        Duration duration = new Duration(90000.0);
        System.out.println("duration=" + duration);
        System.out.println("duration.seconds=" + duration.toSeconds());
        System.out.println("duration.minutes=" + duration.toMinutes());

        Duration oneMinute = Duration.seconds(60);
        System.out.println("oneMinute=" + oneMinute);
        System.out.println("oneMinute.minutes=" + oneMinute.toMinutes());
    }
}

Ausführungsergebnis


duration=90000.0 ms
duration.seconds=90.0
duration.minutes=1.5

oneMinute=60000.0 ms
oneMinute.minutes=1.0

String-Format

package sample.javafx.property;

import javafx.util.Duration;

public class Main {
    public static void main(String[] args) {
        Duration duration = new Duration(12294027.0);
        String text = format(duration);
        System.out.println("text=" + text);
    }
    
    public static String format(Duration duration) {
        long millis = (long) duration.toMillis();
        long absMillis = Math.abs(millis);
        long hours = absMillis / 3_600_000;
        long minutes = (absMillis / 60_000) % 60;
        long seconds = (absMillis / 1_000) % 60;
        long milliseconds = absMillis % 1_000;

        return (millis < 0 ? "-" : "") + String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds);
    }
}

Ausführungsergebnis


text=03:24:54.027

Geben Sie den zu spielenden Bereich an

package sample.javafx;

...

public class MainController implements Initializable {
    private MediaPlayer player;
    
    ...

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Path music = Paths.get("./media/music.mp3");
        Media media = new Media(music.toUri().toString());
        this.player = new MediaPlayer(media);
        
        this.player.setCycleCount(3);
        
        this.player.setStartTime(Duration.seconds(1));
        this.player.setStopTime(Duration.seconds(3));

        this.player.setOnReady(() -> {
            System.out.println("cycleDuration=" + this.player.getCycleDuration());
            System.out.println("totalDuration=" + this.player.getTotalDuration());
        });
    }
}

Ausführungsergebnis


cycleDuration=2000.0 ms
totalDuration=6000.0 ms

Metadaten

Der MP3-Datei können verschiedene Metadaten wie Sänger, Albumname, Text und Albumcover hinzugefügt werden. Sie können über JavaFX auf diese Metadaten zugreifen (FLV-Metadaten scheinen verfügbar zu sein, werden hier jedoch weggelassen).

package sample.javafx;

import javafx.collections.ObservableMap;
import javafx.fxml.Initializable;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

...

public class MainController implements Initializable {
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Path music = Paths.get("./media/music2.mp3");
        Media media = new Media(music.toUri().toString());
        MediaPlayer player = new MediaPlayer(media);
        
        player.setOnReady(() -> {
            ObservableMap<String, Object> metadata = media.getMetadata();

            metadata.forEach((key, value) -> {
                System.out.println("key=" + key + ", value=" + value);
            });
        });
    }
}

Ausführungsergebnis


key=comment-1, value=iTunPGAP[eng]=0  
key=album artist, value=ClariS 
key=comment-0, value=[eng]=  
key=image, value=javafx.scene.image.Image@1ca0c8fb
key=artist, value=ClariS 
key=raw metadata, value={ID3=java.nio.HeapByteBufferR[pos=779441 lim=789675 cap=789675]}
key=composer, value=ryo 
key=album, value=SHIORI 
key=comment-3, value=iTunSMPB[eng]= 00000000 00000210 0000096C 0000000000E5EE04 00000000 007D1469 00000000 00000000 00000000 00000000 00000000 00000000 
key=comment-2, value=iTunNORM[eng]= 000022CF 000021D8 0000C4E5 0000FF84 0002901F 0004CBF5 0000823D 0000832E 0004A049 00049D87 
key=genre, value=  
key=title, value=Eine Geschichte, die Sie nicht kennen

Ändern Sie die Wiedergabeposition

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;

...

public class MainController implements Initializable {
    
    private MediaPlayer player;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Path music = Paths.get("./media/music2.mp3");
        Media media = new Media(music.toUri().toString());
        this.player = new MediaPlayer(media);
        this.player.play();
    }
    
    @FXML
    public void seek() {
        this.player.seek(Duration.minutes(2));
    }
}

javafx.jpg

Video anzeigen

javafx.jpg

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;

import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private MediaView mediaView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Path music = Paths.get("./media/movie.mp4");
        Media media = new Media(music.toUri().toString());
        MediaPlayer player = new MediaPlayer(media);
        
        this.mediaView.setMediaPlayer(player);
        player.play();
    }
}

--Verwenden Sie MediaView, um das Video anzuzeigen

AudioClip Es ist effizienter, "AudioClip" als "Media" für kleine Soundeffekte mit kurzer Wiedergabezeit zu verwenden.

package sample.javafx;

import javafx.fxml.Initializable;
import javafx.scene.media.AudioClip;

import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ResourceBundle;

public class MainController implements Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Path music = Paths.get("./media/music2.mp3");
        AudioClip audioClip = new AudioClip(music.toUri().toString());
        audioClip.play();
    }
}

Der Unterschied zu "Medien" ist wie folgt.

Weitere Informationen finden Sie unter Javadoc.

Versuchen Sie, einen einfachen Musik-Player zu erstellen

Lassen Sie uns einen einfachen Musik-Player erstellen, während wir die bisherigen Inhalte verwenden.

javafx.jpg

package sample.javafx;

import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.StringBinding;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status;
import javafx.util.Duration;

import java.net.URL;
import java.nio.file.Paths;
import java.util.ResourceBundle;
import java.util.stream.Stream;

public class SimpleMusicPlayerController implements Initializable {

    private MediaPlayer player;
    
    @FXML
    private Button playButton;
    @FXML
    private Button stopButton;
    @FXML
    private Button pauseButton;

    @FXML
    private Label volumeLabel;
    @FXML
    private Label totalTimeLabel;
    @FXML
    private Label currentTimeLabel;
    
    @FXML
    private Slider volumeSlider;
    @FXML
    private Slider seekSlider;

    @FXML
    public void play() {
        this.player.play();
    }

    @FXML
    public void stop() {
        this.player.stop();
    }

    @FXML
    public void pause() {
        this.player.pause();
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Media media = new Media(Paths.get("./media/music.m4a").toUri().toString());
        this.player = new MediaPlayer(media);

        //Volumenetikett
        this.volumeLabel.textProperty().bind(this.player.volumeProperty().asString("%.2f"));
        //Gesamtspielzeitbezeichnung
        this.player.setOnReady(() -> {
            Duration total = this.player.getTotalDuration();
            this.totalTimeLabel.setText(this.format(total));
        });
        //Aktuelle Bezeichnung für die Spielzeit
        this.currentTimeLabel.textProperty().bind(new StringBinding() {
            {bind(player.currentTimeProperty());}
            
            @Override
            protected String computeValue() {
                Duration currentTime = player.getCurrentTime();
                return format(currentTime);
            }
        });
        
        //Wiedergabetaste
        this.playButton.disableProperty().bind(new BooleanBinding() {
            {bind(player.statusProperty());}
            
            @Override
            protected boolean computeValue() {
                boolean playable = playerStatusIsAnyOf(Status.READY, Status.PAUSED, Status.STOPPED);
                return !playable;
            }
        });
        //Stopptaste
        this.stopButton.disableProperty().bind(new BooleanBinding() {
            {bind(player.statusProperty());}
            
            @Override
            protected boolean computeValue() {
                boolean stoppable = playerStatusIsAnyOf(Status.PLAYING, Status.PAUSED, Status.STALLED);
                return !stoppable;
            }
        });
        //Pause-Taste
        this.pauseButton.disableProperty().bind(new BooleanBinding() {
            {bind(player.statusProperty());}

            @Override
            protected boolean computeValue() {
                boolean pausable = playerStatusIsAnyOf(Status.PLAYING, Status.STALLED);
                return !pausable;
            }
        });
        
        //Lautstärkeregler
        this.player.volumeProperty().bind(this.volumeSlider.valueProperty());
        this.volumeSlider.setValue(1);
        
        //Suchleiste
        this.seekSlider.valueProperty().addListener((value, oldValue, newValue) -> {
            if (seekSliderIsChanging()) {
                Duration seekTime = this.player.getTotalDuration().multiply((Double) newValue);
                this.player.seek(seekTime);
            }
        });

        this.player.currentTimeProperty().addListener((value, oldValue, newValue) -> {
            if (!seekSliderIsChanging()) {
                double totalDuration = this.player.getTotalDuration().toMillis();
                double currentTime = newValue.toMillis();
                this.seekSlider.setValue(currentTime / totalDuration);
            }
        });

        //Nachbearbeitung nach Beendigung der Wiedergabe
        this.player.setOnEndOfMedia(() -> {
            this.player.seek(this.player.getStartTime());
            this.player.stop();
        });
    }
    
    private boolean playerStatusIsAnyOf(Status... statuses) {
        Status status = this.player.getStatus();
        return Stream.of(statuses).anyMatch(candidate -> candidate.equals(status));
    }

    private boolean seekSliderIsChanging() {
        return this.seekSlider.isValueChanging() || this.seekSlider.isPressed();
    }
    
    private String format(Duration duration) {
        long millis = (long) duration.toMillis();
        long minutes = (millis / 60_000) % 60;
        long seconds = (millis / 1_000) % 60;

        return String.format("%02d:%02d", minutes, seconds);
    }
}

Anzeige der aktuellen Wiedergabezeit

        //Aktuelle Bezeichnung für die Spielzeit
        this.currentTimeLabel.textProperty().bind(new StringBinding() {
            {bind(player.currentTimeProperty());}
            
            @Override
            protected String computeValue() {
                Duration currentTime = player.getCurrentTime();
                return format(currentTime);
            }
        });

    ...
    
    private String format(Duration duration) {
        long millis = (long) duration.toMillis();
        long minutes = (millis / 60_000) % 60;
        long seconds = (millis / 1_000) % 60;

        return String.format("%02d:%02d", minutes, seconds);
    }

--Binden Sie an die Eigenschaft currentTime von MediaPlayer und legen Sie den zeitformatierten Wert in der Beschriftung fest

Tastensteuerung

        //Wiedergabetaste
        this.playButton.disableProperty().bind(new BooleanBinding() {
            {bind(player.statusProperty());}
            
            @Override
            protected boolean computeValue() {
                boolean playable = playerStatusIsAnyOf(Status.READY, Status.PAUSED, Status.STOPPED);
                return !playable;
            }
        });
        //Stopptaste
        this.stopButton.disableProperty().bind(new BooleanBinding() {
            {bind(player.statusProperty());}
            
            @Override
            protected boolean computeValue() {
                boolean stoppable = playerStatusIsAnyOf(Status.PLAYING, Status.PAUSED, Status.STALLED);
                return !stoppable;
            }
        });
        //Pause-Taste
        this.pauseButton.disableProperty().bind(new BooleanBinding() {
            {bind(player.statusProperty());}

            @Override
            protected boolean computeValue() {
                boolean pausable = playerStatusIsAnyOf(Status.PLAYING, Status.STALLED);
                return !pausable;
            }
        });

    ...

    private boolean playerStatusIsAnyOf(Status... statuses) {
        Status status = this.player.getStatus();
        return Stream.of(statuses).anyMatch(candidate -> candidate.equals(status));
    }

--Verwenden Sie "Status" von "MediaPlayer", um "Deaktiviert" der Schaltfläche zu steuern

Lautstärkeregler

javafx.jpg

        //Volumenetikett
        this.volumeLabel.textProperty().bind(this.player.volumeProperty().asString("%.2f"));

        ...

        //Lautstärkeregler
        this.player.volumeProperty().bind(this.volumeSlider.valueProperty());
        this.volumeSlider.setValue(1);

Suchleiste

  1. Passen Sie die Position des Schiebereglers entsprechend der Wiedergabezeit an
  2. Passen Sie die Wiedergabezeit an, wenn der Benutzer den Schieberegler betätigt

javafx.jpg

Wiedergabezeit → Suchleiste

        this.player.currentTimeProperty().addListener((value, oldValue, newValue) -> {
            if (!seekSliderIsChanging()) {
                double totalDuration = this.player.getTotalDuration().toMillis();
                double currentTime = newValue.toMillis();
                this.seekSlider.setValue(currentTime / totalDuration);
            }
        });

    ...

    private boolean seekSliderIsChanging() {
        return this.seekSlider.isValueChanging() || this.seekSlider.isPressed();
    }

Suchleiste → Wiedergabezeit

        this.seekSlider.valueProperty().addListener((value, oldValue, newValue) -> {
            if (seekSliderIsChanging()) {
                Duration seekTime = this.player.getTotalDuration().multiply((Double) newValue);
                this.player.seek(seekTime);
            }
        });

Verarbeitung nach Ablauf der Wiedergabezeit

        //Nachbearbeitung nach Beendigung der Wiedergabe
        this.player.setOnEndOfMedia(() -> {
            this.player.seek(this.player.getStartTime());
            this.player.stop();
        });

Referenz

Speisekarte

Menüleiste

javafx.jpg

** Ausführungsergebnis **

javafx.jpg

Erläuterung

--Verwenden Sie MenuBar, um eine Menüleiste zu erstellen

Implementieren Sie den Prozess, wenn ein Menü ausgewählt ist

javafx.jpg

package sample.javafx;

import javafx.fxml.FXML;

public class MainController {
    
    @FXML
    public void open() {
        System.out.println(""Öffnen" ist ausgewählt");
    }
}

Separator

javafx.jpg

** Ausführungsergebnis **

javafx.jpg

Untermenü

javafx.jpg

** Ausführungsergebnis **

javafx.jpg

Weisen Sie eine Tastenkombination zu

javafx.jpg

** Ausführungsergebnis **

javafx.jpg

--Kurztasten können mit der Eigenschaft "Beschleuniger" von "MenuItem" zugewiesen werden --Kurztasten werden durch eine Kombination aus Modifizierertasten und Haupttasten definiert. --Die Modifikatortaste ist eine der Tasten "Strg", "Umschalt", "Alt", "Meta" und "Verknüpfung".

Memonic

javafx.jpg

package sample.javafx;

import javafx.fxml.FXML;

public class MainController {
    
    @FXML
    public void open() {
        System.out.println("open");
    }
    
    @FXML
    public void close() {
        System.out.println("close");
    }
    
    @FXML
    public void fullScreen() {
        System.out.println("full screen");
    }
}

Jedes Menü ist einer Controller-Methode zugeordnet.

** Ausführungsergebnis **

javafx.gif

――Es ist etwas schwer zu verstehen, aber Sie können das Menü nur mit der Tastatur bedienen, ohne die Maus zu verwenden. ―― Wie Sie sehen können, wenn Sie es tatsächlich berühren, ist die Bewegung ehrlich gesagt verdächtig

javafx.jpg

javafx.jpg

  1. Aktivieren Sie "Mnemonic Parsing"
  2. Setzen Sie einen Unterstrich (_) in Text vor das Alphabet, dem Sie eine Mnemonik zuweisen möchten.

Weisen Sie dem japanischen Menü Mnemonik zu

javafx.jpg

** Ausführungsergebnis **

javafx.jpg

Fügen Sie ein Symbol hinzu

javafx.jpg

Ordnerstruktur


`-src/main/
  |-java/
  | :
  `-resources/
    `-img/
      `-open.png
package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.MenuItem;
import javafx.scene.image.ImageView;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private MenuItem openMenuItem;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        ImageView image = new ImageView("/img/open.png ");
        this.openMenuItem.setGraphic(image);
    }
}

** Ausführungsergebnis **

javafx.jpg

Menü überprüfen

javafx.jpg

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckMenuItem;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private CheckMenuItem checkMenuItem;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.checkMenuItem.selectedProperty().addListener((value, oldValue, newValue) -> {
            System.out.println(newValue ? "Überprüft" : "Deaktiviert");
        });
    }
}

** Ausführungsergebnis **

javafx.gif

Optionsfeldmenü

javafx.jpg

package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.control.ToggleGroup;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private ToggleGroup group1;
    @FXML
    private RadioMenuItem hogeRadioMenuItem;
    @FXML
    private RadioMenuItem fugaRadioMenuItem;
    @FXML
    private RadioMenuItem piyoRadioMenuItem;
    
    @FXML
    private ToggleGroup group2;
    @FXML
    private RadioMenuItem fizzRadioMenuItem;
    @FXML
    private RadioMenuItem buzzRadioMenuItem;
    

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.hogeRadioMenuItem.setUserData("hoge");
        this.fugaRadioMenuItem.setUserData("fuga");
        this.piyoRadioMenuItem.setUserData("piyo");
        this.group1.selectedToggleProperty().addListener((toggle, oldValue, newValue) -> {
            if (newValue != null) {
                System.out.println("[group1] " + newValue.getUserData());
            }
        });
        
        this.fizzRadioMenuItem.setUserData("fizz");
        this.buzzRadioMenuItem.setUserData("buzz");
        this.group2.selectedToggleProperty().addListener((toggle, oldValue, newValue) -> {
            if (newValue != null) {
                System.out.println("[group2] " + newValue.getUserData());
            }
        });
    }
}

** Ausführungsergebnis **

javafx.gif

Gruppe auf fxml umschalten


  <RadioMenuItem fx:id="hogeRadioMenuItem" text="Hoge">
     <toggleGroup>
        <ToggleGroup fx:id="group1" />
     </toggleGroup>
  </RadioMenuItem>

--fx: id ist die durch Toggle Group angegebene Kennung --So können Sie eine ToggleGroup-Instanz mit der angegebenen ID "Toggle Group" in die Controller-Klasse einfügen.

Gruppeninjektion umschalten


    @FXML
    private ToggleGroup group1;
        this.hogeRadioMenuItem.setUserData("hoge");
        this.fugaRadioMenuItem.setUserData("fuga");
        this.piyoRadioMenuItem.setUserData("piyo");
        this.group1.selectedToggleProperty().addListener((toggle, oldValue, newValue) -> {
            if (newValue != null) {
                System.out.println("[group1] " + newValue.getUserData());
            }
        });

--Welches Menü ausgewählt ist, wird durch den in userData der Menüelementinstanz registrierten Wert identifiziert. -- userData ist vom Typ Object, sodass Sie einen beliebigen Wert eingeben können ――Ich benutze es normalerweise nicht oft, aber es kann in Situationen wie dieser Zeit verwendet werden, um ausgewählte Elemente in einer Gruppe zu identifizieren.

Kontextmenü

javafx.jpg

** Ausführungsergebnis **

javafx.jpg

--Das Kontextmenü (das Menü, das durch Klicken mit der rechten Maustaste angezeigt wird) kann durch Hinzufügen von "ContextMenu" zum Zielknoten realisiert werden.

Referenz

Maximieren Sie das Fenster

Main.java


package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.net.URL;

public class Main extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = this.getClass().getResource("/main.fxml");
        FXMLLoader loader = new FXMLLoader(url);
        Parent root = loader.load();

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        
        primaryStage.setMaximized(true); //★ Maximieren

        primaryStage.show();
    }
}

Öffne ein anderes Fenster

Basic

Ordnerstruktur


`-src/main/
  |-java/
  | `-sample/javafx/
  |   |-MainController.java
  |   `-OtherController.java
  |
  `-resources/
    |-main.fxml
    `-other.fxml

other.fxml

javafx.jpg

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;

public class MainController {
    
    @FXML
    public void openOtherWindow() throws IOException {
        //Laden Sie fxml und
        URL fxml = this.getClass().getResource("/other.fxml");
        FXMLLoader loader = new FXMLLoader(fxml);
        Pane pane = loader.load();
        
        //Erstellen Sie eine Szene
        Scene scene = new Scene(pane);
        
        //Registrieren Sie die Szene auf der Bühne
        Stage stage = new Stage();
        stage.setScene(scene);
        
        //Anzeige
        stage.show();
    }
}

--Verwenden Sie FXMLLoader, um fxml zu laden

Holen Sie sich den Controller

MainController.java


package sample.javafx;

public class MainController {
    
    public void hello() {
        System.out.println("Hello MainController!!");
    }
}

Main.java


package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.net.URL;

public class Main extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = this.getClass().getResource("/main.fxml");
        FXMLLoader loader = new FXMLLoader(url);
        Parent root = loader.load();
        
        MainController controller = loader.getController();
        controller.hello();
        
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);

        primaryStage.show();
    }
}

** Ausführungsergebnis **

Hello MainController!!

Besitzereinstellungen

** Verhalten, wenn kein Eigentümer festgelegt ist **

javafx.gif

** Set Besitzer **

Main.java


package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.net.URL;

public class Main extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = this.getClass().getResource("/main.fxml");
        FXMLLoader loader = new FXMLLoader(url);
        Parent root = loader.load();

        MainController controller = loader.getController();
        controller.setStage(primaryStage); //★ Stellen Sie die Stufe des Controllers am Controller ein
        
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);

        primaryStage.show();
    }
}

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;

public class MainController {
    
    private Stage stage; //★ Die Stufe dieses Controllers ist eingestellt

    public void setStage(Stage stage) {
        this.stage = stage;
    }

    @FXML
    public void openOtherWindow() throws IOException {
        URL fxml = this.getClass().getResource("/other.fxml");
        FXMLLoader loader = new FXMLLoader(fxml);
        Pane pane = loader.load();

        Scene scene = new Scene(pane);

        Stage stage = new Stage();
        stage.setScene(scene);
        stage.initOwner(this.stage); //★ Besitzer einstellen

        stage.showAndWait();
    }
}

** Ausführungsergebnis **

javafx.gif

modal

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;

public class MainController {

    private Stage stage;

    public void setStage(Stage stage) {
        this.stage = stage;
    }

    @FXML
    public void openOtherWindow() throws IOException {
        URL fxml = this.getClass().getResource("/other.fxml");
        FXMLLoader loader = new FXMLLoader(fxml);
        Pane pane = loader.load();

        Scene scene = new Scene(pane);

        Stage stage = new Stage();
        stage.setScene(scene);
        stage.initOwner(this.stage);
        stage.initModality(Modality.WINDOW_MODAL); //★ Modalität einstellen

        stage.showAndWait();
    }
}

** Ausführungsergebnis **

javafx.gif

Konstante Bedeutung
NONE Blockieren Sie keine anderen Fenster
WINDOW_MODAL Blockieren Sie das Fenster des Besitzers
(Blockieren Sie keine anderen Fenster als den Eigentümer.)
APPLICATION_MODAL Blockiere alle Fenster

Referenz

Betten Sie eine andere fxml ein

Basic

** Ordnerstruktur **

`-src/main/resources/
  |-embedded.fxml
  `-main.fxml

** Fxml einbetten (embedded.fxml) **

javafx.jpg

** Einbetten des Ziel-fxml (main.fxml) **

javafx.jpg

main.fxml


<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.151" xmlns:fx="http://javafx.com/fxml/1">
   <top>
      <Label text="Main" BorderPane.alignment="CENTER">
         <font>
            <Font size="40.0" />
         </font>
      </Label>
   </top>
   <center>
      <fx:include source="embedded.fxml" />
   </center>
</BorderPane>

Erläuterung

** Versuche, in SceneBuilder aufzunehmen, schlagen fehl **

javafx.jpg

--SceneBuilder scheint ein Menü zu haben, um fxml einzuschließen (Datei-> Einschließen-> FXML) --Aber wenn ich versuche, fxml damit einzuschließen, wird es nicht mit "Fehler beim Einschließen" ***. Fxml "aufgenommen »Manchmal gelingt es Ihnen, aber ich bin mir nicht sicher

Holen Sie sich den eingebetteten fxml-Controller

Dateiorganisation


`-src/main/
  |-java/
  | `-sample/javafx/
  |   |-Main.java
  |   |-MainController.java
  |   `-EmbeddedController.java
  `-resources/
    |-main.fxml
    `-embedded.fxml

embedded.fxml

javafx.jpg

EmbeddedController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class EmbeddedController {
    @FXML
    private Label label;
    
    public void setMessage(String message) {
        this.label.setText(message);
    }
}

main.fxml

javafx.jpg

main.fxml


...

<BorderPane fx:id="pane" ... fx:controller="sample.javafx.MainController">
   <top>
      <Label text="Main" BorderPane.alignment="CENTER">
         ...
      </Label>
   </top>
   <center>
      <fx:include fx:id="embedded" source="embedded.fxml" />
   </center>
</BorderPane>

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private EmbeddedController embeddedController;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.embeddedController.setMessage("Hello!!");
    }
}

** Ausführungsergebnis **

javafx.jpg

Erläuterung

Zeigen Sie die eingebettete fxml als separates Fenster an

embedded.fxml

javafx.jpg

EmbeddedController.java


package sample.javafx;

import javafx.beans.binding.StringBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

import java.net.URL;
import java.util.ResourceBundle;

public class EmbeddedController implements Initializable {
    
    private IntegerProperty count = new SimpleIntegerProperty(0);
    
    @FXML
    private Label label;
    
    @FXML
    public void countUp() {
        int now = this.count.get();
        this.count.set(now + 1);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        StringBinding output = this.count.asString("count = %d");
        this.label.textProperty().bind(output);
    }
}

main.fxml

javafx.jpg

main.fxml


<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.151" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.javafx.MainController">
   <fx:define>
      <fx:include fx:id="embeddedPane" source="embedded.fxml" />
   </fx:define>
   <top>
      <Label text="Main" BorderPane.alignment="CENTER">
         <font>
            <Font size="40.0" />
         </font>
      </Label>
   </top>
   <center>
      <Button mnemonicParsing="false" onAction="#openWindow" text="Open Window" BorderPane.alignment="CENTER">
         <font>
            <Font size="25.0" />
         </font>
      </Button>
   </center>
</BorderPane>

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    @FXML
    private Pane embeddedPane;
    
    private Stage embeddedWindow;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Scene scene = new Scene(this.embeddedPane);
        this.embeddedWindow = new Stage();
        this.embeddedWindow.setScene(scene);
        this.embeddedWindow.initModality(Modality.APPLICATION_MODAL);
    }
    
    @FXML
    public void openWindow() {
        this.embeddedWindow.showAndWait();
    }
}

** Ausführungsergebnis **

javafx.gif

Erläuterung

main.fxml


...

<BorderPane ... fx:controller="sample.javafx.MainController">
   <fx:define>
      <fx:include fx:id="embeddedPane" source="embedded.fxml" />
   </fx:define>
   ...
</BorderPane>

--Betten Sie die einzubettende FXML (embedded.fxml) mit <fx: include> in die eingebettete FXML (main.fxml) ein.

MainController.java


package sample.javafx;

...

public class MainController implements Initializable {
    @FXML
    private Pane embeddedPane;
    
    private Stage embeddedWindow;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Scene scene = new Scene(this.embeddedPane);
        this.embeddedWindow = new Stage();
        this.embeddedWindow.setScene(scene);
        this.embeddedWindow.initModality(Modality.APPLICATION_MODAL);
    }
    
    @FXML
    public void openWindow() {
        this.embeddedWindow.showAndWait();
    }
}

--DI die eingebettete FXML (embedded.fxml) mit @ FXML an den eingebetteten Controller ( MainController.java) (embeddedPane)

Referenz

Dialogfeld zur Dateiauswahl

javafx.jpg

--Klicken Sie auf die Schaltfläche, um den Dateiauswahldialog anzuzeigen

Main.java


package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.net.URL;

public class Main extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = this.getClass().getResource("/main.fxml");
        FXMLLoader loader = new FXMLLoader(url);

        Parent root = loader.load();
        MainController controller = loader.getController();
        controller.setStage(primaryStage);
        
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);

        primaryStage.show();
    }
}

MainController.java


package sample.javafx;

import javafx.fxml.FXML;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.File;

public class MainController {
    
    private Stage stage;
    
    @FXML
    public void openFileDialog() {
        FileChooser chooser = new FileChooser();
        File file = chooser.showOpenDialog(this.stage);
        System.out.println("file=" + file);
    }

    public void setStage(Stage stage) {
        this.stage = stage;
    }
}

** Ausführungsergebnis **

javafx.jpg

Angezeigter Dialog

javafx.jpg

Wählen Sie eine Datei aus und klicken Sie auf "Öffnen".

Konsolenausgabe


file=C:\Program Files\Java\jdk-9.0.1\README.html

Erläuterung

        FileChooser chooser = new FileChooser();
        File file = chooser.showOpenDialog(this.stage);
        System.out.println("file=" + file);

Stellen Sie den Titel ein

        FileChooser chooser = new FileChooser();
        chooser.setTitle("Fair Sentaku");
        File file = chooser.showOpenDialog(this.stage);

** Ausführungsergebnis **

javafx.jpg

Geben Sie das Verzeichnis an, das ursprünglich angezeigt werden soll

        FileChooser chooser = new FileChooser();
        chooser.setInitialDirectory(new File("C:/Program Files/java/jdk-9.0.1"));
        File file = chooser.showOpenDialog(this.stage);

Mit "setInitialDirectory (File)" können Sie das Verzeichnis angeben, das beim Öffnen des Dialogfelds angezeigt werden soll.

Grenzen Sie die auswählbaren Dateien nach Erweiterung ein

package sample.javafx;

import javafx.collections.ObservableList;
import javafx.stage.FileChooser.ExtensionFilter;
...

public class MainController {
    
    private Stage stage;
    
    @FXML
    public void openFileDialog() {
        FileChooser chooser = new FileChooser();
        
        ObservableList<ExtensionFilter> extensionFilters = chooser.getExtensionFilters();
        extensionFilters.add(new ExtensionFilter("Etwas", "*.*"));
        extensionFilters.add(new ExtensionFilter("Mit nur dem Bild", "*.jpg ", "*.jpeg ", "*.png ", "*.gif"));
        extensionFilters.add(new ExtensionFilter("Regentag Video", "*.mp4"));
        
        File file = chooser.showOpenDialog(this.stage);
        System.out.println("file=" + file);
    }

    ...
}

** Ausführungsergebnis **

javafx.jpg

Öffnet einen Dialog, in dem Sie mehrere Dateien auswählen können

        FileChooser chooser = new FileChooser();
        List<File> files = chooser.showOpenMultipleDialog(this.stage);
        if (files == null) {
            System.out.println("files=" + files);
        } else {
            files.forEach(System.out::println);
        }

** Ausführungsergebnis **

javafx.jpg

Konsolenausgabe


C:\Program Files\Java\jdk-9.0.1\COPYRIGHT
C:\Program Files\Java\jdk-9.0.1\README.html
C:\Program Files\Java\jdk-9.0.1\release

Dialogfeld zum Auswählen, wo die Datei gespeichert werden soll

        FileChooser chooser = new FileChooser();
        File file = chooser.showSaveDialog(this.stage);
        System.out.println("file=" + file);

** Ausführungsergebnis **

javafx.jpg

Konsolenausgabe


file=C:\Users\Public\hoge

Dialogfeld zur Verzeichnisauswahl

package sample.javafx;

import javafx.stage.DirectoryChooser;
...

public class MainController {
    
    private Stage stage;
    
    @FXML
    public void openFileDialog() {
        DirectoryChooser chooser = new DirectoryChooser();
        File directory = chooser.showDialog(this.stage);
        System.out.println("directory=" + directory);
    }

    ...
}

** Ausführungsergebnis **

javafx.jpg

Konsolenausgabe


directory=C:\Users\Public\Downloads

Referenz

Richten Sie Schaltflächen und Beschriftungen auf dieselbe Breite (Höhe) aus und ordnen Sie sie vertikal (horizontal) an.

Aussehen

javafx.jpg

Konstruktion

javafx.jpg

** Größeneinstellung jedes vertikalen Elements **

javafx.jpg

--Verwenden Sie VBox, um vertikal mit der gleichen Breite anzuordnen

Recommended Posts

JavaFX-Studiennotizen
Puzzle-Studiennotizen
Docker-Studiennotizen
[Java] Studiennotizen
Mavens grundlegende Studiennotizen
Interne Studiennotizen im Klassen- und Lambda-Stil
JUnit 4 Notizen
Studienpolitik
Java Note
Anmerkungen zur Spring Framework-Studie [Teil 1] DI-Container
JavaFx-Memorandum
synchronisierte Notizen