首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >屏幕中央的JavaFX位置对话框和舞台

屏幕中央的JavaFX位置对话框和舞台
EN

Stack Overflow用户
提问于 2017-10-06 18:43:04
回答 3查看 10.4K关注 0票数 2

下面的代码演示对话框和舞台在屏幕中心的居中位置。应该首先显示该对话框,以便用户输入登录凭据。成功登录后,将显示主窗口(stage)。我在这个网站上找到了使对话和舞台居中的解决方案,但它似乎不是很理想。对于对话框和舞台,必须先显示它们,然后才能计算坐标,然后将它们定位在中心。这意味着我们可以看到对话框和主窗口在显示后移到中心。有没有更好的方法?理想情况下,它们应该在显示之前位于中心位置。

代码语言:javascript
运行
复制
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.Window;

public class Demo extends Application {

    private Stage primaryStage;
    private Dialog<String> dialog;
    private Button createUserButton = new Button("Create User");

    @Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        Text usersLabel = new Text("Current Users:");
        TableColumn<User, String> indexColumn = new TableColumn<User, String>("No.");
        indexColumn.setMaxWidth(1f * Integer.MAX_VALUE * 10);
        indexColumn.setCellValueFactory(p -> p.getValue().indexProperty());
        TableColumn<User, String> userNameColumn = new TableColumn<User, String>("User Name");
        userNameColumn.setMaxWidth(1f * Integer.MAX_VALUE * 60);
        userNameColumn.setCellValueFactory(p -> p.getValue().userNameProperty());
        TableColumn<User, String> roleColumn = new TableColumn<User, String>("Role");
        roleColumn.setMaxWidth(1f * Integer.MAX_VALUE * 30);
        roleColumn.setCellValueFactory(p -> p.getValue().roleProperty());
        TableView<User> tableView = new TableView<User>();
        tableView.getColumns().add(indexColumn);
        tableView.getColumns().add(userNameColumn);
        tableView.getColumns().add(roleColumn);
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        Text dummyLabel = new Text("");
        VBox leftPane = new VBox(5);
        leftPane.getChildren().addAll(usersLabel, tableView);
        VBox rightPane = new VBox(20);
        rightPane.setFillWidth(true);
        rightPane.getChildren().addAll(dummyLabel, createUserButton);
        GridPane mainPane = new GridPane();
        mainPane.setPadding(new Insets(10, 0, 0, 10));
        mainPane.setHgap(20);
        mainPane.add(leftPane, 0, 0);
        mainPane.add(rightPane, 1, 0);
        Scene scene = new Scene(mainPane);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        showDialog();
    }

    private void showDialog() {
        dialog = new Dialog<>();
        dialog.setTitle("Login");
        dialog.setHeaderText("Please enter User Name and Password to login.");
        dialog.setResizable(false);
        Label userNameLabel = new Label("User Name:");
        Label passwordLabel = new Label("Password:");
        TextField userNameField = new TextField();
        PasswordField passwordField = new PasswordField();
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 35, 20, 35));
        grid.add(userNameLabel, 1, 1);
        grid.add(userNameField, 2, 1);
        grid.add(passwordLabel, 1, 2);
        grid.add(passwordField, 2, 2);
        dialog.getDialogPane().setContent(grid);
        dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
        Button okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
        okButton.addEventFilter(ActionEvent.ACTION, event -> {
            createUser(userNameField.getText().trim(), passwordField.getText());
            event.consume();
        });
        dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
        Platform.runLater(() -> {
            Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
            Window window = dialog.getDialogPane().getScene().getWindow();
            window.setX((screenBounds.getWidth() - window.getWidth()) / 2);
            window.setY((screenBounds.getHeight() - window.getHeight()) / 2);
        });
        dialog.showAndWait();
    }

    private void createUser(String userName, String password) {
        dialog.getDialogPane().setDisable(true);
        dialog.getDialogPane().getScene().setCursor(Cursor.WAIT);
        Task<Boolean> task = new Task<Boolean>() {
            @Override
            public Boolean call() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException exception) {
                }
                return Boolean.TRUE;
            }
        };
        task.setOnSucceeded(e -> {
            Boolean success = task.getValue();
            dialog.getDialogPane().setDisable(false);
            dialog.getDialogPane().getScene().setCursor(Cursor.DEFAULT);
            if (success.booleanValue()) {
                Platform.runLater(() -> {
                    dialog.close();
                    primaryStage.show();
                    Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
                    primaryStage.setX((screenBounds.getWidth() - primaryStage.getWidth()) / 2);
                    primaryStage.setY((screenBounds.getHeight() - primaryStage.getHeight()) / 2);
                });
            } else {
                Alert alert = new Alert(AlertType.ERROR);
                alert.setTitle("Login Error");
                alert.setHeaderText("Unable to login.");
                alert.showAndWait();
            }
        });
        new Thread(task).start();
    }

    public static void main(String[] arguments) {
        Application.launch(arguments);
    }

}

