T.M. SoftStudio

feci quod potui, faciant meliora potentes

JavaFX: Создание пользовательских GUI-компонентов

 

Платформа JavaFX предлагает большой набор компонентов для создания GUI-интерфейса. Однако этого может оказаться не достаточно. Например, может понадобиться GUI-компонент, выглядящий как 3D графический объект и одновременно выполняющий функцию элемента контроля GUI-интерфейса.

 

В качестве примера рассмотрим 3D-объект кубической формы, выполняющий функцию элемента меню.

Такого рода элемент будет являться составным компонентом, поэтому его класс должен расширять класс javafx.scene.Parent, являющийся базовым классом узлов графа сцены, имеющих дочерние узлы.

Ближайшая реализация абстрактного класса Parent — это класс javafx.scene.Group, который позволяет свободную компоновку своих дочерних компонентов и при этом трансформации, применяемые к узлу Group, применяются ко всем его дочерним узлам. Поэтому класс нашего пользовательского компонента будет расширять класс Group.

3D-объект кубической формы можно сформировать из цветных прямоугольников, которые будут являться дочерними компонентами компонента Group. На фасадном прямоугольнике можно разместить гиперссылку, которая будет активировать контрольные функции компонента. Целиком ко всему компоненту можно применять различные трансформации, например анимацию вращения.

Ниже приведен код 3D-компонента с гиперссылкой:

import javafx.animation.Animation;

import javafx.animation.KeyFrame;

import javafx.animation.KeyValue;

import javafx.animation.Timeline;

import javafx.event.EventHandler;

import javafx.scene.Group;

import javafx.scene.control.Hyperlink;

import javafx.scene.control.HyperlinkBuilder;

import javafx.scene.input.MouseEvent;

import javafx.scene.layout.StackPane;

import javafx.scene.paint.Color;

import javafx.scene.shape.Rectangle;

import javafx.scene.shape.RectangleBuilder;

import javafx.scene.text.Font;

import javafx.scene.transform.Rotate;

import javafx.util.Duration;

public class MenuContainer extends Group {

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(double size, Color colorContainer, double shade, String label,

Color colorLabel, Font font) {

rx.setAngle(15);

ry.setAngle(15);

rz.setAngle(0);

this.getTransforms().addAll(rz, ry, rx);

final Group group=this;

//

final Rectangle backFace = RectangleBuilder.create() // back face

.width(size*2).height(size)

.fill(colorContainer.deriveColor(0.0, 1.0, (1 - 0.3*shade), 1.0))

.translateX(-0.5*size)

.translateY(-0.5*size)

.translateZ(0.5*size)

.build();

//

final Rectangle bottomFace = RectangleBuilder.create() // bottom face

.width(size*2).height(size)

.fill(colorContainer.deriveColor(0.0, 1.0, (1 - 0.3*shade), 1.0))

.translateX(-0.5*size)

.translateY(0)

.rotationAxis(Rotate.X_AXIS)

.rotate(90)

.build();

//

final Rectangle rightFace = RectangleBuilder.create() // right face

.width(size).height(size)

.fill(colorContainer.deriveColor(0.0, 1.0, (1 - 0.3*shade), 1.0))

.translateX(1*size)

.translateY(-0.5*size)

.rotationAxis(Rotate.Y_AXIS)

.rotate(90)

.build();

//

final Rectangle leftFace = RectangleBuilder.create() // left face

.width(size).height(size)

.fill(colorContainer.deriveColor(0.0, 1.0, (1 - 0.3*shade), 1.0))

.translateX(-1*size)

.translateY(-0.5*size)

.rotationAxis(Rotate.Y_AXIS)

.rotate(90)

.build();

//

final Rectangle topFace = RectangleBuilder.create() // top face

.width(size*2).height(size)

.fill(colorContainer.deriveColor(0.0, 1.0, (1 - 0.2*shade), 1.0))

.translateX(-0.5*size)

.translateY(-1*size)

.rotationAxis(Rotate.X_AXIS)

.rotate(90)

.build();

//

Hyperlink link = HyperlinkBuilder.create()

.text(label)

.textFill(colorLabel)

.font(font)

.build();

final StackPane face = new StackPane();

face.getChildren().addAll(RectangleBuilder.create() // face

.width(size*2).height(size)

.fill(colorContainer)

.build(),

link

);

face.setTranslateX(-0.5*size);

face.setTranslateY(-0.5*size);

face.setTranslateZ(-0.5*size);

link.setOnMouseClicked(new EventHandler<MouseEvent>() {

@Override

public void handle(MouseEvent event) {

System.out.println("Link clicked");

} });

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);

}

});

} });

//

getChildren().addAll(backFace,bottomFace,rightFace,leftFace,topFace,face);

}

}

Использование пользовательского компонента:

import javafx.application.Application;

import javafx.scene.Group;

import javafx.scene.Scene;

import javafx.scene.paint.Color;

import javafx.scene.text.Font;

import javafx.stage.Stage;

public class JavaFXOGWeb extends Application {

@Override

public void start(Stage primaryStage) {

MenuContainer cmHome = new MenuContainer(50,Color.BLUE,2, "Home", Color.WHITE, Font.font("Georgia", 18));

cmHome.setLayoutX(50);

cmHome.setLayoutY(50);

MenuContainer cmServices = new MenuContainer(50,Color.BLUE,2, "Services", Color.WHITE, Font.font("Georgia", 18));

cmServices.setLayoutX(160);

cmServices.setLayoutY(50);

MenuContainer cmBlog = new MenuContainer(50,Color.BLUE,2, "Blog", Color.WHITE, Font.font("Georgia", 18));

cmBlog.setLayoutX(270);

cmBlog.setLayoutY(50);

MenuContainer cmContacts = new MenuContainer(50,Color.BLUE,2, "Contacts", Color.WHITE, Font.font("Georgia", 18));

cmContacts.setLayoutX(380);

cmContacts.setLayoutY(50);

Group root = new Group();

root.getChildren().addAll(cmHome,cmServices, cmBlog, cmContacts);

Scene scene = new Scene(root, 800, 600);

scene.setFill(Color.BLACK);

primaryStage.setScene(scene);

primaryStage.show();

}

public static void main(String[] args) {

launch(args);

}

}