T.M. SoftStudio

feci quod potui, faciant meliora potentes

JavaFX: Создание пользовательских компонентов с помощью Scene Builder

 

Составные пользовательские компоненты 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);

}

}