class User {

    private StringProperty index;

    private StringProperty userName;

    private StringProperty role;

    public String getIndex() {
        return indexProperty().get();
    }

    public StringProperty indexProperty() {
        if (index == null) {
            index = new SimpleStringProperty(this, "index");
        }
        return index;
    }

    public void setIndex(String index) {
        indexProperty().set(index);
    }

    public String getUserName() {
        return userNameProperty().get();
    }

    public StringProperty userNameProperty() {
        if (userName == null) {
            userName = new SimpleStringProperty(this, "userName");
        }
        return userName;
    }

    public void setUserName(String userName) {
        userNameProperty().set(userName);
    }

    public String getRole() {
        return roleProperty().get();
    }

    public StringProperty roleProperty() {
        if (role == null) {
            role = new SimpleStringProperty(this, "role");
        }
        return role;
    }

    public void setRole(String role) {
        roleProperty().set(role);
    }

}

下面是通过设置阶段和对话框自定义维度的解决方案。它适用于舞台,但不适用于对话框。

代码语言:javascript
运行
复制
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.stage.WindowEvent;

public class Demo extends Application {

    private Stage primaryStage;
    private Dialog<String> dialog;
    private Button createUserButton = new Button("Create User");

    @Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        Text usersLabel = new Text("Current Users:");
        TableColumn<User, String> indexColumn = new TableColumn<User, String>("No.");
        indexColumn.setMaxWidth(1f * Integer.MAX_VALUE * 10);
        indexColumn.setCellValueFactory(p -> p.getValue().indexProperty());
        TableColumn<User, String> userNameColumn = new TableColumn<User, String>("User Name");
        userNameColumn.setMaxWidth(1f * Integer.MAX_VALUE * 60);
        userNameColumn.setCellValueFactory(p -> p.getValue().userNameProperty());
        TableColumn<User, String> roleColumn = new TableColumn<User, String>("Role");
        roleColumn.setMaxWidth(1f * Integer.MAX_VALUE * 30);
        roleColumn.setCellValueFactory(p -> p.getValue().roleProperty());
        TableView<User> tableView = new TableView<User>();
        tableView.getColumns().add(indexColumn);
        tableView.getColumns().add(userNameColumn);
        tableView.getColumns().add(roleColumn);
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        Text dummyLabel = new Text("");
        VBox leftPane = new VBox(5);
        leftPane.getChildren().addAll(usersLabel, tableView);
        VBox rightPane = new VBox(20);
        rightPane.setFillWidth(true);
        rightPane.getChildren().addAll(dummyLabel, createUserButton);
        GridPane mainPane = new GridPane();
        mainPane.setPadding(new Insets(10, 0, 0, 10));
        mainPane.setHgap(20);
        mainPane.add(leftPane, 0, 0);
        mainPane.add(rightPane, 1, 0);
        float width = 372f;
        float height = 470f;
        Scene scene = new Scene(mainPane, width, height);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
        primaryStage.setX((screenBounds.getWidth() - width) / 2);
        primaryStage.setY((screenBounds.getHeight() - height) / 2);
        showDialog();
    }

    private void showDialog() {
        dialog = new Dialog<>();
        dialog.setTitle("Login");
        dialog.setHeaderText("Please enter User Name and Password to login.");
        dialog.setResizable(false);
        Label userNameLabel = new Label("User Name:");
        Label passwordLabel = new Label("Password:");
        TextField userNameField = new TextField();
        PasswordField passwordField = new PasswordField();
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(20, 35, 20, 35));
        grid.add(userNameLabel, 1, 1);
        grid.add(userNameField, 2, 1);
        grid.add(passwordLabel, 1, 2);
        grid.add(passwordField, 2, 2);
        dialog.getDialogPane().setContent(grid);
        dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
        Button okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
        okButton.addEventFilter(ActionEvent.ACTION, event -> {
            login(userNameField.getText().trim(), passwordField.getText());
            event.consume();
        });
        dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
        float width = 509f;
        float height = 168f;
        dialog.setWidth(width);
        dialog.setHeight(height);
        Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
        dialog.setX((screenBounds.getWidth() - width) / 2);
        dialog.setY((screenBounds.getHeight() - height) / 2);
        dialog.showAndWait();
    }

    private void login(String userName, String password) {
        dialog.getDialogPane().setDisable(true);
        dialog.getDialogPane().getScene().setCursor(Cursor.WAIT);
        Task<Boolean> task = new Task<Boolean>() {
            @Override
            public Boolean call() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException exception) {
                }
                return Boolean.TRUE;
            }
        };
        task.setOnSucceeded(e -> {
            Boolean success = task.getValue();
            dialog.getDialogPane().setDisable(false);
            dialog.getDialogPane().getScene().setCursor(Cursor.DEFAULT);
            if (success.booleanValue()) {
                Platform.runLater(() -> {
                    primaryStage.show();
                });
            } else {
                Alert alert = new Alert(AlertType.ERROR);
                alert.setTitle("Login Error");
                alert.setHeaderText("Unable to login.");
                alert.showAndWait();
            }
        });
        new Thread(task).start();
    }

    public static void main(String[] arguments) {
        Application.launch(arguments);
    }

}

