如何更改所有屏幕上的背景图像并保留更改

时间:2015-04-17 04:20:45

标签: java javafx background-image fxml

重要信息和方法

所以我有这种方法(目前还不完整),其唯一目的是改变每个屏幕中的背景图像。这是执行此操作的方法。

if(optionButton1.isArmed())
{
    optionButton1.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground1"));
}
else if(optionButton2.isArmed())
{
    optionButton2.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground2"));
}
else
{
    optionButton3.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground3"));
}

那么此代码目前所做的是检查按下并释放了什么按钮,并将旧ID更改为新ID。一旦它将其更改为新的id,它将更改FXML文件中的id,然后FXML文件将进入我的css文件并查找与新id匹配的id。

现在这个FXML变量位于我的一个控制器类( OptionscreenController )中,变量的名称是Optionmenu。它看起来像我的控制器类

@FXML private StackPane Optionmenu;

这意味着optionmenu是此方法更改的FXML文件的主根。

我的挑战之一是找到一种方法将所有节点或根连接到此类,并尽可能更改这些节点的ID。

以下是我尝试解决此问题的方法:

   try
    {
        FXMLLoader myLoader = new FXMLLoader(getClass().getResource(MillionaireTriviaGame.MAIN));
        myLoader.load();
        mainMenu = myLoader.getRoot();
        mainMenu.setId("BlueBackground2")
    }
    catch (IOException ex)
    {
        Logger.getLogger(OptionscreenController.class.getName()).log(Level.SEVERE, null, ex);
    } 

我想要做的是在主要文件旁边加载另一个FXML文件的FXML文件,使用getRoot()在FXML文件中获取对象,将其添加到变量中具有相同的 fx:id ,并使用 setId 更改其旧ID。

现在有两个问题:首先,这样做会调用初始化的override方法,无论什么(每个控制器都必须有这个方法)。所以我说,好吧所以我不会使用FXMLLoader.load()。我马上直接去getRoot()。事实证明它将FXML变量设置为null。

我的最后一项挑战是在用户从屏幕切换到屏幕时保持对每个背景所做的更改。

这些是我目前面临的挑战。


代码时间

我认为您需要看到的第一件事是我如何从屏幕转换到屏幕。会有很多代码可供查看,如果可以,请耐心等待。

ScreenNavigator类 - 用于加载和设置屏幕

package millionairetriviagame;

import java.io.IOException;
import java.util.HashMap;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;

public class ScreenNavigator extends StackPane
{

    private HashMap<String, Node> screens = new HashMap<>();

    public ScreenNavigator()
    {
        super();
    }

    public void addScreen(String name, Node screen)
    {
        screens.put(name, screen);
    }

    public Node getScreen(String name)
    {
        return screens.get(name);
    }

    public boolean loadScreen(String name, String resource)
    {
        try
        {
            FXMLLoader myLoader = new FXMLLoader(getClass().getResource(resource));
            Parent loadscreen = myLoader.load();
            ControllingScreens ScreenController = myLoader.getController();
            ScreenController.setScreenParent(this);
            addScreen(name, loadscreen);
            return true;
        }
        catch (IOException e)
        {
            System.out.println(e.getMessage());
            return false;
        }
    }

    public boolean setScreen(String name)
    {
        if (screens.get(name) != null)
        {
            if (!getChildren().isEmpty())
            {

                Timeline transition = new Timeline(new KeyFrame(Duration.seconds(0.5), (ActionEvent event) ->
                {
                    getChildren().clear();
                    getChildren().add(screens.get(name));
                }));

                transition.play();
                MillionaireTriviaGame.fade(true);
            }
            else
            {
                getChildren().add(screens.get(name));
                MillionaireTriviaGame.fade(false);
            }
            return true;
        }
        else
        {
            Alert alert = new Alert(AlertType.ERROR);
            alert.setTitle("Error Dialog");
            alert.setHeaderText(null);
            alert.setContentText("The screen wasn't able to load.");

            alert.showAndWait();
            return false;
        }
    }
}

接下来是使用此类的主类。

主要类

package millionairetriviagame;

import java.util.Optional;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class MillionaireTriviaGame extends Application
{
    private static final Rectangle fillRectangle = new Rectangle();
    public static final String MAINSCREENID = "main";
    public static final String MAIN = "MenulayoutFXML.fxml";
    public static final String OPTIONSCREENID = "option";
    public static final String OPTION = "Optionscreen.fxml";

    @Override
    public void start(Stage menuStage) throws Exception
    {
        ScreenNavigator controller = new ScreenNavigator();
        controller.loadScreen(MillionaireTriviaGame.MAINSCREENID, MillionaireTriviaGame.MAIN);
        controller.setScreen(MillionaireTriviaGame.MAINSCREENID);

        StackPane root = new StackPane();
        root.getChildren().addAll(controller, fillRectangle);
        root.setAlignment(Pos.TOP_CENTER);

        Scene scene = new Scene(root, 1366, 768);
        fillRectangle.setWidth(scene.getWidth());
        fillRectangle.setHeight(scene.getHeight());
        fillRectangle.setDisable(true);
        menuStage.setScene(scene);

        menuStage.setOnCloseRequest(e ->
        {
            Alert exitConfirmation = new Alert(Alert.AlertType.CONFIRMATION, "Are you sure you want to exit this application?");
            exitConfirmation.setTitle("Exit Application");
            exitConfirmation.setHeaderText("Confirm Exit");
            Optional<ButtonType> choice = exitConfirmation.showAndWait();
            if (choice.get() == ButtonType.OK)
            {
                menuStage.close();
            }
            else
            {
                e.consume();
            }
        });

        menuStage.setTitle("Let's play who wants to be a millionaire");
        menuStage.getIcons().add(new Image(getClass().getResource("/millionairetriviagame/ImageFiles/gameIcon.png").toExternalForm()));
        menuStage.setFullScreen(true);
        menuStage.show();
    }

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

    public static void fade(boolean inOut)
    {
        FadeTransition ft = new FadeTransition(Duration.seconds(5), fillRectangle);
        ft.setFromValue(1);
        ft.setToValue(0);
        if (inOut)
        {
            ft.setDuration(Duration.seconds(0.5));
            ft.setFromValue(0);
            ft.setToValue(1);
            ft.setAutoReverse(true);
            ft.setCycleCount(2);
        }
        ft.play();
    }
}

