Swing应用程序中的JavaFX 2.2 JFXPanel显示了Swing模式对话框

时间:2014-02-19 18:10:23

标签: java swing javafx-2

我有一个完善的Swing应用程序,我正在使用JFXPanel部分升级到JavaFX。带有JFXPanel的JFrame从另一个类中获取一个场景,它在代码中创建一个根节点(不是FXML),它是一个HBox,带有一个非常简单的左侧边栏,带有动态生成的链接和按钮和东西,右边是根据用户在左侧按下的按钮动态填充内容。右侧内容由几组FXML和控制器类构成。

在这些右侧内容类中,我必须提出一些标准的Swing JDialog或JOptionPane,它们在构造函数中接受父(JFrame或JDialog)以进行屏幕放置和模态。 (这些JDialogs和JOptionPanes来自我们多年来编写的常用组件库)

在运行时有没有办法让我获得对包含JFXPanel的JFrame的引用,以便我可以用适当的模态实例化它们?

**编辑**

  1. 模态实际上有效
  2. 我现在真正想做的是将对话框放在父母的中心。当然,我相信这对我将来有很多其他原因都有用。
  3. 这是一个缩写版本。我已经能够运行它,所以它应该适合你。
  4. 如果这有点乱,我道歉:-S
  5. 非常感谢您的帮助!
  6. 这是主要课程:

    import java.awt.*;
    import java.io.IOException;
    import javafx.application.Platform;
    import javafx.embed.swing.JFXPanel;
    import javafx.scene.Scene;
    import javafx.fxml.FXML;
    import javax.swing.*;
    
    public class SwingMain extends JFrame {
    
        public static final String TITLE = "Main JFrame";
    
        private GridBagLayout gridBagLayout1 = new GridBagLayout();
    
        private JPanel jPanel = new JPanel();
    
        private JFXPanel jfxPanel = new JFXPanel();
        private JFXSceneMaker sceneMaker = new JFXSceneMaker(this);
    
        public SwingMain() {
            super();
            try {
                init();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            final SwingMain swingMainTest = new SwingMain();
            swingMainTest.setVisible(true);
        }
    
        void init() throws Exception {
            Dimension minimumSize = new Dimension(1280, 864);
            this.setMinimumSize(minimumSize);
            this.setPreferredSize(minimumSize);
            jPanel.setLayout(gridBagLayout1);
            this.setTitle(TITLE);
    
            Platform.setImplicitExit(false);
            try {
                prepareScene();
            } catch (Exception ex) {
                // log error
            }
    
            getContentPane().add(jPanel);
            jPanel.add(jfxPanel, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0,
                    GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                            0, 0, 0, 0), 0, 0));
        }
    
        protected void prepareScene() {
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        Scene scene = sceneMaker.getScene();
                        jfxPanel.setScene(scene);
                    } catch (IOException ioex) {
                        // log error
                    }
                }
            });
        }
    }
    

    这是为JFXPanel提供场景的类

    import java.io.IOException;
    
    import javax.swing.JFrame;
    import javax.swing.SwingUtilities;
    
    import javafx.animation.*;
    import javafx.application.Platform;
    import javafx.collections.ListChangeListener;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.fxml.FXMLLoader;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.SceneBuilder;
    import javafx.scene.control.Hyperlink;
    import javafx.scene.control.Label;
    import javafx.scene.control.Toggle;
    import javafx.scene.control.ToggleButton;
    import javafx.scene.control.ToggleGroup;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.HBox;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.Priority;
    import javafx.scene.layout.Region;
    import javafx.scene.layout.StackPane;
    import javafx.scene.layout.VBox;
    import javafx.scene.text.Text;
    import javafx.scene.text.TextAlignment;
    import javafx.util.Duration;
    
    public class JFXSceneMaker {
        private static final Interpolator interpolator = Interpolator.SPLINE(0.4829, 0.5709, 0.6803, 0.9928);
    
        // To obtain a scalable page layout, you define all positions and sizes in terms of “root em” (rem), 
        //  the em size of the default font
        private final double rem = Math.rint(new Text("").getLayoutBounds().getHeight());
        private double SIDEBAR_WIDTH = rem * 13;
        private Pane root;
        private StackPane currentPane, sparePane;
        private VBox sideBar;
        private int currentPaneIndex = 0;
        private Timeline timeline;
        private ContentPane nextPane = null;
        private int nextPaneIndex;
        private JFrame swingParent;
    
        public static final String TITLE = "JavaFX Rocks!";
    
        private ContentPane[] panes;
    
        public JFXSceneMaker(JFrame frame) {
            // This is a reference to the Swing parent JFrame that I want to place the JOptionPanes and JDialogs over
            this.swingParent = frame;
        }
    
        public Scene getScene() throws IOException {
    
            Parent pane1 = FXMLLoader.load(Pane1Controller.class.getResource("pane1contentPane.fxml"));
            Parent pane2 = FXMLLoader.load(Pane2Controller.class.getResource("pane2contentPane.fxml"));
            Parent pane3 = FXMLLoader.load(Pane3Controller.class.getResource("pane3contentPane.fxml"));
    
            panes = new ContentPane[]{
                new ContentPane("Panel1", pane1),
                new ContentPane("Panel2", pane2),
                new ContentPane("Panel3", pane3)
            };
    
            // create the left-hand side bar
            sideBar = new VBox(0);
            sideBar.setId("SideBar");
            sideBar.setPrefWidth(SIDEBAR_WIDTH);
            sideBar.setMinWidth(SIDEBAR_WIDTH);
            sideBar.setMaxWidth(SIDEBAR_WIDTH);
            sideBar.setStyle("-fx-background-color: #25282c");
            HBox.setHgrow(sideBar, Priority.NEVER);
    
            PersistentButtonToggleGroup toggleGroup = new PersistentButtonToggleGroup();
            for (int i=0; i < panes.length; i++) {
                final int index = i;
                final ContentPane contentPane = panes[i];
                final ToggleButton button = new ToggleButton(contentPane.getName());
                if (i==0) {
                    Platform.runLater(new Runnable() {
                        @Override public void run() {
                            button.setSelected(true);
                            button.requestFocus();
                        }
                    });
                }
                button.setMaxWidth(Double.MAX_VALUE);
                button.setAlignment(Pos.CENTER_LEFT);
                button.setTextAlignment(TextAlignment.LEFT);
                button.setToggleGroup(toggleGroup);
                button.setOnAction(new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent t) {
                        switchcontentPane(contentPane, index);
                    }
                });
                sideBar.getChildren().add(button);
            }
    
            // current Pane and sparePane are used for switching between panes
            currentPane = new StackPane();
            currentPane.getChildren().setAll(panes[0].getContent());
    
            sparePane = new StackPane();
            sparePane.setVisible(false);
    
            // contentPanePane is the right side of the scene where the relevant content is displayed
            StackPane contentPanePane = new StackPane();
            HBox.setHgrow(contentPanePane, Priority.ALWAYS);
    
            contentPanePane.getChildren().addAll(currentPane, sparePane);
            AnchorPane.setTopAnchor(currentPane, 0.0);
            AnchorPane.setRightAnchor(currentPane, 0.0);
            AnchorPane.setBottomAnchor(currentPane, 0.0);
            AnchorPane.setLeftAnchor(currentPane, 0.0);
    
            //create root node
            root = new HBox();
            root.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
            root.setPrefSize(1250, 844);
    
            root.getChildren().addAll(sideBar,contentPanePane);
    
            return SceneBuilder.create()
                    .root(root)
                    .build();
        }
    
        public void switchcontentPane(ContentPane newcontentPane, final int contentPaneIndex) {
            // check if existing animation running
            if (timeline != null) {
                nextPane = newcontentPane;
                nextPaneIndex = contentPaneIndex;
                timeline.setRate(4);
                return;
            } else {
                nextPane = null;
                nextPaneIndex = -1;
            }
            // load new content
            sparePane.getChildren().setAll(newcontentPane.getContent());
            sparePane.setCache(true);
            currentPane.setCache(true);
            // wait one pulse then animate
            Platform.runLater(new Runnable() {
                @Override public void run() {
                    // animate switch
                    if (contentPaneIndex > currentPaneIndex) { // animate from bottom
                        currentPaneIndex = contentPaneIndex;
                        sparePane.setTranslateY(root.getHeight());
                        sparePane.setVisible(true);
                        timeline = TimelineBuilder.create().keyFrames(
                                    new KeyFrame(Duration.millis(0), 
                                        new KeyValue(currentPane.translateYProperty(),0,interpolator),
                                        new KeyValue(sparePane.translateYProperty(),root.getHeight(),interpolator)
                                    ),
                                    new KeyFrame(Duration.millis(800), 
                                        animationEndEventHandler,
                                        new KeyValue(currentPane.translateYProperty(),-root.getHeight(),interpolator),
                                        new KeyValue(sparePane.translateYProperty(),0,interpolator)
                                    )
                                )
                                .build();
                        timeline.play();
                    } else { // from top
                        currentPaneIndex = contentPaneIndex;
                        sparePane.setTranslateY(-root.getHeight());
                        sparePane.setVisible(true);
                        timeline = TimelineBuilder.create()
                                .keyFrames(
                                    new KeyFrame(Duration.millis(0), 
                                        new KeyValue(currentPane.translateYProperty(),0,interpolator),
                                        new KeyValue(sparePane.translateYProperty(),-root.getHeight(),interpolator)
                                    ),
                                    new KeyFrame(Duration.millis(800), 
                                        animationEndEventHandler,
                                        new KeyValue(currentPane.translateYProperty(),root.getHeight(),interpolator),
                                        new KeyValue(sparePane.translateYProperty(),0,interpolator)
                                    )
                                )
                                .build();
                        timeline.play();
                    }
                }
            });
        }
    
        private EventHandler<ActionEvent> animationEndEventHandler = new EventHandler<ActionEvent>() {
            @Override public void handle(ActionEvent t) {
                // switch panes
                StackPane temp = currentPane;
                currentPane = sparePane;
                sparePane = temp;
                // cleanup
                timeline = null;
                currentPane.setTranslateY(0);
                sparePane.setCache(false);
                currentPane.setCache(false);
                sparePane.setVisible(false);
                sparePane.getChildren().clear();
                // start any animations
                // check if we have a animation waiting
                if (nextPane != null) {
                    switchcontentPane(nextPane, nextPaneIndex);
                }
            }
        };
    
        public static class PersistentButtonToggleGroup extends ToggleGroup {
            PersistentButtonToggleGroup() {
                super();
                getToggles().addListener(new ListChangeListener<Toggle>() {
                    @Override
                    public void onChanged(Change<? extends Toggle> c) {
                        while (c.next())
                            for (final Toggle addedToggle : c.getAddedSubList())
                                ((ToggleButton) addedToggle).addEventFilter(MouseEvent.MOUSE_RELEASED,
                                        new EventHandler<MouseEvent>() {
                                            @Override
                                            public void handle(MouseEvent mouseEvent) {
                                                if (addedToggle.equals(getSelectedToggle()))
                                                    mouseEvent.consume();
                                            }
                                        });
                    }
                });
            }
        }
    }
    

    这是包含右侧窗格

    内容的类
    import javax.swing.JFrame;
    
    import javafx.scene.Parent;
    
    public class ContentPane {
        private String name;
        private Parent content;
        protected JFrame swingParent;
    
        public ContentPane(String name, Parent content) {
            this.name = name;
            this.content = content;
        }
    
        public String getName() {
            return name;
        }
    
        public Parent getContent() {
            return content;
        }
    }
    

    这是第一个内容窗格的fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    
    <AnchorPane fx:id="content" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Pane1Controller">
        <children>
            <VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                <children>
                    <Label maxWidth="1.7976931348623157E308" minHeight="-Infinity" prefHeight="48.0" style="-fx-font-size: 24; -fx-text-fill: #e6e6e6; -fx-background-color: #0072bc; -fx-label-padding: 0 0 0 12;" text="Pane 1" VBox.vgrow="NEVER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    
                    </Label>
                    <AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                        <children>
                            <StackPane prefHeight="25.0" prefWidth="125.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                                <children>
                                    <Button fx:id="optionButton1" mnemonicParsing="false" text="Show a JOptionPane" />
                                </children>
                            </StackPane>
                        </children>
                    </AnchorPane>
                </children>
            </VBox>
        </children>
    </AnchorPane>
    

    这是第一个窗格的控制器

    import java.net.URL;
    import java.util.ResourceBundle;
    
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    
    import javafx.event.ActionEvent;
    import javafx.event.Event;
    import javafx.event.EventHandler;
    import javafx.fxml.Initializable;
    import javafx.fxml.FXML;
    import javafx.scene.control.Button;
    
    public class Pane1Controller implements Initializable {
        @FXML private Button optionButton1;
    
        private JFrame swingParent;
    
        @Override
        public void initialize(URL arg0, ResourceBundle arg1) {
    
            optionButton1.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    showJOptionPane();
                }
            });
        }
    
        private void showJOptionPane() {
            JOptionPane.showMessageDialog(swingParent, "So...now what?");
        }
    
    }
    

    第二个窗格fxml ...

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    
    <AnchorPane fx:id="content" prefHeight="73.0" prefWidth="161.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Pane2Controller">
        <children>
            <VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                <children>
                    <Label maxWidth="1.7976931348623157E308" minHeight="-Infinity" prefHeight="48.0" style="-fx-font-size: 24; -fx-text-fill: #e6e6e6; -fx-background-color: #0072bc; -fx-label-padding: 0 0 0 12;" text="Pane 2" VBox.vgrow="NEVER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    
                    </Label>
                    <AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                        <children>
                            <StackPane prefHeight="25.0" prefWidth="125.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                                <children>
                                    <Button fx:id="optionButton2" mnemonicParsing="false" text="Show another JOptionPane" />
                                </children>
                            </StackPane>
                        </children>
                    </AnchorPane>
                </children>
            </VBox>
        </children>
    </AnchorPane>
    

    第二个窗格控制器......

    import java.net.URL;
    import java.util.ResourceBundle;
    
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    
    import javafx.event.ActionEvent;
    import javafx.event.Event;
    import javafx.event.EventHandler;
    import javafx.fxml.Initializable;
    import javafx.fxml.FXML;
    import javafx.scene.control.Button;
    
    public class Pane2Controller implements Initializable {
        @FXML private Button optionButton2;
    
        private JFrame swingParent;
    
        @Override
        public void initialize(URL arg0, ResourceBundle arg1) {
    
            optionButton2.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    showJOptionPane();
                }
            });
        }
    
        private void showJOptionPane() {
            JOptionPane.showMessageDialog(swingParent, "Here we go again.");
        }
    
    }
    

    第三个窗格fxml ...

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    
    <AnchorPane fx:id="content" prefHeight="73.0" prefWidth="161.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Pane3Controller">
        <children>
            <VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                <children>
                    <Label maxWidth="1.7976931348623157E308" minHeight="-Infinity" prefHeight="48.0" style="-fx-font-size: 24; -fx-text-fill: #e6e6e6; -fx-background-color: #0072bc; -fx-label-padding: 0 0 0 12;" text="Pane 3" VBox.vgrow="NEVER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    
                    </Label>
                    <AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                        <children>
                            <StackPane prefHeight="25.0" prefWidth="125.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
                                <children>
                                    <Button fx:id="optionButton3" mnemonicParsing="false" text="Show yet another JOptionPane" />
                                </children>
                            </StackPane>
                        </children>
                    </AnchorPane>
                </children>
            </VBox>
        </children>
    </AnchorPane>
    

    第三控制器......

    import java.net.URL;
    import java.util.ResourceBundle;
    
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    
    import javafx.event.ActionEvent;
    import javafx.event.Event;
    import javafx.event.EventHandler;
    import javafx.fxml.Initializable;
    import javafx.fxml.FXML;
    import javafx.scene.control.Button;
    
    public class Pane3Controller implements Initializable {
        @FXML private Button optionButton3;
    
        private JFrame swingParent;
    
        @Override
        public void initialize(URL arg0, ResourceBundle arg1) {
    
            optionButton3.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    showJOptionPane();
                }
            });
        }
    
        private void showJOptionPane() {
            JOptionPane.showMessageDialog(swingParent, "Here we go again.");
        }
    
    }
    