class User {

    private StringProperty index;

    private StringProperty userName;

    private StringProperty role;

    public String getIndex() {
        return indexProperty().get();
    }

    public StringProperty indexProperty() {
        if (index == null) {
            index = new SimpleStringProperty(this, "index");
        }
        return index;
    }

    public void setIndex(String index) {
        indexProperty().set(index);
    }

    public String getUserName() {
        return userNameProperty().get();
    }

    public StringProperty userNameProperty() {
        if (userName == null) {
            userName = new SimpleStringProperty(this, "userName");
        }
        return userName;
    }

    public void setUserName(String userName) {
        userNameProperty().set(userName);
    }

    public String getRole() {
        return roleProperty().get();
    }

    public StringProperty roleProperty() {
        if (role == null) {
            role = new SimpleStringProperty(this, "role");
        }
        return role;
    }

    public void setRole(String role) {
        roleProperty().set(role);
    }

}

JKostikiadis的解决方案:

代码语言:javascript
运行
复制
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Screen;
import javafx.stage.Stage;

public class TestApp extends Application {

    private static final double WIDTH = 316.0;
    private static final double HEIGHT = 339.0;

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

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

        HBox pane = new HBox();
        pane.setAlignment(Pos.CENTER);

        Button b = new Button("click me");
        b.setOnAction(e -> {
            showDialog();
        });

        pane.getChildren().add(b);

        Scene scene = new Scene(pane, 300, 300);

        stage.setScene(scene);

