【问题标题】:javafx - Alert and stage focusjavafx - 警报和舞台焦点
【发布时间】:2017-07-07 14:20:00
【问题描述】:

对于我的应用程序,我需要知道应用程序的窗口何时被聚焦。为此,我可以使用primaryStage.focusedProperty().addListener(..),它会警告我舞台焦点的变化。

但我已经意识到,以 primaryStage 作为所有者并将模态设置为 WINDOW_MODAL 打开 Alert 会使 primaryStage 失去焦点(即使窗口实际上是焦点,或者至少在 Windows )。

现在我遇到的问题是我想知道Window 何时被聚焦,而不仅仅是primaryStage;或者至少知道Alert 是否被关注,但我找不到如何。

我尝试在警报上使用类似的属性(如onShowingonHiding)但没有成功。

这里有一段代码来说明我的问题:

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.stage.Modality;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));

        primaryStage.focusedProperty().addListener((observable, oldValue, newValue) -> {
            System.out.println("primaryStage focused : "+newValue);
        });
        primaryStage.show();

        //create a basic alert
        Alert alert = new Alert(Alert.AlertType.INFORMATION,"This is a test");
        alert.initModality(Modality.WINDOW_MODAL); //will block input to its owner window
        alert.initOwner(primaryStage);
        alert.onShowingProperty().addListener((observable, oldValue, newValue) -> {
            System.out.println("alert onShowing : "+newValue);
        });
        alert.onShownProperty().addListener((observable, oldValue, newValue) -> {
            System.out.println("alert onShown : "+newValue);
        });
        alert.onHidingProperty().addListener((observable, oldValue, newValue) -> {
            System.out.println("alert onHiding : "+newValue);
        });
        alert.onHiddenProperty().addListener((observable, oldValue, newValue) -> {
            System.out.println("alert onHidden : "+newValue);
        });
        alert.showAndWait();
    }


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

基本上它会打印这个:

primaryStage focused : true //stage is created and displayed
primaryStage focused : false //alert is displayed, stage loses focus. alt+tab changes nothing
primaryStage focused : true //alert closed by pressing 'ok'

这很奇怪,因为它应该产生所有其他打印。 理想情况下,我需要一个:

primaryStage focused : true //stage is created and displayed
primaryStage focused : false //alert is displayed, stage loses focus
alert focused : true //alert gains focus
alert focused : false //alt+tab to an other window
alert focused : true //alt+tab back to this window
alert focused : false //alert closed by pressing 'ok'
primaryStage focused : true //stage regains focus

或类似的东西。有没有人有实现这一目标的想法,或者这 primaryStage 是否将注意力转移到 WINDOW_MODAL Alert 是我应该报告的问题?

【问题讨论】:

    标签: java javafx focus javafx-8 alert


    【解决方案1】:

    所以我终于可以找到解决方法了。警报中使用的每个buttonType 都可以确定它是否集中。该属性在 alt+tabbing 时也会发生变化,因此我们可以监控每个使用的 buttonType 并查看是否只有一个被聚焦。

    这是我的解决方案,有点老套,但实现了我想要的:

    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ButtonType;
    import javafx.stage.Modality;
    import javafx.stage.Stage;
    
    public class Main extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception{
            Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
            primaryStage.setTitle("Hello World");
            primaryStage.setScene(new Scene(root, 300, 275));
    
            primaryStage.focusedProperty().addListener((observable, oldValue, newValue) -> {
                System.out.println("PrimaryStage focused : "+newValue);
            });
            primaryStage.show();
    
            //create a basic alert
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION,"This is a test");
            alert.initModality(Modality.WINDOW_MODAL); //will block input to its owner window
            alert.initOwner(primaryStage);
    
            alert.getButtonTypes().forEach(buttonType -> {
                //add a focus listnener for each buttonType of this alert
                alert.getDialogPane().lookupButton(buttonType).focusedProperty().addListener((observable, oldValue, newValue) -> {
                    System.out.println(buttonType.getText()+" focused : "+newValue);
                    System.out.println("Alert focused : "+isAlertFocused(alert));
    
                });
            });
            alert.showAndWait();
        }
    
        /** Looks all {@link ButtonType} used in the given {@link Alert} and checks if any of them is
         * focused, hence if the {@link Alert} is being focused
         *
         * @param alert the {@link Alert} we want to check the focused status from
         * @return true if the alert is focused, false otherwise
         */
        private boolean isAlertFocused(Alert alert){
            if(alert == null){
                return false;
            }
    
            final boolean[] focused = {false};
            alert.getButtonTypes().forEach(buttonType -> {
                focused[0] = focused[0] || alert.getDialogPane().lookupButton(buttonType).isFocused();
            });
            return focused[0];
        }
    
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    我想我也可以通过在 isAlertFocused(Alert alert) 方法中添加对 alert.getDialogPane().isFocused() 的检查来将此方法扩展到对话框,但这超出了我的问题范围。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-14
      • 2017-12-17
      • 2016-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 2014-07-25
      相关资源
      最近更新 更多