当前位置: 首页 > 知识库问答 >
问题:

从控制器JavaFX打开新场景

龙永思
2023-03-14

我正在设计一款跳棋游戏,一旦游戏结束,一个新窗口就会打开,你可以开始一个新游戏,也可以退出。我对JavaFX了解不多,我一直在努力让我的代码正常工作,但我没有成功。。。

我有一个困难,我的电路板没有显示为fxml文件,但它是用Java代码创建的,并放在我的边框窗格的中心。边框窗格的顶部是fxml文件。然后,游戏结束后的另一个窗口也是另一个fxml文件:

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

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

 <Pane fx:id="paneMenu" nodeOrientation="LEFT_TO_RIGHT" prefHeight="160.0" prefWidth="240.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.GameMenuController">

<children>
 <Button fx:id="buttonRestart" layoutX="15.0" layoutY="122.0" mnemonicParsing="false" onAction="#restart" prefHeight="27.0" prefWidth="90.0" text="New Game" />
  <Button fx:id="buttonQuit" layoutX="139.0" layoutY="122.0" mnemonicParsing="false" onAction="#quit" prefHeight="27.0" prefWidth="90.0" text="Quit" />
  <Label fx:id="labelWinner" alignment="CENTER" contentDisplay="CENTER" layoutX="23.0" layoutY="80.0" prefHeight="17.0" prefWidth="190.0" text="Label" textAlignment="CENTER" />
  <Text layoutX="50.0" layoutY="47.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Game over!" textAlignment="CENTER">
     <font>
        <Font size="26.0" />
     </font>
  </Text>
    </children>
   <padding>
  <Insets bottom="10.0" right="10.0" />
 </padding>
</Pane>

这个fxml文件的Controller类如下所示:

public class GameMenuController implements Initializable {

public GameMenuController(Checkers model) {
    this.content = model;
}

Checkers content;

@FXML
private Label labelWinner;

@FXML
private Button buttonRestart;

@FXML
private Button buttonQuit;

@FXML
private Pane paneMenu;

BooleanProperty doRestart = new SimpleBooleanProperty(false);

@FXML
void restart(ActionEvent event) {
    content.cleanup();
    doRestart.set(true);
}

@FXML
void quit(ActionEvent event) {
    System.exit(0);
}

@Override
public void initialize(URL location, ResourceBundle resources) {
    labelWinner.setText("Winner here.");
    labelWinner.textProperty().bind(Bindings.createStringBinding(() -> {
        String s = " ";
        if (...);
        return s;
    }, content.whiteTurnProp));
}

}

最后,在我的主要课程中,我想在doRestart的值中添加一个ChangeListener,然后重新创建一个新场景。

我的主要课程是这样的:

public class Main extends Application{

Checkers content = new Checkers();
BorderPane border = new BorderPane(); 
Pane paneBoard = new Pane();
FXMLLoader loader1 = new FXMLLoader();
FXMLLoader loader2 = new FXMLLoader();

@Override
public void start(Stage primaryStage) throws Exception {

    loader1.setLocation(getClass().getResource("sample.fxml"));
    loader1.setControllerFactory(new Callback<Class<?>, Object>() {
        @Override
        public Object call(Class<?> aClass) {
            return new SampleController(content);
        }
    });

    loader2.setLocation(getClass().getResource("GameMenu.fxml"));
    loader2.setControllerFactory(new Callback<Class<?>, Object>() {
        @Override
        public Object call(Class<?> aClass) {
            return new GameMenuController(content);
        }
    });   
    GameMenuController gameMenuControl = loader2.getController(); 

    Scene scene = new Scene(startGame());
    primaryStage.setTitle("Checkers");
    primaryStage.setScene(scene);
    primaryStage.show();

    content.gameOver.addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                try {
                    scene.setRoot(loader2.load());
                    primaryStage.setHeight(180);
                    primaryStage.setWidth(240);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        });

    gameMenuControl.doRestart.addListener(new ChangeListener<Boolean>() {
        @Override
        public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
            if(newValue) {
            scene.setRoot(startGame());
            primaryStage.setHeight(scene.getHeight());
            primaryStage.setWidth(scene.getWidth());
            gameMenuControl.doRestart.set(false);
            }
        }
    });
}

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

    paneBoard.setPrefSize(Checkers.WIDTH * Checkers.TILE_SIZE, Checkers.HEIGHT * Checkers.TILE_SIZE);
    paneBoard.getChildren().addAll(content.tileGroup, content.pieceGroup);

    for (int y = 0; y < Checkers.HEIGHT; y++) {
        for (int x = 0; x < Checkers.WIDTH; x++) {
            Tile tile = new Tile((x + y) % 2 == 0, x, y);
            Checkers.board[y][x] = tile;

            content.tileGroup.getChildren().add(tile);

            Piece piece = null;

            if (y <= 3 && (x + y) % 2 != 0) {
                piece = content.makePiece(PieceType.BLACK, x, y);
            }

            if (y >= 6 && (x + y) % 2 != 0) {
                piece = content.makePiece(PieceType.WHITE, x, y);
            }

            if (piece != null) {
                tile.setPiece(piece);
                content.pieceGroup.getChildren().add(piece);
            }
        }
    }

    return paneBoard;
}

