使用弹出窗口扩展JavaFX阶段内容(?)

使用弹出窗口扩展JavaFX阶段内容(?),javafx,popup,stage,always-on-top,Javafx,Popup,Stage,Always On Top,这是我在这里的第一篇帖子——请友好一点:) 我想做的是让控件/窗口: 属于JavaFX阶段 单击时不会从所属阶段窃取焦点 可以拖动到所属阶段的边界之外 我通过两种方式实现了这一点;然而,两者都有缺陷。首先,我在舞台内容中制作了可拖动的控件;但是,它们不能拖到舞台区域之外。其次,我将它们创建为固定在舞台上的可拖动弹出窗口;然而,即使其他窗口被移动到所属阶段的顶部,它们仍然位于所有内容的顶部 我要问的是:是否有任何方法可以将控件拖出其所属阶段的边界;或者使弹出窗口不总是显示在所有内容的顶部? 我在这

这是我在这里的第一篇帖子——请友好一点:)

我想做的是让控件/窗口:

  • 属于JavaFX阶段
  • 单击时不会从所属阶段窃取焦点
  • 可以拖动到所属阶段的边界之外

  • 我通过两种方式实现了这一点;然而,两者都有缺陷。首先,我在舞台内容中制作了可拖动的控件;但是,它们不能拖到舞台区域之外。其次,我将它们创建为固定在舞台上的可拖动弹出窗口;然而,即使其他窗口被移动到所属阶段的顶部,它们仍然位于所有内容的顶部

    我要问的是:是否有任何方法可以将控件拖出其所属阶段的边界;或者使弹出窗口不总是显示在所有内容的顶部?

    我在这里发现了一个类似的问题,解释了弹出窗口位于顶部()的问题。但是没有可接受的解决方案(我不希望在舞台或应用程序失去焦点时弹出窗口“隐藏”)

    谢谢你的阅读。如果您能提出任何建议,我们将不胜感激

    下面是我用MoveablePopup尝试的MCV示例。它可以正常工作,除了在顶部加上额外的窗口

    package moveablepopuptest;
    
    import javafx.application.Application;
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.geometry.Insets;
    import javafx.geometry.Point2D;
    import javafx.scene.Cursor;
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.Background;
    import javafx.scene.layout.BackgroundFill;
    import javafx.scene.layout.Border;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.BorderStroke;
    import javafx.scene.layout.BorderStrokeStyle;
    import javafx.scene.layout.BorderWidths;
    import javafx.scene.layout.CornerRadii;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.StackPane;
    import javafx.scene.paint.Color;
    import javafx.stage.Popup;
    import javafx.stage.Stage;
    
    public class MoveablePopupTest extends Application
    {    
    
        @Override
        public void start(Stage primaryStage)
        {        
            // Set up Primary Stage:
            StackPane root = new StackPane();        
            Scene scene = new Scene(root, 400, 400);        
            primaryStage.setTitle("MoveablePopup Test");
            primaryStage.setScene(scene);
            primaryStage.show();
    
    
            // Show a MoveablePopup for an associated node in the Stage:
            MoveablePopup popup = new MoveablePopup();
            popup.setTitle("Extension");
            Pane popupContent = new Pane();
            popupContent.setBackground(new Background(new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY)));
            popupContent.setMinSize(200, 200);
            popup.setContent(popupContent);
            popup.show(root, 0, 0);        
    
            // When Primary Stage is moved, re-anchor the popup:
            ChangeListener<Number> windowMoveListener = (ObservableValue<? extends Number> observable, Number oldValue, Number newValue) ->
            {
                 popup.anchorToOwner();
            };       
            primaryStage.xProperty().addListener(windowMoveListener);
            primaryStage.yProperty().addListener(windowMoveListener);
        }
    
        public static void main(String[] args)
        {
            launch(args);
        }
    
        public class MoveablePopup extends Popup
        {    
            private final BorderPane bgPane = new BorderPane(); 
            private final DoubleProperty ownerXAnchorProperty = new SimpleDoubleProperty(0);
            private final DoubleProperty ownerYAnchorProperty = new SimpleDoubleProperty(0);        
            private final Label titleLabel = new Label("Title");
            private Point2D lastMouse = null;      
            private Node content = null;
    
            public MoveablePopup()    
            {   
                // Don't want Esc to close the Popup:
                setHideOnEscape(false);
    
                // Create a border:
                bgPane.setBorder(new Border(new BorderStroke(Color.DARKORANGE, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(2))));
    
                // Create a title bar for the top, which will also function as a handle to move the Popup:
                StackPane barPane = new StackPane();  
                titleLabel.setTextFill(Color.WHITE);
                barPane.getChildren().add(titleLabel);            
                barPane.setCursor(Cursor.MOVE);
                barPane.setBackground(new Background(new BackgroundFill(Color.DARKORANGE, CornerRadii.EMPTY, Insets.EMPTY)));
                barPane.setMaxSize(Double.MAX_VALUE, 24);
                bgPane.setTop(barPane);                         
    
                // Add drag/anchoring functionality to the Popup
                barPane.setOnMousePressed((MouseEvent event) ->
                {
                    lastMouse = new Point2D(event.getScreenX(), event.getScreenY());
                });
                barPane.setOnMouseDragged((MouseEvent event) ->
                {
                    double moveX = event.getScreenX() - lastMouse.getX();
                    double moveY = event.getScreenY() - lastMouse.getY();
                    ownerXAnchorProperty.set(ownerXAnchorProperty.doubleValue()+moveX);
                    ownerYAnchorProperty.set(ownerYAnchorProperty.doubleValue()+moveY);
                    lastMouse = new Point2D(event.getScreenX(), event.getScreenY());
                    anchorToOwner();
                });
                getContent().add(bgPane);        
    
            }
    
            @Override
            protected void show()
            {
                super.show();
                anchorToOwner();
            }
    
            public void setContent(Node content)
            {
                this.content = content;
                bgPane.setCenter(content);
            }
    
            public void setTitle(String title)
            {
                titleLabel.setText(title);
            }
    
            // Repositions the MoveablePopup so that it's relationship to
            // the owning Node's location is maintained:
            public final void anchorToOwner()
            {
                if (getOwnerNode() != null)
                {
                    Point2D screenPoint = getOwnerNode().localToScreen(0, 0);
                    setX(screenPoint.getX() + ownerXAnchorProperty.doubleValue());
                    setY(screenPoint.getY() + ownerYAnchorProperty.doubleValue());
                }
            }
    
        }   
    }
    
    packagemoveablepoputest;
    导入javafx.application.application;
    导入javafx.beans.property.DoubleProperty;
    导入javafx.beans.property.SimpleDoubleProperty;
    导入javafx.beans.value.ChangeListener;
    导入javafx.beans.value.observeValue;
    导入javafx.geometry.Insets;
    导入javafx.geometry.Point2D;
    导入javafx.scene.Cursor;
    导入javafx.scene.Node;
    导入javafx.scene.scene;
    导入javafx.scene.control.Label;
    导入javafx.scene.input.MouseEvent;
    导入javafx.scene.layout.Background;
    导入javafx.scene.layout.BackgroundFill;
    导入javafx.scene.layout.Border;
    导入javafx.scene.layout.BorderPane;
    导入javafx.scene.layout.BorderStroke;
    导入javafx.scene.layout.BorderStrokeStyle;
    导入javafx.scene.layout.BorderWidths;
    导入javafx.scene.layout.CornerRadii;
    导入javafx.scene.layout.Pane;
    导入javafx.scene.layout.StackPane;
    导入javafx.scene.paint.Color;
    导入javafx.stage.Popup;
    导入javafx.stage.stage;
    公共类MoveablePopupTest扩展了应用程序
    {    
    @凌驾
    公共无效开始(阶段primaryStage)
    {        
    //建立初级阶段:
    StackPane root=新的StackPane();
    场景=新场景(根,400400);
    primaryStage.setTitle(“可移动弹出测试”);
    初级阶段。场景(场景);
    primaryStage.show();
    //显示阶段中关联节点的可移动弹出窗口:
    MoveablePopup popup=新的MoveablePopup();
    popup.setTitle(“扩展”);
    窗格popupContent=新窗格();
    popupContent.setBackground(新背景(新背景填充(Color.WHITE,CornerRadii.EMPTY,Insets.EMPTY));
    setMinSize(200200);
    popup.setContent(popupContent);
    显示(根,0,0);
    //移动主阶段时,重新锚定弹出窗口:
    
    ChangeListener windowMoveListener=(ObservalEvalue正如您所发现的,舞台内发生的一切都留在舞台内(请原谅双关语)。因此,如果您需要在后台之外显示某些内容,我们可以排除除
    后台
    本身以外的所有内容。您可以创建一个新后台,并将所有者分配给初始后台。
    后台
    ,作为本机窗口的一种表示形式,将窃取对单击的关注。但是,可以在初始后台返回。这应该勾选您的需求框


    我不确定您试图实现的用例,但提供了对现有JavaFX API的一些扩展,包括通知和窗口。看看这对您是否有帮助。

    正如您所发现的,阶段内发生的一切都在阶段内(请原谅双关语)。因此,如果您需要在后台之外显示某些内容,我们可以排除除
    后台
    本身以外的所有内容。您可以创建一个新后台,并将所有者分配给初始后台。
    后台
    ,作为本机窗口的一种表示形式,将窃取对单击的关注。但是,可以在初始后台返回。这应该勾选您的需求框


    我不确定您尝试实现的用例,但提供了对现有JavaFX API的一些扩展,包括通知和窗口。看看这对您是否有帮助。

    创建一个新的阶段,它将是“弹出窗口”:

    Stage childStage = new Stage();
    
    childStage.initModality(Modality.WINDOW_MODAL);
    childStage.setTitle("Title of popup");
    
    childStage.setScene(YOUR_SCENE);
    childStage.sizeToScene();
    childStage.setResizable(false);
    
    childStage.show();
    

    创建一个新阶段,该阶段将成为“弹出窗口”:

    Stage childStage = new Stage();
    
    childStage.initModality(Modality.WINDOW_MODAL);
    childStage.setTitle("Title of popup");
    
    childStage.setScene(YOUR_SCENE);
    childStage.sizeToScene();
    childStage.setResizable(false);
    
    childStage.show();
    

    我知道这似乎没有什么帮助,但请在你的问题中加入一个你已经尝试过的方法。好吧,我添加了一个MoveablePopup方法的示例。至于在舞台上拖动控件:我认为这更简单,不能将它们从舞台上拖下来的问题更清楚;但是我如果您愿意,也可以添加一个示例。不,弹出窗口示例足以帮助演示问题。如果不创建子类窗口(如弹出窗口),则无法实现您的愿望,所以你不能用一个阶段作为你应用程序中的唯一窗口。这就是我害怕的。除了那个烦人的细节,我似乎离你很近……哈。好吧,谢谢你提供的信息。“我将它们创建为锚定在舞台上的可拖动弹出窗口;但是,即使其他窗口移动到舞台的顶部,它们仍然位于所有窗口的顶部。"-->我在OS X 10.9.5、Java 8u72上运行了您的示例,但没有得到此行为。当我将其他窗口移动到所属阶段的顶部时,其他窗口也会阻塞弹出窗口。我知道这似乎没有帮助,但请在您的问题中包含一个示例,说明您已经尝试过的内容。好的,我为MoveablePopup添加了一个示例接近