JavaFX:如何管理阶段的 z-index

Posted

技术标签:

【中文标题】JavaFX:如何管理阶段的 z-index【英文标题】:JavaFX : How to manage the z-index of stages 【发布时间】:2019-11-30 23:05:48 【问题描述】:

有没有办法管理多个阶段的 z-index 排序(彼此独立)。例如,假设有 A、B 和 C 三个阶段。StageA 应该始终位于后面。 StageB 应位于中间,StageC 应始终位于顶部。只是特别注意这三个阶段彼此没有关系(如所有者)

下面是我所期待的快速演示。我需要访问任何阶段(用于拖动或修改),但需要维护 z 顺序。任何想法或帮助都将受到高度赞赏。

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.HashMap;
import java.util.Map;

public class StagesZOrdering_Demo extends Application 
    private Map<String, Stage> stages = new HashMap<>();

    @Override
    public void start(Stage stage) throws Exception 
        Button button1 = new Button("Back");
        button1.setOnAction(e -> openStage("Back"));

        Button button2 = new Button("Middle");
        button2.setOnAction(e -> openStage("Middle"));

        Button button3 = new Button("Front");
        button3.setOnAction(e -> openStage("Front"));

        VBox root = new VBox(button1, button2, button3);
        root.setAlignment(Pos.CENTER);
        root.setSpacing(10);
        Scene sc = new Scene(root, 200, 200);
        stage.setScene(sc);
        stage.show();
    

    private void openStage(String title) 
        if (stages.get(title) != null) 
            stages.get(title).requestFocus();
         else 
            Stage stg = new Stage();
            stg.setTitle(title);
            stg.setScene(new Scene(new StackPane(), 300, 300, Color.GRAY));
            stg.show();
            stg.setOnHidden(e -> stages.remove(title));
            stages.put(title, stg);
        
    

    public static void main(String... a) 
        Application.launch(a);
    

【问题讨论】:

很确定 API 不允许开箱即用。唯一的机会是去当地的 JNA。据我所知,Windows(不确定其他操作系统)似乎也没有通过 DLL 直接从盒子中取出该功能,最近的事情是全局“始终在顶部”功能。 我认为最接近 Java 的方法是在 List 中保持所需的阶段顺序并监听何时拖动阶段;当它被释放时,以正确的顺序重新聚焦所有阶段以重置它们的 z 顺序。不过,这只是我脑海中的一个快速想法。 您是想阻止说“中间”阶段获得焦点还是希望它在完成后回到中间?你也可以使用internal frame 吗? 感谢 Jai 和 Zephyr 的投入。我尝试使用 toFront 和 toBack 但无法获得确切的行为。将继续尝试其他方法。 【参考方案1】:

以下 mcve 演示从后到前阶段的重新排序,一旦从其中一个触发 ROOT MOUSE_EXITED_TARGET 事件。 这是一个简单但有限的解决方案:

import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventType;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class StagesZOrdering_Demo extends Application 

    public enum STAGES BACK, MIDDLE, FRONT;
    private final EnumMap<STAGES, Stage> stages = new EnumMap<>(STAGES.class);

    @Override
    public void start(Stage stage) throws Exception 

        VBox root = new VBox();
        for(STAGES s : STAGES.values())
            Button button = new Button(s.name());
            button.setOnAction(e -> openStage(s));
            root.getChildren().add(button);
        

        root.setAlignment(Pos.CENTER);
        root.setSpacing(10);
        Scene sc = new Scene(root, 200, 200);
        stage.setScene(sc);
        stage.show();
    

    private void openStage(STAGES s) 
        if (stages.get(s) == null) 
            Stage stg = new Stage();
            stg.setTitle(s.name());
            stg.addEventHandler(EventType.ROOT, e->reOrder(e));
            stg.setScene(new Scene(new StackPane(), 300, 100, Color.GRAY));
            stg.show();
            stg.setOnHidden(e -> stages.remove(s));
            stages.put(s, stg);
        
    

    private void reOrder(Event e)
        if(! e.getEventType().getName().equals("MOUSE_EXITED_TARGET"))
            return;

        for(STAGES s : STAGES.values())
            Stage stage = stages.get(s);
            if(stage != null) 
                stage.requestFocus();
            
        
    

    public static void main(String... a) 
        Application.launch(a);
    


【讨论】:

感谢@c0der 提出另一种方法。这看起来比我迄今为止尝试的方法更有希望。如果我能得到更多建议,将等待一周,否则将其标记为已回答。 :)

以上是关于JavaFX:如何管理阶段的 z-index的主要内容,如果未能解决你的问题,请参考以下文章

关闭阶段JavaFX后如何停止WebEngine?

JavaFX如何改变阶段

如何在一定时间后关闭一个阶段JavaFX

如何在 JavaFX 中获得一个阶段的关闭事件?

JavaFX:如何在初始化期间从控制器获取阶段?

如何在我的应用程序的javafx 2.0中更改阶段标题栏上的图标[重复]