我有一个使用JDesktopPane的旧Java Swing应用程序。我知道JavaFX并不支持这一点,并且MDI总体上不受欢迎。无论我想看看JavaFX中的类似应用程序是如何实现的,并且遇到了我在这里问的问题。
简而言之,我有一个包含带有JDesktopPane的SwingNode的JavaFX应用程序。在该桌面窗格中,我打开一个加载JavaFX场景的JInternalFrame。
问题是JInternalFrame场景包含一个菜单栏。菜单栏中的MenuItems可以使用键盘激活,但在鼠标事件中不会激活。
我认为鼠标事件没有进入JavaFX组件,而是可能转到Swing线程。我已经尝试过无数种方法来解决这个问题(例如Spark History Server)但是没有运气。
代码如下。任何建议都表示赞赏。
Test.java
package test;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Test extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainScene.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
MainScene.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<AnchorPane id="AnchorPane" prefHeight="508.0" prefWidth="665.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.MainSceneController">
<children>
<BorderPane fx:id="borderPane" prefHeight="200.0" prefWidth="320.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#handleAddInternalFrameAction" text="Add internal frame" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
</children>
</AnchorPane>
MainSceneController.java
package test;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.embed.swing.SwingNode;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.BorderPane;
import javax.swing.JDesktopPane;
import javax.swing.SwingUtilities;
public class MainSceneController implements Initializable {
JDesktopPane desktopPane = new JDesktopPane();
@FXML
BorderPane borderPane;
@FXML
private void handleAddInternalFrameAction(ActionEvent event) {
InternalFrame internalFrame = new InternalFrame();
desktopPane.add(internalFrame);
internalFrame.setVisible(true);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
final SwingNode swingNode = new SwingNode();
SwingUtilities.invokeLater(() -> {
swingNode.setContent(desktopPane);
});
borderPane.setCenter(swingNode);
}
}
InternalFrame.java
package test;
import java.awt.Dimension;
import java.io.IOException;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javax.swing.JInternalFrame;
public class InternalFrame extends JInternalFrame {
public InternalFrame() {
setTitle("InternalFrameScene.fxml");
setResizable(true);
setSize(300, 300);
setPreferredSize(new Dimension(300, 300));
JFXPanel jfxPanel = new JFXPanel();
add(jfxPanel);
Platform.runLater(new Runnable() {
@Override
public void run() {
try {
FXMLLoader fxmlLoader = new FXMLLoader(InternalFrame.class.getResource("InternalFrameScene.fxml"));
Scene scene = new Scene(fxmlLoader.load());
jfxPanel.setScene(scene);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
}
InternalFrameScene.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<AnchorPane fx:id="anchorPane" minHeight="400.0" minWidth="400.0" prefHeight="500.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.InternalFrameController">
<children>
<BorderPane fx:id="borderPane" prefHeight="500.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<MenuBar fx:id="menuBar" BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#closeMenuItemAction" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
</children>
</AnchorPane>
InternalFrameController.java
package test;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
public class InternalFrameController implements Initializable {
@FXML
private void closeMenuItemAction(ActionEvent event) {
System.out.println("closeMenuItemAction");
}
@Override
public void initialize(URL location, ResourceBundle resources) {}
}