当前位置: 首页 > 知识库问答 >
问题:

JavaFX modal stage在MAC上的行为异常

宗政斌
2023-03-14

我有一个JavaFX应用程序,它有子窗口或阶段。我处理所有阶段如何相互交互的方式如下:在我的主类中有一个名为GuiContainer的静态类集合。GUI容器如下所示:

public class GuiContainer {
    private final Stage stage;
    private final Scene scene;
    private final FXMLLoader loader;
    private final Controller controller;
    private final Parent parent;

    public GuiContainer(Stage stage, Scene scene, FXMLLoader loader, Controller controller, Parent parent) {
        this.stage = stage;
        this.scene = scene;
        this.loader = loader;
        this.controller = controller;
        this.parent = parent;
    }

    public Stage getStage() {
        return stage;
    }

    public Scene getScene() {
        return scene;
    }

    public FXMLLoader getLoader() {
        return loader;
    }

    public Controller getController() {
        return controller;
    }

    public Parent getParent() {
        return parent;
    }

    public static final GuiContainer createMain(Stage stage, String title, int width, int height, String pathToView) throws Exception {
        FXMLLoader loaderInner = new FXMLLoader(GuiContainer.class.getResource(pathToView));

        Parent parentInner = loaderInner.load();
        final Controller controllerInner = loaderInner.getController();

        Scene sceneInner = new Scene(parentInner, width, height);

        stage.setTitle(title);
        stage.setScene(sceneInner);

        GuiContainer guiContainer = new GuiContainer(
                stage, sceneInner, loaderInner, controllerInner, parentInner
        );

        controllerInner.start(guiContainer);

        return guiContainer;
    }

    public static final GuiContainer createModal(Window owner, String title, int width, int height, String pathToView) throws Exception {
        if (owner == null) {
            Log.error(GuiContainer.class.getSimpleName(), "Unable to create instance, missing window owner!");
            return null;
        }

        Stage stageInner = new Stage();

        FXMLLoader loaderInner = new FXMLLoader(GuiContainer.class.getResource(pathToView));

        Parent parentInner = loaderInner.load();
        Controller controllerInner = loaderInner.getController();

        Scene sceneInner = new Scene(parentInner, width, height);

        stageInner.setTitle(title);
        stageInner.setScene(sceneInner);

        stageInner.initStyle(StageStyle.DECORATED);
        stageInner.initModality(Modality.WINDOW_MODAL);
        stageInner.initOwner(owner);

        GuiContainer guiContainer = new GuiContainer(
                stageInner, sceneInner, loaderInner, controllerInner, parentInner
        );

        controllerInner.start(guiContainer);

        return guiContainer;
    }
}

这样我就可以从任何地方访问任何舞台或控制器。

所有可能的guiContainer在引导时只创建一次(在静态main(String[]args)中),然后任何人都可以从任何地方静态访问。

现在在主应用程序(初级阶段内的场景)中,我有一个树状视图,其中有一个自定义单元格工厂,当右键单击单元格时,会显示相应的上下文菜单。在这个上下文菜单中,我打开了一个child/modal stage,如下所示:

String containerName = "guiName";
GuiContainer container = Main.getGuiContainers().getOrDefault(containerName, null);
if(container == null) {
    Log.error(getClass().getSimpleName(), "Unable to find GuiContainer: " + containerName);
    return;
}

container.getStage().showAndWait();

现在,问题来了。JavaFX不要求将焦点放在子级上。例如,我不能键入TextField(在子级上),因为我在主级上注册了一个onKeyPress事件,它会捕获我按下的所有键。在这个子级上,我还有一个组合框,当我从组合框中选择一个项目时,子级最终会聚焦,主级不再捕获我按下的键。

我还尝试将模式更改为所有可能的值,并阅读它们在oracle上的操作。com,但这些信息对我都没有帮助。。。

我的代码有问题吗?或者这可能是JavaFX的问题吗?有什么想法吗?

编辑:这是我的应用程序覆盖启动方法:(我希望这能提供更多信息)

@Override
public void start(Stage stage) throws Exception {
    GuiContainer guiWindow1 = GuiContainer.createMain(stage, "Window1", 900, 460,
            "/com/project/app/gui/views/Window1.fxml");

    GuiContainer guiWindow2 = GuiContainer.createModal(stage, "Window2", 320, 240,
            "/com/project/app/gui/views/Window2.fxml");

    GuiContainer guiWindow3 = GuiContainer.createModal(stage, "Window3", 320, 240,
            "/com/project/app/gui/views/Window3.fxml");

    GuiContainer guiWindow4 = GuiContainer.createModal(stage, "Window4", 420, 360,
            "/com/project/app/gui/views/Window4.fxml");

    GuiContainer guiWindow5 = GuiContainer.createModal(stage, "Window5", 380, 460,
            "/com/project/app/gui/views/Window5.fxml");

    guiWindow5.getStage().setResizable(false);

    guiContainers.put("guiWindow1", guiWindow1);
    guiContainers.put("guiWindow2", guiWindow2);
    guiContainers.put("guiWindow3", guiWindow3);
    guiContainers.put("guiWindow4", guiWindow4);
    guiContainers.put("guiWindow5", guiWindow5);

    guiWindow1.getStage().show();
}

