Hinweise zum Studium von JavaFX
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 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;
}
}
value
) mit private
DoubleProperty
selbst ist eine Schnittstelle, und SimpleDoubleProperty
wird als Implementierungsklasse bereitgestellt.final
definiertViele 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.
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".
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]
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.
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
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
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
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]
bind ()
verwenden, um sie einfach zu implementieren.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]
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 **
Die bidirektionale Bindungsmethode für "Eigenschaft
Auf der anderen Seite verfügt StringProperty über die folgenden zwei Methoden für die bidirektionale Bindung. Wurde hinzugefügt.
--Formatenspezifikation
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 **
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 **
StringConverter
definiert
--String toString (T)
: Konvertiert das Objekt T
in String
--T fromString (String)
: Konvertiert String
in Objekt T
JavaFX bietet eine eigene Auflistungsklasse, die eine Erweiterung der Standardauflistung ("Liste" oder "Karte") darstellt.
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] }
FXCollections
, um eine Instanz zu erstellen
--FXCollections
ist eine Dienstprogrammklasse für JavaFX-Sammlungen mit ähnlichen Methoden wie java.util.Collections. --
addListener (ListChangeListener) kann verwendet werden, um Listener zu registrieren, um Änderungsbenachrichtigungen zu erhalten. --
ObservableList erbt auch
Observable--Und
Observable definiert auch eine Methode mit dem gleichen Namen
addListener (InvalidationListener)`, aber unterschiedlichen Argumenten.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 }
next ()
-Methode ** ausführen, bevor Sie die Änderungen vom Change
-Objekt ** erhalten könnenChange
Objekt darf nicht in einem anderen Thread verwendet werden **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
wasAdded ()
true zurückgetFrom ()
ist der erste Index (einschließlich dieses Index), zu dem das Element hinzugefügt wurde.
--getTo ()
ist der letzte Index, zu dem das Element hinzugefügt wurde (dieser Index ist nicht enthalten)
--getAddedSubList ()
kann verwendet werden, um eine List
abzurufen, die nur die hinzugefügten Elemente enthält.getAddedSize ()
abrufenpackage 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
List
mit getRemoved ()
abrufen
--getRemovedSize ()
gibt die Anzahl der entfernten Elemente zurückpackage 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
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
wasReplaced ()
kann niemals true
sein
--Wenn wasReplaced ()
is true
ist, sindwasAddedd ()
und wasRemoved ()
immer true
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]
SortedList
implementiert ObservableList
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]
FilteredList
) erhalten, die mit der ursprünglichen ObservableList
verknüpft ist, indem Sie die Methodegefiltert (Prädikat)
ausführen.setPredicate ()
ändern
--FilteredList
implementiert ObservableList
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 überwachbare
Mapbereitgestellt --Verwenden Sie
FXCollections.observableHashMap ()`, um eine Instanz zu erstellen
wasAdded ()
)" und "gelöscht (wasRemoved ()
)".getValueAdded ()
,
Sie können den entfernten Wert mit getValueRemoved ()
abrufenOrdnerstruktur
`-src/main/
|-java/sample/javafx/
| |-Main.java
| `-MainController.java
|
`-resources/
|-main.fxml
`-my-style.css
main.fxml
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 **
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 ()".
[Pfad]
wird als ** relativ zur Wurzel des Klassenpfads ** behandeltmy-style.css
.label {
-fx-background-color: skyblue;
}
Selector {property: value;}
.xxxx
für JavaFX CSS styleClass =" xxxx "
Label
, ListView
usw.) ist das Attribut styleClass
standardmäßig nach bestimmten Konvertierungsregeln benannt.-
getrennt und alle sind in Kleinbuchstaben.
――Diese Konvertierung verfügt jedoch über keine automatische Konvertierungslogik, sondern wird nur in jeder Klasse gemäß den oben genannten Regeln festgelegt.
――Sie können es anhand der Implementierung der Label-Klasse erkennen.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
)
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 **
-fx-underline: true;
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 **
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);
}
}
add ()
zur Liste hinzugefügt werdenOrdnerstruktur
|-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 **
file: [path]
an, um eine lokale CSS-Datei anzugebenWie man -fx-Hintergrundbild
einstellt
Ordnerstruktur
|-image.jpg
`-src/main/
|-resources/
| |-img/
| | `-image.jpg
| |-my-style.css
| `-main.fxml
:
my-style.css
.my-class {
-fx-background-image: url('/img/image.jpg');
}
url
anmy-style.css
.my-class {
-fx-background-image: url('file:./image.jpg');
}
--Wenn Sie eine lokale Datei angeben, verwenden Sie file: [path]
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 **
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
Wenn ein Ereignis eintritt, wird die Verarbeitung in der folgenden Reihenfolge ausgeführt
[^ 2]: Im offiziellen japanischen Dokument wird es als "root" beschrieben, aber es wird als "route" geschrieben, weil es mit "root" verwechselt zu werden scheint.
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));
}
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
setOnMouseClicked (EventHandler)
etc.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");
}
...
}
YellowPane
) führt die Consum ()
-Methode von MouseEvent
aus.** Ausführungsergebnis **
Klicken Sie auf den gelben Bereich
filter bluePane
filter yellowPane
filter label
handler label
handler yellowPane
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.
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 **
Erläuterung
MainController.java
@FXML
public void onDragOver(DragEvent e) {
e.acceptTransferModes(TransferMode.ANY);
e.consume();
}
ANY
repräsentiert alle drei Übertragungsmodi (dh alles ist in Ordnung).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.
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 **
Erläuterung
MainController.java
@FXML
public void onDragOver(DragEvent e) {
Dragboard dragboard = e.getDragboard();
if (dragboard.hasFiles()) {
e.acceptTransferModes(TransferMode.ANY);
}
e.consume();
}
acceptTransferModes ()
nur ausgeführt, wennhasFiles ()
true ist, sodass Sie nur Dateien löschen können.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();
}
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 **
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();
}
getHtml ()
reproduziert.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 **
Erläuterung
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 **
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.
ClipboardContent
selbst eine Map ist, die HashMap <DataFormat, Object>
erbt, können Sie jeden Wert speichern.Referenz
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.
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.showAndWait();
** Ausführungsergebnis **
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
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Messeji");
alert.showAndWait();
INFORMATION
CONFIRMATION
WARNING
ERROR
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();
--ButtonType
kann nach dem dritten Argument des Konstruktors angegeben werden
ButtonType
als Konstanten definiert. Wenn dies alles ist, was Sie benötigen, verwenden Sie sie.ButtonBar
ist eine Klasse für das Tastenlayout und kann das für jedes Betriebssystem einzigartige Tastenlayout reproduzieren.** 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.
F
ist nicht gut verstanden, weil es keine entsprechende Konstante gibt)ButtonType.CANCEL
im Konstruktor Alert
angegeben ist,
Da "ButtonData" von "ButtonType.CANCEL" "CANCEL_CLOSE" ist, wird die Schaltfläche "Abbrechen" in der Reihenfolge "ButtonBar" in den Teil "C" eingefügt.ButtonType myButton = new ButtonType("Taste");
Alert alert = new Alert(Alert.AlertType.INFORMATION, "Messeji", myButton);
alert.showAndWait().ifPresent(System.out::println);
** Ausführungsergebnis **
Konsolenausgabe, wenn auf die Schaltfläche "Botan" geklickt wird
ButtonType [text=Taste, buttonData=OTHER]
ButtonType
angegeben werden.ButtonType
hat auch einen Konstruktor, der ButtonData
empfängt, sodass Sie ihn explizit angeben können.--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 **
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 **
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.
ButtonData
ist CANCEL_CLOSE`` ButtonType
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,
ButtonType
ButtonType
wobei ButtonData`` CANCEL_CLOSE
istButtonData.isCancelButton ()
gibt true
ButtonType
zurückMit 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();
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();
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.
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.
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)
Arbeiter haben einen Lebenszyklus und der Zustand geht wie folgt über.
READY
SCHEDULED
RUNNING
SUCCEEDED
value
gesetztFAILED
--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
call ()
ist eine abstrakte Methodecall ()
in Ihrer eigenen Klasse und beschreiben Sie den Prozess, der im Hintergrund ausgeführt wird.
--Die Klasse "Task" implementiert die Schnittstelle "Runnable", sodass Sie sie an "Thread" oder "Executor" übergeben können, um sie auszuführen.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!!
call ()
abgebrochen wurde.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 **
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
updateProgress ()
kann problemlos von einem Nicht-UI-Thread ausgeführt werden.
--In welchem runLater ()
verwendet wirdpackage 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 **
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
Wertes
wird durch das Typargument von Task
angegeben.Task
erfolgreich ist, wird der Rückgabewert der call ()
-Methode schließlich auf die value
-Eigenschaft gesetzt.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
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
call ()
ausgelöst wird, wird die ausgelöste Ausnahme in der Eigenschaft exception
gesetzt.
――Die Ausnahme wird nicht an die Spitze des Stapels übertragen. Wenn Sie sie also in Ruhe lassen, werden Sie nicht bemerken, dass die Ausnahme ausgelöst wurde.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.
Service
umschließt Task
so, dass eine neue Instanz von Task
erstellt und jedes Mal ein Thread gestartet wird, wenn die Thread-Verarbeitung ausgeführt wird.
--Service
ist eine abstrakte Klasse, und Sie können Ihre eigene Klasse erstellen und verwenden, die diese Klasse erbt.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();
}
start ()
of Service
in einem anderen Zustand als READY
ausführen, wird IllegalStateException
ausgelöst.reset ()
Methode im fertigen Zustand aus (SUCCEEDED
, FAILED
, CANCELLED
)
--Für SCHEDULED
, RUNNING
, brechen Sie mitcancel ()
ab und führen Sie dann die Methodereset ()
aus.
――Wenn Sie nicht auf jeden Status zurückblicken möchten, führen Sie einfach die Methode restart ()
aus.
--Wenn der Status "BEREIT" lautet, starten Sie den Vorgang so wie er istrestart()Beim Umschreiben mit
@FXML
public void start() throws IOException {
System.out.println("restart");
this.service.restart();
}
start ()
, reset ()
und restart ()
müssen alle vom UI-Thread ausgeführt werden.Ü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
Service
den Thread, um Task
von executor
auszuführen.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
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.
** Ausführungsergebnis **
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);
}
}
** Ausführungsergebnis **
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);
}
}
** Ausführungsergebnis **
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);
}
}
0.0
und es fühlt sich an, als würde es sich von dort aus im Uhrzeigersinn drehen.
- ―
: 0.0
- \
: 45.0
- |
: 90.0
- /
: 135.0
- ―
: 180.0
** Ausführungsergebnis **
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);
}
}
** Ausführungsergebnis **
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);
}
}
offsetX
, offsetY
an
--Verwenden Sie "Breite" und "Höhe", um den Grad der Unschärfe der Schatten in vertikaler und horizontaler Richtung festzulegen.Nehmen Sie einige Änderungen am Szenendiagramm vor, um die Anzeige zu erleichtern.
** Ausführungsergebnis **
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
offsetX
, offsetY
an** Ausführungsergebnis **
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
topOffset
die relative Position (Offset) des oberen Teils des reflektierten Teils an.topOpacity
die Transparenz des oberen Teils des reflektierten Teils an.bottomOpacity
die Transparenz am unteren Rand des reflektierten Teils an.** Ausführungsergebnis **
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.
setInput ()
übergebene wird zuerst angewendet.Referenz
――Wenn die Mediendaten unverändert bleiben, sind selbst einige Minuten Inhalt groß, z. B. Hunderte von MB oder GB.
.mp4
für MP4, .flv
, .f4v
usw. für FLV).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 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.
Referenz
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
bietet eine API zum Bearbeiten von MedienPlay ()
, pause ()
, stop ()
sind Methoden von MediaPlayer
Status | Erläuterung |
---|---|
UNKNOWN |
Unmittelbar nach dem Erstellen und Lesen ist nicht abgeschlossen |
READY |
Bereit zum Laden und Spielen |
PLAYING |
Spielzustand |
PAUSED |
Angehaltener ZustandPLAYING Wenn Sie zu zurückkehren, wird es dort fortgesetzt, wo es gestoppt wurde. |
STOPPED |
Angehaltener ZustandPLAYING Spielen 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.
Media
-Instanz gelesen.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();
}
}
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.
MediaPlayer.INDEFINITE
angegeben ist, ist eine unbegrenzte kontinuierliche Wiedergabe möglich.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
cycleDuration
repräsentiert die Wiedergabezeit für ein Mal
--totalDuration
repräsentiert die gesamte Wiedergabezeit einschließlich Wiederholung
--Duration.INDEFINITE
, wenn die Anzahl der Ansichten INDEFINITE
istpackage 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
Duration
-Version von JavaFX unter Bezugnahme auf das Implementierungsbeispiel von StackOverflow in ↑ zu schreiben, sieht es wie ↓ auspackage 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
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
cycleDuration
gibt die Zeit zwischen startTime
und stopTime
zurück
--totalDuration
ist cycleDuration * views
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
ObservableMap
, die die Metadaten enthält, mit getMetadata ()
of Media
abrufen.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));
}
}
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
fitWidth
und fitHeight
eingestellt werdenAudioClip 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();
}
}
Media
eine URL-Zeichenfolge an das Konstruktorargument, um eine Instanz zu erstellen.play ()
gestartet werdenDer Unterschied zu "Medien" ist wie folgt.
stop ()
danach keine Wirkung mehr.
--Die gleiche Instanz kann mit play ()
mehrmals gleichzeitig abgespielt werdenWeitere Informationen finden Sie unter Javadoc.
Lassen Sie uns einen einfachen Musik-Player erstellen, während wir die bisherigen Inhalte verwenden.
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);
}
}
//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
//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
//Volumenetikett
this.volumeLabel.textProperty().bind(this.player.volumeProperty().asString("%.2f"));
...
//Lautstärkeregler
this.player.volumeProperty().bind(this.volumeSlider.valueProperty());
this.volumeSlider.setValue(1);
volume
eingestellt werdenMediaPlayer.seek ()
aufrufen 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();
}
currentTime
--Berechnen Sie das Verhältnis der aktuellen Zeit zur Gesamtzeit und stellen Sie es auf den Schieberegler "Wert"isValueChanging()
isPressed()
this.seekSlider.valueProperty().addListener((value, oldValue, newValue) -> {
if (seekSliderIsChanging()) {
Duration seekTime = this.player.getTotalDuration().multiply((Double) newValue);
this.player.seek(seekTime);
}
});
//Nachbearbeitung nach Beendigung der Wiedergabe
this.player.setOnEndOfMedia(() -> {
this.player.seek(this.player.getStartTime());
this.player.stop();
});
MediaPlayer
hat intern ein Flag für boolean
, unabhängig davon, ob die Wiedergabe beendet wurde oder nicht. Wenn dieses Flag jedoch true
ist, gibt getCurrentTime ()
stopTime` zurück. Mögen
--Und wenn Sie den Status nach dem Ende der Wiedergabe nur mit "stop ()" ändern, bleibt dieses Flag "true", und ich glaube, dass "currentTime" nur "stopTime" zurückgibt, obwohl es danach abgespielt wird.
――Ich denke, es ist ein Fehler, aber ich bin mit den Spezifikationen nicht vertraut, daher kann ich nichts sagen.Referenz
** Ausführungsergebnis **
Erläuterung
--Verwenden Sie MenuBar
, um eine Menüleiste zu erstellen
Menu
, um eine Kategorie (in der" File "steht) zu MenuBar
hinzuzufügenpackage sample.javafx;
import javafx.fxml.FXML;
public class MainController {
@FXML
public void open() {
System.out.println(""Öffnen" ist ausgewählt");
}
}
** Ausführungsergebnis **
** Ausführungsergebnis **
** Ausführungsergebnis **
--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".
Shortcut
ist eine Taste, die häufig in Verknüpfungen verwendet wird und OS-unabhängige Definitionen realisieren kann.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 **
――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
_
) in Text
vor das Alphabet, dem Sie eine Mnemonik zuweisen möchten.** Ausführungsergebnis **
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 **
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 **
CheckMenuItem
können Sie einen Menüpunkt definieren, um die Prüfung ein- und auszuschalten.selected
ausgewählt ist.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 **
Toggle Group
ist in fxml wie folgt definiertGruppe 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.
** Ausführungsergebnis **
--Das Kontextmenü (das Menü, das durch Klicken mit der rechten Maustaste angezeigt wird) kann durch Hinzufügen von "ContextMenu" zum Zielknoten realisiert werden.
Referenz
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();
}
}
Ordnerstruktur
`-src/main/
|-java/
| `-sample/javafx/
| |-MainController.java
| `-OtherController.java
|
`-resources/
|-main.fxml
`-other.fxml
other.fxml
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
load ()
abrufen.show ()
oder showAndWait ()
.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!!
FXMLLoader.load ()
geladen haben, können Sie eine Instanz des Controllers abrufen, die mit der Methode FXMLLoader.getController ()
fxml zugeordnet ist.
--Beachten Sie, dass "null" vor "load ()" zurückgegeben wird** Verhalten, wenn kein Eigentümer festgelegt ist **
** 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 **
initOwner ()
, um den Eigentümer festzulegen
Übrigens, auch wenn Sie den Eigentümer festlegen, ist es nicht 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 **
initModality ()
modal machenNONE
, WINDOW_MODAL
, APPLICATION_MODAL
sind in Modality
definiert.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
** Ordnerstruktur **
`-src/main/resources/
|-embedded.fxml
`-main.fxml
** Fxml einbetten (embedded.fxml) **
** Einbetten des Ziel-fxml (main.fxml) **
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
/
beginnt
-Die Referenz lautet "Es wird als relativ zum Klassenpfad angesehen", daher ist es schwierig, die Bedeutung zu verstehen. .. ../
beginnt, scheint es ein relativer Pfad vom Speicherort der eingebetteten fxml-Datei zu sein.
--Dies ist auch schwer zu verstehen, da in der Referenz steht "Es wird als relativ zum Pfad des aktuellen Dokuments angesehen". .. ../
schreiben, um eine Vorschau anzuzeigen.** Versuche, in SceneBuilder aufzunehmen, schlagen fehl **
--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
<fx: include>
von Hand eingebettet haben, können Sie es normal von SceneBuilder aus bedienen.Dateiorganisation
`-src/main/
|-java/
| `-sample/javafx/
| |-Main.java
| |-MainController.java
| `-EmbeddedController.java
`-resources/
|-main.fxml
`-embedded.fxml
embedded.fxml
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
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 **
Erläuterung
EmbeddedController
), der der mit<fx: include>
eingebetteten FXML ( embedded.fxml
) zugeordnet ist, ist das Einbettungsziel.
Sie können mit @ FXML
in den Controller ( MainController
) von FXML (main.fxml
) injizierenfx: id
muss jedoch in <fx: include>
gesetzt werden.fx: id
nicht gesetzt ist, wird die Controller-Instanz nicht injiziert und ist null
.embedded.fxml
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
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 **
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.
<fx: define>
ein.fx: id
in <fx: include>
(erforderlich, um DI an die Steuerung zu senden)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
)
EmbeddedController
) ist der gleiche wie der des eingebetteten Controllers.FXMLLoader
laden.Referenz
--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 **
Angezeigter Dialog
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);
Stage
als ArgumentStage
anshowOpenDialog ()
wird blockiert, während der Dialog angezeigt wirdnull
wird zurückgegeben, wenn der Dialog ohne Auswahl einer Datei geschlossen wird FileChooser chooser = new FileChooser();
chooser.setTitle("Fair Sentaku");
File file = chooser.showOpenDialog(this.stage);
** Ausführungsergebnis **
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.
setInitialDirectory ()
angeben, wenn Sie den Dialog erneut öffnen.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 **
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 **
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
null
zurück, wenn nichts ausgewählt ist (ist es keine leere Liste ...) FileChooser chooser = new FileChooser();
File file = chooser.showSaveDialog(this.stage);
System.out.println("file=" + file);
** Ausführungsergebnis **
Konsolenausgabe
file=C:\Users\Public\hoge
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 **
Konsolenausgabe
directory=C:\Users\Public\Downloads
Referenz
Aussehen
Konstruktion
** Größeneinstellung jedes vertikalen Elements **
--Verwenden Sie VBox
, um vertikal mit der gleichen Breite anzuordnen
HBox
, wenn Sie nebeneinander auf derselben Höhe aufstellen möchtenRecommended Posts