1 个答案:

答案 0 :(得分:3)

JFXPanel扩展JComponent,因此您应该能够像使用任何Swing组件一样获得JFrame的运行时引用。我假设您正在使用类似getRootPane(...)的内容。

作为获取运行时引用的替代方法,您始终可以创建自己的扩展JFXPanel的类,并在自定义构造函数中传递对JFrame的引用。

修改

如果您将SwingMain课程改为singleton,您应该能够轻松获得对其中任何字段的引用。这是一个如何使用它的演示。

import java.awt.Color;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.*;
import javafx.scene.text.*;
import javax.swing.*;

public class SwingJFXCombo {

    /**
     * The control who starts everything.
     * This should have the references you need.
     * Uses the singleton pattern
     */
    public static class MainController{

        //Top level fields we may need access too
        JFXPanel jfxPanel;
        JPanel jp;
        JFrame frame;

        //Doing singleton stuff
        private static MainController instance;
        public static MainController getInstance(){
            if(instance == null){
                instance = new MainController();
            }
            return instance;
        }

        private MainController(){
            jfxPanel = new JFXPanel();
            jp = new JPanel();

            jp.add(jfxPanel);
            jp.setVisible(true);
            jp.setBackground(Color.CYAN);

            //Setup to display swing stuff
            frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            frame.add(jp);
            frame.pack();
        }

        public static void initialize(){
            getInstance();

            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    MainController mc = getInstance();
                    Scene scene = mc.initScene();
                    mc.jfxPanel.setScene(scene);
                }
            });
        }

        private Scene initScene(){
            Group  root  =  new  Group();
            Scene  scene  =  new  Scene(root, javafx.scene.paint.Color.ALICEBLUE);
            Text  text  =  new  Text(40,100,"JavaFX Scene");
            text.setFont(new Font(25));
            root.getChildren().add(text);
            return (scene);
        }
    }

    /**
     * Another random class for demonstration purposes
     * This would be similar to your FX Controllers
     */
    public static class RandomController{
        public void printFrameColor(){
            //Now from anywhere, I can get any of the top level items by calling the singleton
            System.out.println(MainController.getInstance().frame.getBackground());
        }
    }

    public static void main(String[] args){
        MainController.initialize();
        new RandomController().printFrameColor();


    }
}