Transparent stage/scene loses its transparency aft

2019-09-17 22:39发布

问题:

When I start my application my transparent javafx.stage.Stage shows a half transparent image as expected. But after a second stage is loaded the first stage loses its transparency.

The weird thing is that if the second fxml file ("MainScreen.fxml") doesn't contains any components like buttons or text fields, the background stays transparent.

I'm using JavaFX with JavaSE-1.8 in eclipse neon.2 on macOS Sierra.

Main class

package customPackage.main;

import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;

public class Main extends Application implements Runnable {

    private Stage primaryStage;
    private Stage stage;

    private Controller launchController;

    @Override
    public void start(Stage primaryStage) {
        this.primaryStage = primaryStage;

        launchController = new Controller("LaunchScreen.fxml");
        Scene launchScene = new Scene(launchController);

        launchScene.setFill(Color.TRANSPARENT);

        primaryStage.initStyle(StageStyle.TRANSPARENT);
        primaryStage.setAlwaysOnTop(true);
        primaryStage.setResizable(false);
        primaryStage.setScene(launchScene);
        primaryStage.show();

        Thread thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        try {
            Thread.sleep(3000);
            // simulate work
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Controller controller = new Controller("MainScreen.fxml");
        Scene scene = new Scene(controller);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                stage = new Stage();
                stage.initStyle(StageStyle.UNDECORATED);
                stage.setResizable(false);
                stage.setScene(scene);
                stage.show();
            }
        });
    }
}

Controller class

package customPackage.main;

import java.io.IOException;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.AnchorPane;

public class LaunchController extends AnchorPane {

    @FXML
    private ProgressBar bar;

    public LaunchController(String filename) {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(filename));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        try {
            fxmlLoader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FXML File ("LaunchScreen.fxml")

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.effect.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<fx:root fx:id="pane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="326.0" prefWidth="883.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <ImageView fitHeight="326.0" fitWidth="883.0" layoutX="7.0" layoutY="134.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <image>
            <Image url="@http://www.lunapic.com/editor/premade/transparent.gif" />
         </image>
      </ImageView>
   </children>
   <cursor>
      <Cursor fx:constant="DEFAULT" />
   </cursor>
</fx:root>

FXML File ("MainScreen.fxml")

    <?xml version="1.0" encoding="UTF-8"?>

<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<fx:root fx:id="pane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="720.0" prefWidth="1280.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <ImageView fitHeight="720.0" fitWidth="1280.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <image>
            <Image url="@http://i.telegraph.co.uk/multimedia/archive/03589/Wellcome_Image_Awa_3589699k.jpg" />
         </image>
      </ImageView>
      <HBox spacing="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
         <children>
            <Button fx:id="button1" mnemonicParsing="false" onAction="#button1Press" prefHeight="45.0" prefWidth="1000.0" text="Singleplayer" />
            <Button fx:id="button2" mnemonicParsing="false" onAction="#button2Press" prefHeight="45.0" prefWidth="1000.0" text="Multiplayer" />
            <Button fx:id="button3" mnemonicParsing="false" onAction="#button3Press" prefHeight="45.0" prefWidth="1000.0" text="Settings" />
            <Button fx:id="button4" mnemonicParsing="false" onAction="#button4Press" prefHeight="45.0" prefWidth="1000.0" text="Quit" />
         </children>
         <padding>
            <Insets bottom="30.0" left="100.0" right="100.0" top="20.0" />
         </padding>
      </HBox>
      <Region fx:id="region" prefHeight="15.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
   </children>
</fx:root>

Solution (solved by James_D)

I added

.root {
    -fx-background-color: transparent;
}

to the external style sheet and added stylesheets="@application.css" to the root node in the FXML file.

回答1:

The default CSS style sheet for JavaFX, modena, applies a non-transparent color to the background of the root node. That's the color you're seeing when you display your main view.

The reason you don't see this in your first screen, or if you remove the buttons from the main screen, is that the default style sheet is only loaded the first time the Control class (or one of its subclasses) is instantiated. This is done to avoid the overhead of CSS processing for applications not needing it.

To fix, either add style="-fx-background-color: transparent;" to the root node in the FXML file, or add the rule

.root {
    -fx-background-color: transparent ;
}

to the external style sheet.