2

我的应用程序中有一些 JavaFX Popup。当这些弹出窗口中的任何一个被关注时,我需要将它放在所有其他弹出窗口之上,无论它在Window.getWindows().

我试过调用方法,toFront但它不在Popup课堂上。我也尝试过更改 focus Popupin 的索引,Window.getWindows()但这也没有用,因为我不知道如何交换 a 中两个元素的索引ObservableList

例如

假设我有两个Popup被调用的p1andp2在每个中我都有节点n1andn2分别用于移动这些弹出窗口,所以每当n1被拖动时都p1应该在顶部,而当n2被拖动时p2应该在顶部。

这是我的最小示例:

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();
    }
    
}

那么这个问题的解决方案是什么?

4

2 回答 2

2

出于某种原因,我不明白,toFront/back 仅在 Stage 上实现,而不是在其父类上实现,即使管理堆叠的实际协作者已经在 Window 中可用:

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()是 Window 中的一个包私有方法,它返回内部类 TKStage。因此,如果您被允许变脏(因为访问内部类并且必须通过反射访问 - 所有这些都带有通常响亮的“当心”!)将是:

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();
    }
}

需要在 javafx.graphics 中导出/打开未导出的包 - 编译器和运行时错误将指导您(无论如何,我的上下文都经过大量调整,所以不知道究竟添加了哪些包)

于 2019-01-14T16:01:41.200 回答
0

这是带有阶段的解决方案,它是我发现的唯一解决方法,即使您讨厌拥有多个阶段的想法,如果您想要功能就是这样。如果您决定坚持将它们留在后台,那也很酷。解决您的阶段困境的一个想法是在使用时使用阶段队列删除,如果所有阶段都显示,则在隐藏阶段时添加一个新阶段发送到队列末尾

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); }

}
于 2019-01-14T15:05:35.753 回答