如何在单个阶段中更改动态生成的JavaFX场景?
我目前正在做一个项目,要求我在场景之间来回切换。我已经为它编写了一些代码,但它并没有我想要的那么优雅,特别是当我在它们之间切换时,几乎没有闪烁,有时甚至我生成的按钮也会消失,只是在生成另一个场景时再次出现。此外,我在应用程序中使用的布局并不是固定的,我认为使用FXML可能不适合我正在做的事情 多谢各位 这就是我用来在场景之间切换的内容:如何在单个阶段中更改动态生成的JavaFX场景?,javafx,scene,Javafx,Scene,我目前正在做一个项目,要求我在场景之间来回切换。我已经为它编写了一些代码,但它并没有我想要的那么优雅,特别是当我在它们之间切换时,几乎没有闪烁,有时甚至我生成的按钮也会消失,只是在生成另一个场景时再次出现。此外,我在应用程序中使用的布局并不是固定的,我认为使用FXML可能不适合我正在做的事情 多谢各位 这就是我用来在场景之间切换的内容: void changeScene(Stage stage,Scene scene){ stage.setScene(scene); primar
void changeScene(Stage stage,Scene scene){
stage.setScene(scene);
primaryStage.setFullScreen(true);
}
我假设“在场景之间切换”是指您希望更改现有窗口的全部内容
有两种(非常)略有不同的方法可以做到这一点。创建一个新的场景
并将其传递给阶段
的设置场景(…)
方法。或者创建作为新UI根的Parent
(通过FXML或其他方式),并将其传递给现有场景的setRoot(…)
方法。我看不出两者之间有什么真正的优势
这里是第二个选项的最小实现。UI与问题无关:重要的部分是“登录”按钮(从登录场景切换到主场景)和“注销”按钮(切换回)的事件处理程序
import java.util.stream.IntStream;
导入javafx.application.application;
导入javafx.beans.binding.Bindings;
导入javafx.beans.property.IntegerProperty;
导入javafx.beans.property.SimpleIntegerProperty;
导入javafx.geometry.HPos;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.Label;
导入javafx.scene.control.ListView;
导入javafx.scene.control.SplitPane;
导入javafx.scene.control.TextField;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.layout.ColumnConstraints;
导入javafx.scene.layout.GridPane;
导入javafx.scene.layout.Priority;
导入javafx.scene.text.Font;
导入javafx.scene.text.FontWeight;
导入javafx.stage.stage;
公共类最小场景切换示例扩展应用程序{
@凌驾
公共无效开始(阶段primaryStage){
LoginView LoginView=新LoginView();
场景=新场景(loginView.getView(),400400);
初级阶段。场景(场景);
primaryStage.show();
}
公共静态类LoginView{
私有最终IntegerProperty登录尝试;
私有最终网格窗格视图;
公共登录视图(){
视图=新建网格窗格();
TextField usernameTF=新的TextField(“用户”);
TextField passwordTF=新的TextField(“pass”);
//登录按钮切换到主视图:
按钮登录按钮=新按钮(“登录”);
loginButton.setOnAction(事件->{
if(usernameTF.getText().equalsIgnoreCase(“用户”)
&&passwordTF.getText().equalsIgnoreCase(“pass”)){
//***切换到主视图:***
父mainView=新的mainView().getView();
view.getScene().setRoot(mainView);
}否则{
loginattents.set(loginattents.get()+1);
}
});
//只需设置登录UI…与此示例无关:
LoginAttents=新的SimpleIntegerProperty();
usernameTF.setPrompText(“提示:用户”);
passwordTF.setPrompText(“提示:通过”);
view.addRow(0,新标签(“用户名:”),usernameTF);
view.addRow(1,新标签(“密码”)、passwordTF;
Label loginErrorMessage=新标签();
loginErrorMessage.textProperty().bind(
Bindings.when(loginattests.isEqualTo(0))
.然后(“”)
。否则(Bindings.format(“登录错误(尝试次数:%d)”,
登录测试);
添加(loginErrorMessage,0,2,2,1);
添加(登录按钮,0,3,2,1);
ColumnConstraints leftCol=新ColumnConstraints();
leftCol.setHgrow(Priority.NEVER);
左列设定值(HPos.右);
ColumnConstraints rightCol=新ColumnConstraints();
rightCol.setHgrow(优先级始终);
右列设定值(HPos左);
view.getColumnConstraints().addAll(leftCol,rightCol);
GridPane.setHalignment(loginErrorMessage,HPos.CENTER);
GridPane.setHalignment(登录按钮,HPos.CENTER);
视图。setHgap(10);
视图。setVgap(16);
视图。设置对齐(位置中心);
}
公共父getView(){
返回视图;
}
}
公共静态类MainView{
私有边框视图;
公共主视图(){
视图=新建边框窗格();
//***注销按钮切换回登录视图:***
按钮注销按钮=新按钮(“注销”);
注销按钮。设置操作(事件->
view.getScene().setRoot(新的LoginView().getView());
//任意用户界面,与本例无关:
SplitPane SplitPane=新的SplitPane();
ListView ListView=新建ListView();
IntStream.rangeClosed(1,10)
.mapToObj(整数::toString)
.map(“项目”::concat)
.forEach(listView.getItems()::添加);
Label bigLabel=新标签();
bigLabel.textProperty().bind(
listView.getSelectionModel().SelectEditeProperty();
setFont(Font.Font(“Verdana”,fontwweight.BOLD,18));
BorderPane.setAlignment(大标签,位置中心);
BorderPane.setMargin(
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
public class MinimalSceneSwitchingExample extends Application {
@Override
public void start(Stage primaryStage) {
LoginView loginView = new LoginView();
Scene scene = new Scene(loginView.getView(), 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class LoginView {
private final IntegerProperty loginAttempts ;
private final GridPane view ;
public LoginView() {
view = new GridPane();
TextField usernameTF = new TextField("user");
TextField passwordTF = new TextField("pass");
// Login button switches to main view:
Button loginButton = new Button("Login");
loginButton.setOnAction(event -> {
if (usernameTF.getText().equalsIgnoreCase("user")
&& passwordTF.getText().equalsIgnoreCase("pass")) {
// *** Switch to main view: ***
Parent mainView = new MainView().getView();
view.getScene().setRoot(mainView);
} else {
loginAttempts.set(loginAttempts.get()+1);
}
});
// just set up login UI... irrelevant to this example:
loginAttempts = new SimpleIntegerProperty();
usernameTF.setPromptText("Hint: user");
passwordTF.setPromptText("Hint: pass");
view.addRow(0, new Label("Username:"), usernameTF);
view.addRow(1, new Label("Password:"), passwordTF);
Label loginErrorMessage = new Label();
loginErrorMessage.textProperty().bind(
Bindings.when(loginAttempts.isEqualTo(0))
.then("")
.otherwise(Bindings.format("Login incorrect (Attempts: %d)",
loginAttempts)));
view.add(loginErrorMessage, 0, 2, 2, 1);
view.add(loginButton, 0, 3, 2, 1);
ColumnConstraints leftCol = new ColumnConstraints();
leftCol.setHgrow(Priority.NEVER);
leftCol.setHalignment(HPos.RIGHT);
ColumnConstraints rightCol = new ColumnConstraints();
rightCol.setHgrow(Priority.ALWAYS);
rightCol.setHalignment(HPos.LEFT);
view.getColumnConstraints().addAll(leftCol, rightCol);
GridPane.setHalignment(loginErrorMessage, HPos.CENTER);
GridPane.setHalignment(loginButton, HPos.CENTER);
view.setHgap(10);
view.setVgap(16);
view.setAlignment(Pos.CENTER);
}
public Parent getView() {
return view ;
}
}
public static class MainView {
private BorderPane view ;
public MainView() {
view = new BorderPane();
// *** logout button switches back to a login view: ***
Button logoutButton = new Button("Log out");
logoutButton.setOnAction(event ->
view.getScene().setRoot(new LoginView().getView()));
// Arbitrary UI, irrelevant to this example:
SplitPane splitPane = new SplitPane();
ListView<String> listView = new ListView<>();
IntStream.rangeClosed(1, 10)
.mapToObj(Integer::toString)
.map("Item "::concat)
.forEach(listView.getItems()::add);
Label bigLabel = new Label();
bigLabel.textProperty().bind(
listView.getSelectionModel().selectedItemProperty());
bigLabel.setFont(Font.font("Verdana", FontWeight.BOLD, 18));
BorderPane.setAlignment(bigLabel, Pos.CENTER);
BorderPane.setMargin(bigLabel, new Insets(10));
Label details = new Label();
details.textProperty().bind(
Bindings.when(
listView.getSelectionModel().selectedItemProperty().isNull())
.then("")
.otherwise(Bindings.format("This is where you would display "
+ "all sorts of details about %1$s. "
+ "If %1$s were really a model object, you "
+ "might have a GridPane displaying all its "
+ "properties, for example.",
listView.getSelectionModel().selectedItemProperty())));
details.setWrapText(true);
BorderPane detailsPane = new BorderPane(details, bigLabel, null, null, null);
splitPane.getItems().addAll(listView, detailsPane);
view.setCenter(splitPane);
view.setBottom(logoutButton);
BorderPane.setAlignment(logoutButton, Pos.CENTER);
BorderPane.setMargin(logoutButton, new Insets(8));
BorderPane.setMargin(splitPane, new Insets(16));
}
public Parent getView() {
return view ;
}
}
public static void main(String[] args) {
launch(args);
}
}