添加到 JavaFX 中的 HBox 时如何滑动节点?
How to slide the node when added to an HBox in JavaFX?
我正在创建一个包含 2 或 3 个 children 的 HBox
面板。第一个 child 是一个带有图标的 VBox
并停留在屏幕的左侧,当我将鼠标悬停在 VBox
(第一个 child)我想添加我的第二个 child 是带有按钮的 VBox
。我的第三个 child 是支持我的内容的 AnchorPane
。
我的问题是,如何使用过渡幻灯片(从左到右)将我的第二个 VBox
添加到 HBox
?
隐藏我的第二个 child(VBox
带有按钮)的最终结果是增加我第三个 child 的宽度内容(内容 AnchorPane
);
示例代码
public class Test extends Application {
@Override
public void start(Stage primaryStage) {
HBox root = new HBox();
Scene scene = new Scene(root, 300, 250);
VBox c1 = new VBox();
ImageView i1 = new ImageView(new Image(getClass().getResourceAsStream("home/home.png")));
ImageView i2 = new ImageView(new Image(getClass().getResourceAsStream("home/contactos.png")));
ImageView i3 = new ImageView(new Image(getClass().getResourceAsStream("home/info.png")));
c1.getChildren().addAll(i1, i2, i3);
VBox c2 = new VBox();
Button b1 = new Button("home opção1");
Button b2 = new Button("home opção2");
c2.getChildren().addAll(b1, b2);
AnchorPane c3 = new AnchorPane();
// Set backgrounds
c1.setBackground(new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)));
c2.setBackground(new Background(new BackgroundFill(Color.GRAY, CornerRadii.EMPTY, Insets.EMPTY)));
c3.setBackground(new Background(new BackgroundFill(Color.rgb(255,255,148), CornerRadii.EMPTY, Insets.EMPTY)));
root.getChildren().addAll(c1, c3);
c1.setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
root.getChildren().add(1, c2);
// Fault transation slide
}
});
c1.setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
root.getChildren().remove(1);
}
});
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
遗憾的是,JavaFX 中没有获得滑动效果的预定义方法。您可以通过 understanding/implementing 裁剪的概念来获得这种效果。在内部,相同的概念用于 ScrollPane 和我们需要剪辑内容的其他控件。
思路是,我们剪辑我们想要滑动的布局,通过时间轴逐渐改变它的值。可以在我的 blog 中找到关于此的更详细的解释。 (我在 2012 年初写了这篇博客,所以代码可能看起来有点过时;)但你应该明白这个概念)
我根据您的要求快速制作了以下演示。这应该可以帮助您了解一些想法。
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.stream.Stream;
public class SlideMenuDemo extends Application {
/* THE ONLY DRAWBACK OF THIS APPROACH IS YOU HAVE TO KNOW THE WIDTH OF THE SUBMENU AHEAD*/
double subMenuWidth = 140;
HBox root;
VBox subMenu;
VBox menuPane;
StackPane subMenuPane;
private Rectangle clipRect;
private Timeline timelineHide;
private Timeline timelineShow;
private final Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.LAVENDER, Color.PINK};
private final String[] shapes = {"cirlce", "triangle", "square", "rectangle"};
@Override
public void start(Stage primaryStage) {
root = new HBox();
Scene scene = new Scene(root, 400, 300);
primaryStage.setTitle("Sliding Demo");
primaryStage.setScene(scene);
primaryStage.show();
// Main menu pane
menuPane = new VBox();
menuPane.setStyle("-fx-background-color:#DDDDDD;");
Stream.of(shapes).forEach(shape -> menuPane.getChildren().addAll(buildMenuButton(shape, Color.BLACK, null)));
// Sub menu pane
subMenu = new VBox();
subMenuPane = new StackPane(subMenu);
subMenuPane.setMinWidth(0);
subMenuPane.setPrefWidth(0);
StackPane subMenuContainer = new StackPane(subMenuPane);
subMenuContainer.setStyle("-fx-background-color:#AAAAAA");
HBox menuBox = new HBox(menuPane, subMenuContainer);
menuBox.setOnMouseExited(e -> hideSubMenu());
// Content Pane
StackPane contentPane = new StackPane(new Text("Hello Slide Checking"));
contentPane.setAlignment(Pos.TOP_LEFT);
contentPane.setPadding(new Insets(15));
HBox.setHgrow(contentPane, Priority.ALWAYS);
contentPane.setStyle("-fx-background-color:#0000FF70,#FFFFFF;-fx-background-insets:0,1;");
root.getChildren().addAll(menuBox, contentPane);
setAnimation();
}
private void hideSubMenu() {
timelineHide.play();
}
private void showSubMenu() {
timelineShow.play();
}
private void setAnimation() {
clipRect = new Rectangle();
clipRect.setWidth(0);
clipRect.heightProperty().bind(root.heightProperty());
clipRect.translateXProperty().set(subMenuWidth);
subMenuPane.setClip(clipRect);
subMenuPane.translateXProperty().set(-subMenuWidth);
/* Event handler hide is finished. */
EventHandler<ActionEvent> onFinished = e -> {
menuPane.getChildren().stream().forEach(n -> n.setStyle(null));
subMenu.getChildren().clear();
};
timelineShow = new Timeline();
timelineHide = new Timeline();
/* Animation for show. */
timelineShow.setCycleCount(1);
final KeyValue kvDwn1a = new KeyValue(clipRect.widthProperty(), subMenuWidth);
final KeyValue kvDwn1b = new KeyValue(subMenuPane.prefWidthProperty(), subMenuWidth);
final KeyValue kvDwn1c = new KeyValue(subMenuPane.minWidthProperty(), subMenuWidth);
final KeyValue kvDwn2 = new KeyValue(clipRect.translateXProperty(), 0);
final KeyValue kvDwn3 = new KeyValue(subMenuPane.translateXProperty(), 0);
final KeyFrame kfDwn = new KeyFrame(Duration.millis(200), kvDwn1a, kvDwn1b, kvDwn1c, kvDwn2, kvDwn3);
timelineShow.getKeyFrames().add(kfDwn);
/* Animation for hide. */
timelineHide.setCycleCount(1);
final KeyValue kvUp1a = new KeyValue(clipRect.widthProperty(), 0);
final KeyValue kvUp1b = new KeyValue(subMenuPane.prefWidthProperty(), 0);
final KeyValue kvUp1c = new KeyValue(subMenuPane.minWidthProperty(), 0);
final KeyValue kvUp2 = new KeyValue(clipRect.translateXProperty(), subMenuWidth);
final KeyValue kvUp3 = new KeyValue(subMenuPane.translateXProperty(), -subMenuWidth);
final KeyFrame kfUp = new KeyFrame(Duration.millis(200), onFinished, kvUp1a, kvUp1b, kvUp1c, kvUp2, kvUp3);
timelineHide.getKeyFrames().add(kfUp);
}
private StackPane buildMenuButton(String type, Color color, String text) {
double size = 50;
double sSize = (size / 5) * 4;
double hSize = sSize / 2;
StackPane menuButton = new StackPane();
menuButton.setPadding(new Insets(0, 5, 0, 5));
menuButton.setMaxHeight(size);
menuButton.setMinHeight(size);
Node shape = null;
switch (type) {
case "triangle":
StackPane s = new StackPane();
s.setPrefSize(sSize, sSize);
s.setMaxSize(sSize, sSize);
s.setBackground(new Background(new BackgroundFill(color, CornerRadii.EMPTY, Insets.EMPTY)));
s.setStyle("-fx-shape:\"M0 1 L1 1 L.5 0 Z\";");
s.setPadding(new Insets(hSize));
shape = s;
break;
case "square":
shape = new Rectangle(sSize, sSize, color);
break;
case "rectangle":
shape = new Rectangle(sSize, hSize, color);
break;
default:
shape = new Circle(hSize, color);
break;
}
HBox hb = new HBox(shape);
hb.setAlignment(Pos.CENTER_LEFT);
if (text != null) {
hb.setSpacing(10);
hb.getChildren().add(new Label(text));
}
menuButton.getChildren().add(hb);
if (text == null) {
// Main menu button
menuButton.setOnMouseEntered(e -> {
menuPane.getChildren().stream().forEach(n -> n.setStyle(null));
subMenu.getChildren().clear();
menuButton.setStyle("-fx-background-color:#AAAAAA;");
Stream.of(colors).forEach(c -> subMenu.getChildren().addAll(buildMenuButton(type, c, c.toString())));
if (subMenuPane.getWidth() == 0) {
showSubMenu();
}
});
} else {
// Sub menu button
menuButton.setPrefWidth(subMenuWidth);
menuButton.setMinWidth(subMenuWidth);
menuButton.setOnMouseEntered(e -> menuButton.setStyle("-fx-background-color:#777777;"));
menuButton.setOnMouseExited(e -> menuButton.setStyle(null));
}
return menuButton;
}
public static void main(String[] args) {
launch(args);
}
}
我正在创建一个包含 2 或 3 个 children 的 HBox
面板。第一个 child 是一个带有图标的 VBox
并停留在屏幕的左侧,当我将鼠标悬停在 VBox
(第一个 child)我想添加我的第二个 child 是带有按钮的 VBox
。我的第三个 child 是支持我的内容的 AnchorPane
。
我的问题是,如何使用过渡幻灯片(从左到右)将我的第二个 VBox
添加到 HBox
?
隐藏我的第二个 child(VBox
带有按钮)的最终结果是增加我第三个 child 的宽度内容(内容 AnchorPane
);
示例代码
public class Test extends Application {
@Override
public void start(Stage primaryStage) {
HBox root = new HBox();
Scene scene = new Scene(root, 300, 250);
VBox c1 = new VBox();
ImageView i1 = new ImageView(new Image(getClass().getResourceAsStream("home/home.png")));
ImageView i2 = new ImageView(new Image(getClass().getResourceAsStream("home/contactos.png")));
ImageView i3 = new ImageView(new Image(getClass().getResourceAsStream("home/info.png")));
c1.getChildren().addAll(i1, i2, i3);
VBox c2 = new VBox();
Button b1 = new Button("home opção1");
Button b2 = new Button("home opção2");
c2.getChildren().addAll(b1, b2);
AnchorPane c3 = new AnchorPane();
// Set backgrounds
c1.setBackground(new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY)));
c2.setBackground(new Background(new BackgroundFill(Color.GRAY, CornerRadii.EMPTY, Insets.EMPTY)));
c3.setBackground(new Background(new BackgroundFill(Color.rgb(255,255,148), CornerRadii.EMPTY, Insets.EMPTY)));
root.getChildren().addAll(c1, c3);
c1.setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
root.getChildren().add(1, c2);
// Fault transation slide
}
});
c1.setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
root.getChildren().remove(1);
}
});
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
遗憾的是,JavaFX 中没有获得滑动效果的预定义方法。您可以通过 understanding/implementing 裁剪的概念来获得这种效果。在内部,相同的概念用于 ScrollPane 和我们需要剪辑内容的其他控件。
思路是,我们剪辑我们想要滑动的布局,通过时间轴逐渐改变它的值。可以在我的 blog 中找到关于此的更详细的解释。 (我在 2012 年初写了这篇博客,所以代码可能看起来有点过时;)但你应该明白这个概念)
我根据您的要求快速制作了以下演示。这应该可以帮助您了解一些想法。
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.stream.Stream;
public class SlideMenuDemo extends Application {
/* THE ONLY DRAWBACK OF THIS APPROACH IS YOU HAVE TO KNOW THE WIDTH OF THE SUBMENU AHEAD*/
double subMenuWidth = 140;
HBox root;
VBox subMenu;
VBox menuPane;
StackPane subMenuPane;
private Rectangle clipRect;
private Timeline timelineHide;
private Timeline timelineShow;
private final Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.LAVENDER, Color.PINK};
private final String[] shapes = {"cirlce", "triangle", "square", "rectangle"};
@Override
public void start(Stage primaryStage) {
root = new HBox();
Scene scene = new Scene(root, 400, 300);
primaryStage.setTitle("Sliding Demo");
primaryStage.setScene(scene);
primaryStage.show();
// Main menu pane
menuPane = new VBox();
menuPane.setStyle("-fx-background-color:#DDDDDD;");
Stream.of(shapes).forEach(shape -> menuPane.getChildren().addAll(buildMenuButton(shape, Color.BLACK, null)));
// Sub menu pane
subMenu = new VBox();
subMenuPane = new StackPane(subMenu);
subMenuPane.setMinWidth(0);
subMenuPane.setPrefWidth(0);
StackPane subMenuContainer = new StackPane(subMenuPane);
subMenuContainer.setStyle("-fx-background-color:#AAAAAA");
HBox menuBox = new HBox(menuPane, subMenuContainer);
menuBox.setOnMouseExited(e -> hideSubMenu());
// Content Pane
StackPane contentPane = new StackPane(new Text("Hello Slide Checking"));
contentPane.setAlignment(Pos.TOP_LEFT);
contentPane.setPadding(new Insets(15));
HBox.setHgrow(contentPane, Priority.ALWAYS);
contentPane.setStyle("-fx-background-color:#0000FF70,#FFFFFF;-fx-background-insets:0,1;");
root.getChildren().addAll(menuBox, contentPane);
setAnimation();
}
private void hideSubMenu() {
timelineHide.play();
}
private void showSubMenu() {
timelineShow.play();
}
private void setAnimation() {
clipRect = new Rectangle();
clipRect.setWidth(0);
clipRect.heightProperty().bind(root.heightProperty());
clipRect.translateXProperty().set(subMenuWidth);
subMenuPane.setClip(clipRect);
subMenuPane.translateXProperty().set(-subMenuWidth);
/* Event handler hide is finished. */
EventHandler<ActionEvent> onFinished = e -> {
menuPane.getChildren().stream().forEach(n -> n.setStyle(null));
subMenu.getChildren().clear();
};
timelineShow = new Timeline();
timelineHide = new Timeline();
/* Animation for show. */
timelineShow.setCycleCount(1);
final KeyValue kvDwn1a = new KeyValue(clipRect.widthProperty(), subMenuWidth);
final KeyValue kvDwn1b = new KeyValue(subMenuPane.prefWidthProperty(), subMenuWidth);
final KeyValue kvDwn1c = new KeyValue(subMenuPane.minWidthProperty(), subMenuWidth);
final KeyValue kvDwn2 = new KeyValue(clipRect.translateXProperty(), 0);
final KeyValue kvDwn3 = new KeyValue(subMenuPane.translateXProperty(), 0);
final KeyFrame kfDwn = new KeyFrame(Duration.millis(200), kvDwn1a, kvDwn1b, kvDwn1c, kvDwn2, kvDwn3);
timelineShow.getKeyFrames().add(kfDwn);
/* Animation for hide. */
timelineHide.setCycleCount(1);
final KeyValue kvUp1a = new KeyValue(clipRect.widthProperty(), 0);
final KeyValue kvUp1b = new KeyValue(subMenuPane.prefWidthProperty(), 0);
final KeyValue kvUp1c = new KeyValue(subMenuPane.minWidthProperty(), 0);
final KeyValue kvUp2 = new KeyValue(clipRect.translateXProperty(), subMenuWidth);
final KeyValue kvUp3 = new KeyValue(subMenuPane.translateXProperty(), -subMenuWidth);
final KeyFrame kfUp = new KeyFrame(Duration.millis(200), onFinished, kvUp1a, kvUp1b, kvUp1c, kvUp2, kvUp3);
timelineHide.getKeyFrames().add(kfUp);
}
private StackPane buildMenuButton(String type, Color color, String text) {
double size = 50;
double sSize = (size / 5) * 4;
double hSize = sSize / 2;
StackPane menuButton = new StackPane();
menuButton.setPadding(new Insets(0, 5, 0, 5));
menuButton.setMaxHeight(size);
menuButton.setMinHeight(size);
Node shape = null;
switch (type) {
case "triangle":
StackPane s = new StackPane();
s.setPrefSize(sSize, sSize);
s.setMaxSize(sSize, sSize);
s.setBackground(new Background(new BackgroundFill(color, CornerRadii.EMPTY, Insets.EMPTY)));
s.setStyle("-fx-shape:\"M0 1 L1 1 L.5 0 Z\";");
s.setPadding(new Insets(hSize));
shape = s;
break;
case "square":
shape = new Rectangle(sSize, sSize, color);
break;
case "rectangle":
shape = new Rectangle(sSize, hSize, color);
break;
default:
shape = new Circle(hSize, color);
break;
}
HBox hb = new HBox(shape);
hb.setAlignment(Pos.CENTER_LEFT);
if (text != null) {
hb.setSpacing(10);
hb.getChildren().add(new Label(text));
}
menuButton.getChildren().add(hb);
if (text == null) {
// Main menu button
menuButton.setOnMouseEntered(e -> {
menuPane.getChildren().stream().forEach(n -> n.setStyle(null));
subMenu.getChildren().clear();
menuButton.setStyle("-fx-background-color:#AAAAAA;");
Stream.of(colors).forEach(c -> subMenu.getChildren().addAll(buildMenuButton(type, c, c.toString())));
if (subMenuPane.getWidth() == 0) {
showSubMenu();
}
});
} else {
// Sub menu button
menuButton.setPrefWidth(subMenuWidth);
menuButton.setMinWidth(subMenuWidth);
menuButton.setOnMouseEntered(e -> menuButton.setStyle("-fx-background-color:#777777;"));
menuButton.setOnMouseExited(e -> menuButton.setStyle(null));
}
return menuButton;
}
public static void main(String[] args) {
launch(args);
}
}