接下来是控制器类,负责更改所有屏幕的背景图像。

OptionscreenController

package millionairetriviagame;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

public class OptionscreenController implements Initializable, ControllingScreens
{
    private ScreenNavigator controller;
    private MediaPlayer optionMenuPlayer;
    @FXML private Button backToMain;
    private BooleanProperty isDisabled;
    @FXML private StackPane Optionmenu;
    @FXML private Button optionButton1;
    @FXML private Button optionButton2;
    @FXML private Button optionButton3;

    @Override
    public void initialize(URL url, ResourceBundle rb)
    {
        configureProperties();
        playSong();
    }

    private void configureProperties()
    {
        isDisabled = new SimpleBooleanProperty();
        backToMain.disableProperty().bind(isDisabled);
    }

    @Override
    public void setScreenParent(ScreenNavigator parentScreen)
    {
        controller = parentScreen;
    }

    private void playSong()
    {
        Media optionIntroTheme = new Media(getClass().getResource("/millionairetriviagame/AudioFiles/OptionMenuMusic.mp3").toExternalForm());
        optionMenuPlayer = new MediaPlayer(optionIntroTheme);
        optionMenuPlayer.setAutoPlay(true);
        optionMenuPlayer.setVolume(0.1);
        optionMenuPlayer.setCycleCount(MediaPlayer.INDEFINITE);
    }

    @FXML private void changeBackgroundScreen() // This is the method where it all happens.
    {
        if(optionButton1.isArmed())
        {
            optionButton1.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground1"));
        }
        else if(optionButton2.isArmed())
        {
            optionButton2.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground2"));
        }
        else
        {
            optionButton3.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground3"));
        }
    }

    @FXML private void goToTheMainMenu()
    {
        isDisabled.setValue(true);
        optionMenuPlayer.stop();
        controller.loadScreen(MillionaireTriviaGame.MAINSCREENID, MillionaireTriviaGame.MAIN);
        controller.setScreen(MillionaireTriviaGame.MAINSCREENID);
    }
}

控制显示哪个屏幕的界面(每个控制器都有此方法)。

package millionairetriviagame;

public interface ControllingScreens 
{
     public void setScreenParent(ScreenNavigator parentScreen);
}

1 个答案:

答案 0 :(得分:1)

<强>解决方案

这是我提出的一个解决方案:

在我的screenNavigator类中,我添加了这个方法:

private String getBackgroundId()
{
    BufferedReader br = null;
    String backgroundId = "";

    try
    {
        br = new BufferedReader(new FileReader("Background.txt"));
        backgroundId = br.readLine();
    }
    catch (IOException e)
    {
        System.out.println(e.getMessage());
    }
    finally
    {
        try
        {
            if (br != null)
            {
                br.close();
            }
        }
        catch (IOException ex)
        {
           System.out.println(ex.getMessage());
        }
    }

    return backgroundId;
}

然后在同一个类中,我向loadScreen方法添加了两行代码

 mainMenu = myLoader.getRoot();
 mainMenu.setId(getBackgroundId());

以下是覆盖文件的方法。

private void changeBackgroundId(String backgroundId)
{
    BufferedWriter bw = null;

    try
    {
        bw = new BufferedWriter(new FileWriter("Background.txt", false));
        bw.write(backgroundId);
    }
    catch (IOException e)
    {
        System.out.println(e.getMessage());
    }
    finally
    {
        try
        {
            if (bw != null)
            {
                bw.close();
            }
        }
        catch (IOException ex)
        {
           System.out.println(ex.getMessage());
        }
    }

}

以下是changeBackgroundScreen现在的外观

@FXML private void changeBackgroundScreen()
{
    if(optionButton1.isArmed())
    {
        optionButton1.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground1"));
        changeBackgroundId("BlueBackground1");
    }
    else if(optionButton2.isArmed())
    {
        optionButton2.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground2"));
        changeBackgroundId("BlueBackground2");
    }
    else
    {
        optionButton3.setOnMouseClicked(e-> Optionmenu.setId("BlueBackground3"));
        changeBackgroundId("BlueBackground3");
    }
}

<强>解释

这个解决方案的工作方式是每次我从一个屏幕转换到另一个屏幕时,我将加载backgroundId文件中的唯一一行,这是css文件中的id。一旦用户点击按钮更改背景(查看optionScreenController类),我将写入文件并使用新的Id覆盖旧的Id,以便每个屏幕都将加载新的背景。对我的两个问题来说,这是一个很好的解决方案。如果其他人认为他们可以改进这个解决方案,请做。