EDIT2:这是我如何注册onKeyPed侦听器:(在我的父控制器init()方法中)

getGuiContainer().getScene().setOnKeyPressed((e) -> {
    Log.info(getClass().getSimpleName(), "Key pressed: " + e.getCode().getName());

    Macro macro = Main.getProject().getSelectedMacro();
    if(macro == null) {
        Log.error(getClass().getSimpleName(), "Unable to find selected macro");
        return;
    }

    if (e.getCode() == KeyCode.ESCAPE) {
        macro.getNodePlacement().reset();
        macro.cancelSelect();
        macro.repaint();
    } else if(e.getCode() == KeyCode.DELETE) {
        macro.deleteSelectedNodes();
    }
});

EDIT3:这就是我的抽象控制器类的样子——我希望这能提供更好的洞察力

public abstract class Controller {

    private GuiContainer guiContainer;

    public final GuiContainer getGuiContainer() {
        return guiContainer;
    }

    public final void start(GuiContainer guiContainer) {
        this.guiContainer = guiContainer;

        init();
    }

    public abstract void init(); // this is where the onKeyPressed is registered, when extending the abstract class

    public abstract void reset();

    public abstract void refresh();

}

重要编辑:这只发生在MAC平台上,我在windows上运行相同的应用程序,没有这样的问题。

共有1个答案

谯振国
2023-03-14

你能把你舞台的构造器的代码贴出来吗?

只是医生的一张便条:

请注意,显示模态阶段并不一定会阻止调用者。show()方法会立即返回,无论舞台的形式如何。如果需要在模式阶段隐藏(关闭)之前阻止调用方,请使用showAndWait()方法。在阶段可见之前,必须初始化模态。

编辑——我错了,我没有注意到createModal()方法。在我的一些定制阶段,我最终做的是:

    Platform.runLater(() -> somecontrol.requestFocus());

(显然,如果lambda在当前语言级别不可用,java 8会重写run()方法(

但我只在非模态阶段这样做。模态阶段应该自动聚焦。

根据模态文件,应用程序_模态应该做你期望的事情(包括阻止其他窗口的事件):

APPLICATION_MODAL定义了一个模式窗口,用于阻止事件传递到任何其他应用程序窗口。

在调用initOwner之前,先用WINDOW_MODAL调用InitModal。请看:

WINDOW_MODAL public static final MODAL WINDOW_MODAL定义了一个模式窗口,阻止事件传递到其整个所有者窗口层次结构。注:模态设置为WINDOW_MODAL但其所有者为空的阶段,被视为模态设置为NONE。

If requestFocus()(在模态阶段显示后调用,在UI线程中对吗?)没有聚焦,我猜你的主窗口会自动将其取回。

 类似资料:
  • 我试图bin/cassandra-f和我得到以下错误。 xss=-ea-javaagent:bin/./lib/jamm-0.2.5.jar-XX:UseThreadPriorityPolicy-XX:ThreadPriorityPolicy=42-Xms2048M-Xmx2048M-Xmn512M-XX:线程“main”java.lang.NoClassDefFoundError:org/apa

  • 我安装了最新版本的Java,当我尝试运行eclipse时,它会说: JVM的版本不适合本产品。版本:需要或更高版本。 为什么?我该怎么办?

  • 我最近在我的Mac上下载了JDK7U25(我运行的是OSX10.7.5)用于我的java developers类。在http://www.Oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html从Oracle下载了.dmg文件并成功安装了软件包之后,我尝试在Library>Java>JavaVirtualMac

  • 当我试图运行测试套件时,在Mac上遇到了这个异常,我们在这里使用的是maven项目,今天早上eclipse挂起了,我强制退出,然后重新启动了同样的测试,但后来无法运行测试。我做了刷新、清理、重新安装testNG、用新的eclipse实例重新配置eclipse并导入maven项目,但却得到了同样的异常。相同的maven项目将在其他Mac上运行,请建议这里缺少的任何方法。

  • 我使用. net core 2.1和C#开发了一个应用程序,在这个应用程序中,我在Windows版本中通过HTTPS(SSL)调用API,自助式应用程序可以正常工作,但在Mac上我收到了以下错误: 系统。无法建立SSL连接,请参见内部异常。-

  • 问题内容: 我可以在PC上运行,但是在Mac上,可执行文件是Eclipse.app -如何在命令行中使用参数运行它? 问题答案: 如果使用终端CD到Eclipse安装目录,则将看到一个名为的目录。CD到该目录下应该有一个名为的可执行文件。 我相信您可以通过使用参数执行可执行文件来从命令行启动Eclipse ,如下所示: ./eclipse-干净