在 javafx 应用程序的 swingnode 内部使用时,JDialogs 模态行为不起作用

JDialogs Modal behaviour not working when used inside swingnode of javafx application

我有一个完整的 Java Swing 应用程序。现在我有另一个 Java-FX 应用程序。

我必须使用 Java-FX 中的 SwingNode 将 Swing 应用程序集成到 Java-FX 应用程序中。

当我这样做时,一切看起来都很好,除了 Swing 应用程序中对话框的模态行为消失了。

有什么方法可以解决此类集成中的这种行为吗?

我的 Swing 应用程序的代码片段:

class Solve extends JFrame implements ActionListener {
    static JFrame f = null;

    public JFrame getFrame() {
        f = new JFrame("frame");
        Solve s = new Solve();
        JPanel p = new JPanel();
        JButton b = new JButton("click");
        b.addActionListener(s);
        p.add(b);
        f.add(p);
        f.setSize(200, 200);
        return f;
    }

    public void actionPerformed(ActionEvent e) {
        String s = e.getActionCommand();
        if (s.equals("click")) {
            JDialog d = new JDialog(f, "dialog Box", Dialog.ModalityType.DOCUMENT_MODAL);
            JLabel l = new JLabel("this is a dialog box");
            d.add(l);
            d.setSize(100, 100);
            d.setVisible(true);
        }
    }
}

我的 JavaFX 应用程序的代码片段:

public class SolveJavaFX extends Application {

    @Override
    public void start(Stage stage) {
        final SwingNode swingNode = new SwingNode();
        createAndSetSwingContent(swingNode);    
        BorderPane pane = new BorderPane();     
        pane.setCenter(swingNode);  
        stage.setScene(new Scene(pane, 400, 450));
        stage.show();
    }
    private void createAndSetSwingContent(final SwingNode swingNode) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Solve solve = new Solve();              
                swingNode.setContent((JComponent) solve.getFrame().getContentPane());
            }
        });
    }   
    public static void main(String[] args) {
        launch(args);
    }
}

第一个问题是当您创建对话框时,您使用的是从未使用过的 JFrame。而是使用 null.

JDialog d = new JDialog(null, "dialog Box", Dialog.ModalityType.APPLICATION_MODAL);

这对我有用。请注意,它是 APPLICATION_MODAL 而不是 DOCUMENT_MODAL

如果我想使用 DOCUMENT_MODAL,那么我需要正确的 window。我已经创建了一个实用方法,可以帮助您。

Window findWindow(Container c ){
    Container p = c.getParent();
    while ( !(p instanceof Window )){
        p = p.getParent();
    }
    return (Window)p;
}

现在显示对话框时。

        JDialog d = new JDialog(findWindow(panel), "dialog Box", Dialog.ModalityType.DOCUMENT_MODAL);

这两者都会显示对话框,并且在对话框关闭之前不会处理对原始框架的输入。 请注意,在第二个版本中,您需要保留对 jpanel 的引用。

我认为使用 APPLICATION_MODAL 更可靠一些。 find window 应该适用于 swing 和 javafx 版本。在 openjdk11 和 openjfx11 上,SwingNode 根本不起作用。

此解决方案禁用对其他摆动组件的输入。不会禁用其他 javafx 组件。在以下示例中,javafx 按钮在显示对话框时仍会接收输入。

package sample;

import javax.swing.*;
import java.awt.event.*;
import java.awt.Dialog;
import java.awt.Window;
import java.awt.Dimension;
import java.awt.Container;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.embed.swing.SwingNode;
import javafx.scene.layout.FlowPane;
import java.awt.EventQueue;
public class SolveJavaFX extends Application {

    @Override
    public void start(Stage stage) {
        final SwingNode swingNode = new SwingNode();
        createAndSetSwingContent(swingNode);    
        FlowPane pane = new FlowPane();

        pane.getChildren().add(swingNode);
        Button but = new Button("fx button");
        but.setOnMouseClicked(evt->System.out.println("click!"));
        pane.getChildren().add(but);
        stage.setScene(new Scene(pane, 400, 450));
        stage.show();
    }

    JPanel getPanel(){
        JPanel p = new JPanel();
        JButton b = new JButton("click");
        b.addActionListener(evt->{
            JDialog d = new JDialog(null, "dialog Box", Dialog.ModalityType.APPLICATION_MODAL);
            JLabel l = new JLabel("this is a dialog box");
            d.add(l);
            d.setSize(100, 100);
            d.setVisible(true);
        } );
        p.add(b);
        return p;
    }

    private void createAndSetSwingContent(final SwingNode swingNode) {
        SwingUtilities.invokeLater(() -> {
                swingNode.setContent( getPanel() );

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