首页 > 解决方案 > JavaFX:如何在具有阴影效果的舞台上正确滑动窗格?

问题描述

我在“ JavaFX:如何为窗格(透明舞台内)创建动画效果幻灯片”中看到了这个问题。

而且我不明白 John Astralidis 发布的最后一条评论的部分代码。它似乎解决了我的问题。我想滑动带有阴影阶段的窗格。现在我的问题是幻灯片动画在我的可视根窗格绑定之外播放,它只是在舞台(或实际根窗格)绑定的情况下播放。

我的视觉根窗格是实际根窗格的子窗格,我使用填充和 Corlor.TRANSPARENT 设置实际根窗格以实现我的视觉根窗格阴影效果。

幻灯片图像

这是我从 John Astralidis 和 Felipe Guizar Diaz 修改的代码。起始代码:

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
    stage.initStyle(StageStyle.TRANSPARENT);
    Scene scene = new Scene(root);//
    stage.setScene(scene);
    stage.show();
}
public static void main(String[] args) {
    launch(args);
}

FXMLDocument.fxml:

<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:id="anchorPane" prefWidth="500" prefHeight="500" style="-fx-background-color: transparent;"   
        fx:controller="leftslidemenusample.FXMLDocumentController">
<children>
    <ToolBar AnchorPane.topAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" minHeight="56.0"   >
           <Button text="menu" fx:id="menu"  />
    </ToolBar>
    <StackPane fx:id="mainContent"  style="-fx-background-color:rgba(0,0,0,0.30)" AnchorPane.bottomAnchor="0.0" AnchorPane.topAnchor="56.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"    >
        <children>
        </children>
    </StackPane>
    <AnchorPane fx:id="navList" style="-fx-background-color:white" AnchorPane.topAnchor="56.0" AnchorPane.bottomAnchor="0.0" prefWidth="180.0" translateX="-180"   >
        <children>
            <Label text="left side menu"/>
        </children>
    </AnchorPane>
</children>

和控制器 FXMLDocumentController.java

public class FXMLDocumentController implements Initializable {
@FXML
private AnchorPane anchorPane;
@FXML
private Button menu;
@FXML
private AnchorPane navList;

private double shadowSize = 15;

@Override
public void initialize(URL url, ResourceBundle rb) {

    Rectangle rectangle = new Rectangle(500,500);

    anchorPane.setClip(rectangle);
    anchorPane.getChildren().add(setupShadowPane());

    prepareSlideMenuAnimation();
}
private Pane setupShadowPane() {
    Pane shadowPane = new Pane();
    shadowPane.setPrefHeight(500);
    shadowPane.setPrefWidth(500);
    shadowPane.setStyle(
            "-fx-background-color: RED;" +
                    "-fx-effect: dropshadow(gaussian, black, " + 20 + ", 0, 0, 0);" +
                    "-fx-background-insets: " + shadowSize + ";"
    );

    Rectangle innerBounds = new Rectangle();
    Rectangle outerBounds = new Rectangle();
    shadowPane.layoutBoundsProperty().addListener((observable, oldBounds, newBounds) -> {
        System.out.println(newBounds.getWidth());
        innerBounds.relocate(newBounds.getMinX() + shadowSize, newBounds.getMinY() + shadowSize);
        innerBounds.setWidth(newBounds.getWidth() - shadowSize * 2);
        innerBounds.setHeight(newBounds.getHeight() - shadowSize * 2);
        outerBounds.setWidth(newBounds.getWidth());
        outerBounds.setHeight(newBounds.getHeight());

        Shape clip = Shape.subtract(outerBounds, innerBounds);
        shadowPane.setClip(clip);
    });

    return shadowPane;
}
private void prepareSlideMenuAnimation() {
    TranslateTransition openNav=new TranslateTransition(new Duration(350), navList);
    openNav.setToX(0);
    TranslateTransition closeNav=new TranslateTransition(new Duration(350), navList);
    menu.setOnAction((ActionEvent evt)->{
        if(navList.getTranslateX()!=0){
            openNav.play();
        }else{
            closeNav.setToX(-(navList.getWidth()));
            closeNav.play();
        }
    });
}

}

标签: javafxslideshadowstage

解决方案