protected BorderPane startGame() {
    try {
        border.setTop(loader1.load());
    } catch (IOException e) {
        e.printStackTrace();
    }
    border.setCenter(createContent());

    return border;
}

}

我很确定我的代码是一团糟,我一直在尝试尽可能多地处理这里给出的提示,但由于我仍然是超级新手,我真的不知道如何处理这一切。

我想做的是,我想直接从我的控制器更改视图,而不是使用这个更改侦听器(它也不起作用,我得到了一个NullPointerException)。我该怎么办?

1) 除了通过工厂创建控制器,我可以让他们以其他方式访问我的模型检查器吗?(所有游戏逻辑都存储在那里等)

2)我基本上如何重新创建我的第一个窗口?(由start Game()创建)

非常感谢你!!最好的,丽莎

共有1个答案

益银龙
2023-03-14

您正在调用GameMenuController gameMenuControl=loader2。getController()在调用loader2之前。load()。控制器是作为加载过程的一部分创建的,因此gameMenuControl将为空。

您只需将调用移动到loader2即可。getController()gameMenuControl。多雷斯塔特。addListener(…) 调用加载程序2后立即调用。load()

或者,只需自己创建控制器,而不是委托给控制器工厂。从FXML文件中删除fx:controller属性,然后执行以下操作:

@Override
public void start(Stage primaryStage) throws Exception {

    // You can make similar changes to loader1 if you want...

    loader2.setLocation(getClass().getResource("GameMenu.fxml"));

    GameMenuController gameMenuControl = new GameMenuController(content) ;

    gameMenuControl.doRestart.addListener(new ChangeListener<Boolean>() {
        @Override
        public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
            if(newValue) {
            scene.setRoot(startGame());
            primaryStage.setHeight(scene.getHeight());
            primaryStage.setWidth(scene.getWidth());
            gameMenuControl.doRestart.set(false);
            }
        }
    });

    loader2.setController(gameMenuControl);

    content.gameOver.addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                try {
                    scene.setRoot(loader2.load());
                    primaryStage.setHeight(180);
                    primaryStage.setWidth(240);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        });

    Scene scene = new Scene(startGame());
    primaryStage.setTitle("Checkers");
    primaryStage.setScene(scene);
    primaryStage.show();


}
 类似资料:
  • 问题内容: 我的问题是所有使用示例都需要您通过一个阶段。唯一的问题是,我的UI是在文件中定义的,该文件使用与主阶段分离的控制器类。 我该怎么做才能使其正常工作?就像我说的那样,我在控制器类中没有任何阶段的引用,那我该怎么办? 问题答案: 对于场景中的任何节点(例如,根节点;但是注入的任何节点都可以),请执行

  • 我是的新手,我有一个和多个场景,我可以使用在它们之间切换,所有工作都很好,直到我尝试在单击菜单项时做一些事情而不是显示场景。 我试图通过使用方法类中调用,在那里我有菜单项action methods,我调用在单击菜单项时将文本写入方法中的文本字段,但在加载该场景的控制器后,什么都没有发生。这是我的代码: 类 家庭控制器类 我知道我可能忽略了一些东西,但我不知道它是什么,帮助将不胜感激。

  • 问题内容: 有什么方法可以从关联的类控制器获取FXML加载文件的Scene对象。 我正在做这样的事情: 但是我想要一个不引用AnchorPane控件的解决方案。 问题答案: 为什么不?Controller是一个抽象类,除非您有意让他知道,否则他不了解UI。 节点(包括AnchorPane)是另一个故事,它们几乎不存在于场景图的外部。因此,最好向Node询问有关其父母或场景的信息。 如果您仍然想单独

  • 但我想要一个不引用AnchorPane控件的解决方案。

  • 问题内容: 大家好,我正在构建一个JavaFX项目并正在使用JavaFX Scene Builder2。我想将控制器链接到我的fxml文件,但是我看不到在Scene Builder 2中将控制器添加到我的fxml文件的可能性。我想知道是否有人可以帮助我。谢谢。 问题答案: 我偶然在SceneBuilder 2中找到了控制器属性。关闭左侧的层次结构菜单时,将显示“控制器”菜单,可以在其中声明我的控制

  • 我写信是为了获取有关JavaFX的一些信息。我使用SceneBuilder设计了一个应用程序,它有一个主要场景,由几个文本字段和用于浏览文件的按钮组成。程序运行后还有一个用于输出的文本区域。我在控制器的初始化方法中添加了更改侦听器,以便在更新输出文本区域时修改日志文件。 最初,我使用输出文本区域来显示日志文件,对其进行了测试。一旦我从主文件菜单中选择了“查看日志”菜单项,我就能够在这个输出文本区域