简体   繁体   English

聚焦时如何将 JavaFX Popup 带到前面?

[英]How to bring JavaFX Popup to front when focused?

I have some JavaFX Popup in my application.我的应用程序中有一些 JavaFX Popup And when any of these popups is foucsed, I need it bring on top of every other popups regardless of it's index in Window.getWindows() .当这些弹出窗口中的任何一个被聚焦时,我需要它位于所有其他弹出窗口之上,而不管它在Window.getWindows()的索引如何。

I've tried to call method like toFront but it's not in Popup class.我试图调用像toFront这样的方法,但它不在Popup类中。 I've also tried to change index of focused Popup in Window.getWindows() but that also didn't worked because I don't know how to interchange index of two elements in a ObservableList .我还尝试更改Window.getWindows()中重点Popup索引,但这也不起作用,因为我不知道如何交换ObservableList中两个元素的索引。

eg例如

Let's say I have two Popup called p1 and p2 and in each I have nodes n1 and n2 respectively which are used to move these popup, So whenever n1 is dragged p1 should come on top and when n2 is dragged p2 should come on top.假设我有两个名为p1p2 Popup窗口,在每个弹出窗口中,我分别有节点n1n2用于移动这些弹出窗口,因此无论何时拖动n1p1都应该在顶部,当拖动n2时, p2应该在顶部。

Here is my minimal example:这是我的最小示例:

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Popup;
import javafx.stage.Stage;

public class Example extends Application{

    public static void main(String... arguments){

        launch(arguments);
    }

    public void applyTo(Pane node, Popup parent){

        final double[] dragDelta = new double[2];

        node.setOnMousePressed(e -> {
            dragDelta[0] = parent.getX() - e.getScreenX();
            dragDelta[1] = parent.getY() - e.getScreenY();
            //code to bring parent Popup to front
        });

        node.setOnMouseDragged(e -> {
            parent.setX(e.getScreenX() + dragDelta[0]);
            parent.setY(e.getScreenY() + dragDelta[1]);
        });
    }

    @Override
    public void start(Stage primaryStage) throws Exception{

        Button b1 = new Button("Open p1");
        Button b2 = new Button("Open p2");

        HBox n1 = new HBox(new Label("This is p1"));
        HBox n2 = new HBox(new Label("This is p2"));
        n1.setMinSize(200, 120);
        n2.setMinSize(200, 120);
        n1.setStyle("-fx-background-color: blue; -fx-background-radius: 4px;");
        n2.setStyle("-fx-background-color: red; -fx-background-radius: 4px;");
        n1.setAlignment(Pos.CENTER);
        n2.setAlignment(Pos.CENTER);

        Popup p1 = new Popup();
        Popup p2 = new Popup();
        p1.getContent().add(n1);
        p2.getContent().add(n2);

        applyTo(n1, p1);
        applyTo(n2, p2);

        b1.setOnAction(event -> {
            if(!p1.isShowing()) p1.show(primaryStage);
            else p1.hide();
        });
        b2.setOnAction(event -> {
            if(!p2.isShowing()) p2.show(primaryStage);
            else p2.hide();
        });

        HBox root = new HBox(10, b1, b2);
        root.setAlignment(Pos.CENTER);

        primaryStage.setScene(new Scene(root, 500, 200));
        primaryStage.show();
    }

}

So what is the solution for this problem?那么这个问题的解决方案是什么?

For some reason I don't understand, toFront/back is only implemented on Stage, not on its parent classes even though the actual collaborator that manages the stacking is already available in Window:出于某种原因,我不明白,toFront/back 仅在 Stage 上实现,而不是在其父类上实现,即使管理堆叠的实际协作者已经在 Window 中可用:

The implementation in Stage: Stage中的实现:

/**
 * Bring the {@code Window} to the foreground.  If the {@code Window} is
 * already in the foreground there is no visible difference.
 */
public void toFront() {
    if (getPeer() != null) {
        getPeer().toFront();
    }
}