        centerStage(stage, WIDTH, HEIGHT);
        stage.show();


    }

    private void showDialog() {
        Alert dialog = new Alert(AlertType.ERROR);
        dialog.setTitle("Error Dialog");
        dialog.setHeaderText("Look, an Error Dialog");
        dialog.setContentText("Ooops, there was an error!\nOoops, there was an error!");

        Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
        centerStage(stage, -10000, -10000);
        dialog.show();
        System.out.println(stage.getWidth() + " " + stage.getHeight());
        dialog.hide();
        centerStage(stage, stage.getWidth(), stage.getHeight());        
        dialog.showAndWait();

    }

    private void centerStage(Stage stage, double width, double height) {
        Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
        stage.setX((screenBounds.getWidth() - width) / 2);
        stage.setY((screenBounds.getHeight() - height) / 2);
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-10-09 19:13:48

好的,因为你在推荐中问我,我将提供一个例子,通过早期初始化它们的尺寸来将舞台(主应用程序或对话框)设置到屏幕的中心。

代码语言:javascript
运行
复制
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Screen;
import javafx.stage.Stage;

public class TestApp extends Application {

    private static final double WIDTH = 316.0;
    private static final double HEIGHT = 339.0;

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

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

        HBox pane = new HBox();
        pane.setAlignment(Pos.CENTER);

        Button b = new Button("click me");
        b.setOnAction(e -> {
            showDialog();
        });

        pane.getChildren().add(b);

        Scene scene = new Scene(pane, 300, 300);

        stage.setScene(scene);

        centerStage(stage, WIDTH, HEIGHT);
        stage.show();

        System.out.println(stage.getWidth() + " " + stage.getHeight());
    }

    private void showDialog() {
        Alert dialog = new Alert(AlertType.ERROR);
        dialog.setTitle("Error Dialog");
        dialog.setHeaderText("Look, an Error Dialog");
        dialog.setContentText("Ooops, there was an error!");

        Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
        centerStage(stage, 366, 175);

        dialog.showAndWait();

    }

    private void centerStage(Stage stage, double width, double height) {
        Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
        stage.setX((screenBounds.getWidth() - width) / 2);
        stage.setY((screenBounds.getHeight() - height) / 2);
    }
}

在上面的示例中,您将看到我将应用程序维度指定为300,300,但我使用的是for width = 316.0和height = 339.0,您可能想知道为什么。这是因为舞台的大小总是比场景大一点(边框+标题栏等等),所以为了找到舞台的实际宽度和高度,你必须在展示之后打印出舞台的尺寸。同样的逻辑也发生在对话框上。

重要提示:当然,您可以忘记上述所有内容,只需执行以下操作:

代码语言:javascript
运行
复制
stage.setWidth(300); // or a variable here 
stage.setHeight(300);

但这将影响您的内部组件,因为如果以前场景的组件大小为300,300,现在它们将被压缩到较小的大小,以便使舞台固定大小为300,300,所以在这种情况下,它可能会影响您的应用程序的外观。

在过去,我一直在寻找一种方法,在我展示标签之前找到它的尺寸。我发现可以通过将它添加到场景中来获得它的尺寸,然后调用

代码语言:javascript
运行
复制
labe.impl_processCSS(true);
System.out.println(labe.prefWidth(-1) + "/" + labe.prefHeight(-1));

现在,如果我尝试对上面的应用程序中的主窗格执行同样的操作,它会显示59/25,这是按钮本身的尺寸,所以如果有人对此感到疑惑,这种方法将不起作用。

编辑

我真的不想展示这个"hack“,因为我觉得它很愚蠢,而且我相信有更好的方法,但在我找到它之前,你可以继续:

代码语言:javascript
运行
复制
private void showDialog() {
    Alert dialog = new Alert(AlertType.ERROR);
    dialog.setTitle("Error Dialog");
    dialog.setHeaderText("Look, an Error Dialog");
    dialog.setContentText("Ooops, there was an error!\nOoops, there was an error!");

    Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
    centerStage(stage, -10000, -10000);
    dialog.show();
    centerStage(stage, stage.getWidth(), stage.getHeight());   
}
票数 0
EN

Stack Overflow用户

发布于 2017-10-06 19:58:41

不幸的是,您必须等待计算Window (或Dialog)的宽度/高度以及显示Window。由于Window是可见的,因此当更新xy位置时,您将始终注意到窗口在移动。

在触发WindowEvent.WINDOW_SHOWN事件时执行更新可能会提供更好的结果:

代码语言:javascript
运行
复制
   final Window window = dialog.getDialogPane().getScene().getWindow();

    window.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent event) {
            Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
            window.setX((screenBounds.getWidth() - window.getWidth()) / 2);
            window.setY((screenBounds.getHeight() - window.getHeight()) / 2);

        }
    });

而对于primaryStage

代码语言:javascript
运行
复制
    primaryStage.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>() {

    @Override
    public void handle(WindowEvent event) {
        Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
        primaryStage.setX((screenBounds.getWidth() - primaryStage.getWidth()) / 2);
        primaryStage.setY((screenBounds.getHeight() - primaryStage.getHeight()) / 2);
    }
});
primaryStage.show();

但正如JKostikiadis提到的,一个更好、更合适的解决方案可能是根据当前屏幕尺寸计算您自己的尺寸。

这是我能看到的小改进。在我的机器上运行演示时,移动不稳定:

我可以看到在使用WindowEvent.WINDOW_SHOWN (在第一个对话框中不使用Platform.runLater)时有一个小小的改进:

无论如何,我不认为使用Platform.runLater来显示第一个窗口是理想的,因为不能保证showAndWait()总是在Runnable之前执行

票数 5
EN

Stack Overflow用户

发布于 2017-10-10 21:15:21

在渲染一个舞台之前,您可以将它置于另一个舞台的中心,方法是应用css,它将为您提供宽度/高度。

例如。

从创建舞台的位置:

代码语言:javascript
运行
复制
WindowHelper.centerChildWindowOnStage(stage, primaryStage);  //assuming primary is the stage you want to center on
stage.show();

下面是使未显示的窗口居中显示的代码(假设这位于要在应用程序中重用的WindowHelper类上)。

代码语言:javascript
运行
复制
public static void centerChildWindowOnStage(Stage stage, Stage primaryStage ) {

    if(primaryStage == null){
        return;
    }

    double x = stage.getX();
    double y = stage.getY();

    // Firstly we need to force CSS and layout to happen, as the dialogPane
    // may not have been shown yet (so it has no dimensions)
    stage.getScene().getRoot().applyCss();
    stage.getScene().getRoot().layout();

    final Scene ownerScene = primaryStage.getScene();
    final double titleBarHeight = ownerScene.getY();

    // because Stage does not seem to centre itself over its owner, we
    // do it here.

    // then we can get the dimensions and position the dialog appropriately.
    final double dialogWidth = stage.getScene().getRoot().prefWidth(-1);
    final double dialogHeight = stage.getScene().getRoot().prefHeight(dialogWidth);

    final double ownerWidth = primaryStage.getScene().getRoot().prefWidth(-1);
    final double ownerHeight = primaryStage.getScene().getRoot().prefHeight(ownerWidth);

    if(dialogWidth < ownerWidth){
        x = primaryStage.getX() + (ownerScene.getWidth() / 2.0) - (dialogWidth / 2.0);
    }else {
        x = primaryStage.getX();
        stage.setWidth(dialogWidth);
    }

    if(dialogHeight < ownerHeight){
        y = primaryStage.getY() + titleBarHeight / 2.0 + (ownerScene.getHeight() / 2.0) - (dialogHeight / 2.0);
    }else {
        y = primaryStage.getY();
    }

    stage.setX(x);
    stage.setY(y);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46603948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档