最后,我完成了。我认为 John Astralidis 的回答是错误的。但是谢谢。关键是:

  1. 使用一个 StackPane 作为实际根窗格,然后将可视根窗格和阴影窗格添加到实际根窗格中作为 StackPane 的子窗格。可视根窗格是需要添加阴影效果窗格的。
  2. 用芯片设置可视根窗格,使其外部布局显示阴影窗格的阴影效果;
  3. 设置带有芯片的阴影窗格,该芯片包含其内部布局以显示可视根窗格的内容。

希望我的英语不好回答可以帮助某人。我在下面发布了我的整个演示代码:

入门类--FXApplication.java

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;
import javafx.stage.StageStyle;

public class FXApplication extends Application {

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
    stage.initStyle(StageStyle.TRANSPARENT);
    Scene scene = new Scene(root);//
    scene.setFill(Color.TRANSPARENT);
    stage.setScene(scene);
    stage.show();
}

public static void main(String[] args) {
    launch(args);
}
}

布局FXML文件--FXMLDocument.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.*?>

<StackPane xmlns:fx="http://javafx.com/fxml/1" fx:id="pane" prefWidth="500" prefHeight="500" style="-fx-background-color: transparent;"
        fx:controller="FXMLDocumentController">
<children>
    <AnchorPane fx:id="anchorPane" prefWidth="500" prefHeight="500" style="-fx-background-color: WHITE;">
        <children>
            <ToolBar AnchorPane.topAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" minHeight="56.0"   >
                <Button text="menu" fx:id="menu"  />
            </ToolBar>
            <StackPane fx:id="mainContent"  style="-fx-background-color:rgba(0,0,0,0.30)" AnchorPane.bottomAnchor="0.0" AnchorPane.topAnchor="56.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"    >
                <children>
                </children>
            </StackPane>
            <AnchorPane fx:id="navList" style="-fx-background-color:white" AnchorPane.topAnchor="56.0" AnchorPane.bottomAnchor="0.0" prefWidth="180.0" translateX="-180"   >
                <children>
                    <Label text="left side menu"/>
                </children>
            </AnchorPane>
        </children>
    </AnchorPane>
</children>

控制器类--FXMLDocumentController.java

import javafx.animation.TranslateTransition;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.util.Duration;
import java.net.URL;
import java.util.ResourceBundle;

public class FXMLDocumentController implements Initializable {

@FXML
private AnchorPane anchorPane;
@FXML
private StackPane pane;
@FXML
private Button menu;
@FXML
private AnchorPane navList;
private double shadowSize = 10;

@Override
public void initialize(URL url, ResourceBundle rb) {

    Rectangle rectangle = new Rectangle(480,480);
    rectangle.relocate(10,10);
    anchorPane.setClip(rectangle);
    pane.getChildren().add(setupShadowPane());

    prepareSlideMenuAnimation();
}
private Pane setupShadowPane() {
    Pane shadowPane = new Pane();
    shadowPane.setPrefHeight(500);
    shadowPane.setPrefWidth(500);
    shadowPane.setStyle(
            "-fx-background-color: RED;" +
                    "-fx-effect: dropshadow(gaussian, black, " + 20 + ", 0, 0, 0);" +
                    "-fx-background-insets: " + shadowSize + ";"
    );

    Rectangle innerBounds = new Rectangle();
    Rectangle outerBounds = new Rectangle();
    shadowPane.layoutBoundsProperty().addListener((observable, oldBounds, newBounds) -> {
        innerBounds.relocate(newBounds.getMinX() + shadowSize, newBounds.getMinY() + shadowSize);
        innerBounds.setWidth(newBounds.getWidth() - shadowSize * 2);
        innerBounds.setHeight(newBounds.getHeight() - shadowSize * 2);
        outerBounds.setWidth(newBounds.getWidth());
        outerBounds.setHeight(newBounds.getHeight());

        Shape clip = Shape.subtract(outerBounds, innerBounds);
        shadowPane.setClip(clip);
    });

    return shadowPane;
}
private void prepareSlideMenuAnimation() {
    TranslateTransition openNav=new TranslateTransition(new Duration(350), navList);
    openNav.setToX(0 + shadowSize);
    TranslateTransition closeNav=new TranslateTransition(new Duration(350), navList);
    menu.setOnAction((ActionEvent evt)->{
        if(navList.getTranslateX()!=0+shadowSize){
            openNav.play();
        }else{
            closeNav.setToX(-(navList.getWidth())+shadowSize);
            closeNav.play();
        }
    });
}

}

以及下图:

在此处输入图像描述

在此处输入图像描述


推荐阅读