Составные пользовательские компоненты JavaFX GUI-интерфейса можно создавать путем разработки Java-класса, расширяющего класс javafx.scene.Parent, который является базовым классом узлов графа сцены, имеющих дочерние узлы. При этом класс пользовательского компонента можно адаптировать для использования в FXML-описании графа сцены приложения.
Однако пользовательский JavaFX-компонент можно также создать, разделив его на FXML-описание составных частей компонента и Java-класс контроллер, соединяющий FXML-описание компонента и его логику.
Для создания FXML-описания составных частей компонента удобно использовать инструмент Scene Builder (http://docs.oracle.com/javafx/scenebuilder/1/installation/jsbpub-installation.htm), обеспечивающий визуальное редактирование графа сцены.
В качестве примера рассмотрим использование пользовательского компонента кубической формы с гиперссылкой.
После визуального создания инструментом Scene Builder FXML-описания 3D-компонента, изменим корневой элемент FXML-описания на <fx:root>:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.text.*?>
<fx:root type="javafx.scene.Group" xmlns:fx="http://javafx.com/fxml" >
<children>
<Rectangle fill="DARKBLUE" height="50.0" rotate="90.0" translateX="-25.0" translateY="-50.0" width="100.0">
<rotationAxis>
<Point3D x="1.0" />
</rotationAxis>
</Rectangle>
<Rectangle fill="DARKBLUE" height="50.0" rotate="90.0" translateX="-50.0" translateY="-25.0" width="50.0">
<rotationAxis>
<Point3D y="1.0" />
</rotationAxis>
</Rectangle>
<Rectangle fill="DARKBLUE" height="50.0" rotate="90.0" translateX="50.0" translateY="-25.0" width="50.0">
<rotationAxis>
<Point3D y="1.0" />
</rotationAxis>
</Rectangle>
<Rectangle fill="DARKBLUE" height="50.0" rotate="90.0" translateX="-25.0" width="100.0">
<rotationAxis>
<Point3D x="1.0" />
</rotationAxis>
</Rectangle>
<Rectangle fx:id="backface" fill="DARKBLUE" height="50.0" translateX="-25.0" translateY="-25.0" translateZ="25.0" width="100.0"/>
<StackPane id="StackPane" translateX="-25.0" translateY="-25.0" translateZ="-25.0">
<children>
<Rectangle fill="BLUE" height="50.0" width="100.0" />
<Hyperlink fx:id="link" textFill="WHITE">
<font>
<Font name="Georgia" size="18.0" />
</font>
</Hyperlink>
</children>
</StackPane>
</children>
</fx:root>
Создадим Java-класс, загружающий FXML-описание компонента и определяющий его поведение:
package javafxogwebfxmlscenebuilder;
import java.io.IOException;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.control.Hyperlink;
import javafx.scene.input.MouseEvent;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
public class MenuContainer extends Group{
@FXML private Hyperlink link;
final Rotate rx = new Rotate(0,Rotate.X_AXIS);
final Rotate ry = new Rotate(0,Rotate.Y_AXIS);
final Rotate rz = new Rotate(0,Rotate.Z_AXIS);
public MenuContainer(){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MenuContainer.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
final Group group=this;
rx.setAngle(15);
ry.setAngle(15);
rz.setAngle(0);
this.getTransforms().addAll(rz, ry, rx);
final Timeline animation = new Timeline();
animation.getKeyFrames().addAll(
new KeyFrame(Duration.ZERO, new KeyValue(rx.angleProperty(), 15d)),
new KeyFrame(new Duration(1000), new KeyValue(rx.angleProperty(), 375d))
);
animation.setCycleCount(Animation.INDEFINITE);
group.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
animation.play();
double x= event.getSceneX();
double y = event.getSceneY();
group.setLayoutX(x);
group.setLayoutY(y);
group.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
animation.stop();
rx.angleProperty().set(15);
}
});
} });
}
public String getLabel(){
return link.textProperty().get();
}
public void setLabel(String value){
link.textProperty().setValue(value);
}
}
Теперь созданный компонент можно использовать в FXML-описании графа сцены приложения:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafxogwebfxmlscenebuilder.*?>
<AnchorPane id="AnchorPane" prefHeight="600" prefWidth="800" xmlns:fx="http://javafx.com/fxml" >
<children>
<MenuContainer layoutX="50" layoutY="50" label="Home" />
<MenuContainer layoutX="160" layoutY="50" label="Services" />
<MenuContainer layoutX="270" layoutY="50" label="Blog" />
<MenuContainer layoutX="380" layoutY="50" label="Contacts" />
</children>
</AnchorPane>
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class JavaFXOGWebFXMLSceneBuilder extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("OGWeb.fxml"));
Scene scene = new Scene(root);
scene.setFill(Color.BLACK);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}