getPeer() is a package-private method in Window that returns the internal class TKStage. getPeer()是 Window 中的包私有方法,它返回内部类 TKStage。 So if you are allowed to go dirty (because accessing an internal class and having to access via reflection - all with the usual loud "Beware"!) would be:因此,如果您被允许变脏(因为访问内部类并且必须通过反射访问 - 所有这些都带有通常的响亮“小心”!)将是:

protected void toFront(Popup popup) {
    // use your favorite utility method to invoke a method  
    TKStage peer = (TKStage) FXUtils.invokeGetMethodValue(Window.class, popup, "getPeer");
    if (peer != null) {
        peer.toFront();
    }
}

Requires to export/open not-exported packages in javafx.graphics - compiler and runtime errors will guide you (my context is heavily tweaked anyway, so don't know exactly which are added by this)需要在 javafx.graphics 中导出/打开未导出的包 - 编译器和运行时错误将指导您(我的上下文无论如何都经过了大量调整,所以不知道到底添加了哪些)

Here is the solution with stages it is the only work around I have found at all even though you hate the idea of having multiple stages if you want the functionality this is it.这是带有阶段的解决方案,它是我发现的唯一解决方法,即使您讨厌拥有多个阶段的想法,如果您想要这样的功能。 If you decide to stick with leaving them in the background thats cool too.如果您决定坚持将它们留在背景中,那也很酷。 An idea to solve your too may stages dilemma is to use a queue of stages remove when in use and if all are shown add a new one when a stage is hidden send to the end of the queue解决您的太可能阶段困境的一个想法是使用阶段队列在使用时删除,如果所有阶段都显示,则在阶段隐藏时添加一个新阶段发送到队列末尾

public class Example extends Application {


    public void applyTo(Pane node, Stage parent, Stage primaryStage){

        final double[] dragDelta = new double[2];

        node.setOnMousePressed(e -> {
            dragDelta[0] = parent.getX() - e.getScreenX();
            dragDelta[1] = parent.getY() - e.getScreenY();
            //code to bring parent Popup to front
        });

        node.setOnMouseDragged(e -> {
            parent.setX(e.getScreenX() + dragDelta[0]);
            parent.setY(e.getScreenY() + dragDelta[1]);
            primaryStage.requestFocus();
        });

        node.setOnMouseReleased(event -> {
            primaryStage.requestFocus();
        });
    }


    @Override
    public void start(Stage primaryStage) throws Exception{

        Button b1 = new Button("Open p1");
        Button b2 = new Button("Open p2");

        HBox n1 = new HBox(new Label("This is p1"));
        HBox n2 = new HBox(new Label("This is p2"));
        n1.setMinSize(200, 120);
        n2.setMinSize(200, 120);
        n1.setStyle("-fx-background-color: blue; -fx-background-radius: 4px;");
        n2.setStyle("-fx-background-color: red; -fx-background-radius: 4px;");
        n1.setAlignment(Pos.CENTER);
        n2.setAlignment(Pos.CENTER);

        Stage p1 = new Stage(StageStyle.UNDECORATED);
        Stage p2 = new Stage(StageStyle.UNDECORATED);
        p1.setAlwaysOnTop(true);
        p2.setAlwaysOnTop(true);
        p1.setScene(new Scene(n1));
        p2.setScene(new Scene(n2));

        applyTo(n1, p1, primaryStage);
        applyTo(n2, p2, primaryStage);

        b1.setOnAction(event -> {
            if(!p1.isShowing()) {
                p1.show();
                primaryStage.requestFocus();
            }
            else
                p1.hide();
        });

        b2.setOnAction(event -> {
            if(!p2.isShowing()) {
                p2.show();
                primaryStage.requestFocus();
            }
            else
                p2.hide();
        });



        HBox root = new HBox(10, b1, b2);
        root.setAlignment(Pos.CENTER);

        primaryStage.setScene(new Scene(root, 500, 200));
        primaryStage.show();
    }

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM