在JavaFX应用程序中使用showAndWait [英] Using showAndWait in JavaFX application

查看:1021
本文介绍了在JavaFX应用程序中使用showAndWait的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个使用单点登录的登录。为此,如果用户登录的公司启用了SSO,则将打开JavaFX WebView ,允许用户登录。此登录将完全基于Web,因此我不需要真正的数据捕获。

I'm creating a Login which uses Single Sign On. To do this, if the company a user logs in with is SSO enabled, then a JavaFX WebView will open, allowing the user to login. This login will be entirely web based so no real data capture on my part is required.

我有两个类, LoginManager SSO LoginManager 检查公司是否为SSOEnabled,然后转到 SSO (如果是)。从这里,我创建UI,然后使用 Platform.runLater(),转到打开 webview 。但是,我的程序转到 initJFXPanel ,然后立即回到 LoginManager 来执行代码,这会导致问题。

I have two classes, LoginManager and SSO. LoginManager checks to see if the company is SSOEnabled, and then goes to SSO if it is. From here, I create the UI, and then using Platform.runLater(), go to the method which opens the webview. However, my program goes to initJFXPanel and then instantly goes back to LoginManager to execute code there, which causes issues.

我想要的是能够通过所有 SSO 直到它到达某个网页然后我使用frame.dispose(),然后返回 LoginManager 继续。我想我需要使用 Stage showAndWait()但是我不确定如何去做这件事。

What I would like is to be able to go through all of SSO until it reaches a certain webpage and then I use frame.dispose(), then go back to LoginManager to continue. I think I need to use a Stage and showAndWait() but I'm not really sure how to go about this.

我尝试在 initJFXPanel 中创建一个舞台,但这不起作用,因为它回到 LoginManager 在它有机会做任何事情之前,我也尝试在 createPopup 中设置舞台,但我不知道该怎么做用作舞台或场景。

I tried creating a Stage inside initJFXPanel but this didn't work as it goes back to LoginManager before it has the chance to do anything, and I also tried setting the stage in createPopup but I wasn't sure what to use as the stage or the scene.

这是我的代码:

LoginManager类

LoginManager class

public class LoginManager {

    private boolean bSSOEnabled = true;

    private void Login() {

        // get company details

        if(bSSOEnabled) {
            new SSO();
        }

        // once SSO is done, continue with execution
    }
}

SSO类

public class SSO {

    private JFrame frame;
    private JFXPanel fxPanel;
    private JPanel containerPanel;
    final static String WEBVIEW = "WebView";

    public SSO(){
        createPopup();
    }

    private void createPopup(){

        Dimension size = new Dimension(480, 80);

        frame = new JFrame("Web Login");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        containerPanel = new JPanel(new CardLayout());

        fxPanel = new JFXPanel();
        fxPanel.setSize(size);

        Platform.runLater(() -> initJFXPanel(frame, fxPanel));

        containerPanel.add(fxPanel, WEBVIEW);

        frame.add(containerPanel, BorderLayout.CENTER);

        frame.setPreferredSize(size);
        frame.setResizable(false);
        frame.getRootPane().setWindowDecorationStyle(JRootPane.NONE);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

    }

    private void initJFXPanel(final JFrame frame, final JFXPanel fxPanel){

        Group group = new Group();
        Scene scene = new Scene(group);
        fxPanel.setScene(scene);

        WebView webview = new WebView();

        group.getChildren().add(webview);
        webview.setMinSize(500, 640);
        webview.setMaxSize(500, 640);

        CookieManager cookieManager = new CookieManager();
        java.net.CookieHandler.setDefault(cookieManager);

        webview.getEngine().load("http://google.com/");


        if(webview.getEngine().getLocation().equalsIgnoreCase("cookie url")) {
            // harvest the cookies
        }
        else if(webview.getEngine().getLocation().equalsIgnoreCase("end url")) {
            frame.dispose();
        }

    }

}

任何帮助表示赞赏。我已经被困在这一整天了,我不知道该怎么做。

Any help is appreciated. I've been stuck on this for a whole day and am not sure what to do at all.

推荐答案

如果您的申请是一个Swing应用程序,您需要使用 WebView ,然后正确的方法是您在代码中显示的方法,即使用Swing窗口并嵌入 WebView JFXPanel 中。混合来自两个框架的窗口通常是一个坏主意,因此我建议完全避免使用 Stage

If your application is a Swing application, and you need to use a WebView, then the correct approach is the one you have shown in your code, i.e. use a Swing window and embed the WebView in a JFXPanel. It is usually a bad idea to mix windows from the two frameworks, so I would recommend avoiding using a Stage at all.

在用户关闭窗口之前在Swing块中创建代码的方法,即JavaFX的Swing等价物 Stage.showAndWait()调用,是使用 JDialog 并使其成为模态。除了阻止对任何其他窗口的输入之外,这将阻止执行(AWT事件调度线程)直到对话框被解除。

The way to make code in Swing block until the user dismisses a window, i.e. the Swing equivalent of a JavaFX Stage.showAndWait() call, is to use a JDialog and make it modal. As well as blocking input to any other window, this will block execution (of the AWT Event Dispatch thread) until the dialog is dismissed.

这使得这个有点棘手的是你有三个线程可以使用:AWT事件调度线程,JavaFX应用程序线程和主线程。显示模态对话框将阻止AWT事件调度线程,但您想要(如果我正确理解了问题)要阻止的主线程。此外,您只能在AWT事件调度线程上创建,修改和显示Swing组件,并且您只能在JavaFX应用程序线程上创建,修改和显示JavaFX节点。

What makes this a little trickier is that you have three threads to work with: the AWT Event Dispatch Thread, the JavaFX Application Thread, and the main thread. Showing the modal dialog will block the AWT Event Dispatch thread, but you want (if I understand the question correctly) the main thread to be blocked. Additionally, you must only create, modify, and show your Swing components on the AWT Event Dispatch thread, and you must only create, modify, and show your JavaFX nodes on the JavaFX Application Thread.

所以我认为你想要这样的东西:

So I think you want something like this:

public class SSO {

    private JDialog dialog;
    private JFXPanel fxPanel;
    private JPanel containerPanel;
    final static String WEBVIEW = "WebView";

    public SSO(){
        // creates Swing components: MUST be called on AWT Event thread
        createPopup();
    }

    private void createPopup(){

        Dimension size = new Dimension(480, 80);

        dialog = new JDialog();
        dialog.setTite("Web Login");

        // make dialog modal:
        dialog.setModalityType(ModalityType.APPLICATION_MODAL);

        // oops: don't want this:
        // dialog.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        // but this:
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        containerPanel = new JPanel(new CardLayout());

        fxPanel = new JFXPanel();
        fxPanel.setSize(size);

        Platform.runLater(() -> initJFXPanel(dialog, fxPanel));

        containerPanel.add(fxPanel, WEBVIEW);

        dialog.add(containerPanel, BorderLayout.CENTER);

        dialog.setPreferredSize(size);
        dialog.setResizable(false);
        dialog.getRootPane().setWindowDecorationStyle(JRootPane.NONE);

        dialog.pack();
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);

    }

    private void initJFXPanel(final JDialog dialog, final JFXPanel fxPanel){

        Group group = new Group();
        Scene scene = new Scene(group);
        fxPanel.setScene(scene);

        WebView webview = new WebView();

        group.getChildren().add(webview);
        webview.setMinSize(500, 640);
        webview.setMaxSize(500, 640);

        CookieManager cookieManager = new CookieManager();
        java.net.CookieHandler.setDefault(cookieManager);

        webview.getEngine().load("http://google.com/");


        if(webview.getEngine().getLocation().equalsIgnoreCase("cookie url")) {
            // harvest the cookies
        }
        else if(webview.getEngine().getLocation().equalsIgnoreCase("end url")) {
            // this will hide the dialog and release the event dispatch thread
            // that is waiting for it, but it must be called on the event dispatch thread
            // not sure of your exact requirements, but you may need to do this
            // in the if clause as well?
            SwingUtilities.invokeLater(() -> dialog.setVisible(false));
        }

    }

}

现在,如果您实例化 SSO ,代码将会阻止,直到对话框被解除。但是,您必须在AWT Event Dispatch线程上执行此操作。在主线程上等待完成的技巧是将 new SSO()的调用表示为 FutureTask ,提交 FutureTask SwingUtilities.invokeLater(),然后,回到主线程,调用 get() FutureTask 上的:这将阻塞,直到任务完成。你需要在这里小心:如果你无意中在事件调度线程上执行此操作,最终会陷入死锁,因为事件调度线程将阻塞,等待事件调度线程发生某些事情...所以你可能想要一个防止这是安全的。

Now if you instantiate SSO, the code will block until the dialog is dismissed. However, you must do that on the AWT Event Dispatch thread. The trick to waiting for that to complete on the main thread is to represent the call to new SSO() as a FutureTask, submit the FutureTask to SwingUtilities.invokeLater(), and then, back on the main thread, call get() on the FutureTask: this will block until the task completes. You need to be careful here: if you inadvertently do this on the Event Dispatch Thread, you end up in deadlock, as the event dispatch thread will block, waiting for something to happen on the event dispatch thread... So you probably want a guard against that to be safe.

所以你的代码可能需要看起来像这样:

So your code probably needs to look like this:

public class LoginManager {

    private boolean bSSOEnabled = true;

    private void Login() {

        // get company details

        if(bSSOEnabled) {
            if (SwingUtilities.isEventDispatchThread()) {
                // already on EDT, just invoke the SSO which will block 
                // until the dialog is dismissed:
                new SSO();
            } else {
                // create FutureTask to show dialog, etc:
                FutureTask<Void> ssoTask = new FutureTask<>(SSO:new, null);
                // submit task to AWT event dispatch thread:
                SwingUtilities.invokeLater(ssoTask);
                // wait for task to complete, i.e. for dialog to be dismissed:
                try {
                    ssoTask.get();
                } catch (InterruptedException exc) {
                    // thread was interrupted, representing cancelation of some kind:
                    System.out.println("Thread interrupted");
                    Thread.currentThread().interrupt();
                } catch (ExecutionException ee) {
                    // something went wrong...
                    throw new RuntimeException(ee);
                }
            }
        }



    // once SSO is done, continue with execution
    }
}

这篇关于在JavaFX应用程序中使用showAndWait的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