Extension du contenu de la scène JavaFX avec Popup (?)


C'est mon premier post ici - soyez gentil :)

Ce que j'essaie de faire, c'est d'avoir des contrôles / fenêtres qui:

  1. appartiennent à une étape JavaFX
  2. ne volera PAS le focus de la scène propriétaire lorsque vous cliquez sur
  3. peut être déplacé au-delà des limites de l'étape propriétaire

J'ai pu implémenter cela de deux manières; cependant, les deux sont imparfaits. Tout d'abord, j'ai créé des contrôles déplaçables dans le contenu de la Scène; cependant, ils ne peuvent pas être traînés en dehors de la scène zone. Deuxièmement, je les ai créés sous forme de fenêtres contextuelles déplaçables ancrées à la Scène; cependant, elles restent au-dessus de TOUT, même lorsque d'autres fenêtres sont déplacées au-dessus de la scène propriétaire.

Ce que je demande, c'est: Existe-t-il un moyen de faire glisser un contrôle en dehors des limites de son stade propriétaire; ou de faire en sorte qu'une fenêtre contextuelle n'apparaisse pas toujours au-dessus de tout?

J'ai trouvé une question similaire ici, expliquant le problème avec la fenêtre contextuelle en haut (La fenêtre contextuelle Javafx ne le fera pas se cacher derrière une autre application en perdant le focus). Mais il n'y avait pas de solution acceptable (je ne veux pas que la fenêtre contextuelle "se cache" lorsque la scène ou l'Application perd le focus).

Merci d'avoir lu. Si vous pouviez suggérer quelque chose, ce serait apprécié.

Ci-dessous est un exemple MCV de ce que j'ai essayé avec MoveablePopup. Cela fonctionne bien, sauf lorsque vous apportez des fenêtres supplémentaires par-dessus.

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

    }   
}
Author: Community, 2016-01-11

2 answers

Créer une nouvelle étape qui sera le 'popup':

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();
 0
Author: Siloft, 2016-01-11 20:20:33

Comme vous l'avez découvert, tout ce qui se passe dans la scène reste dans la scène (excusez le jeu de mots). Donc, si vous avez besoin d'un contenu affiché en dehors de la scène, nous pouvons tout exclure sauf Stage lui-même. Vous pouvez créer une nouvelle étape et affecter le propriétaire de votre étape initiale. Stage, étant une représentation d'une fenêtre native, volera le focus sur le clic. Cependant, il est possible de demander le focus à l'étape initiale. Cela devrait cocher vos cases d'exigence.

Je ne suis pas sûr du cas d'utilisation de ce que vous essayez d'implémenter, mais JFXtras fournit quelques extensions à l'API JavaFX existante, y compris les notifications et MDI windows. Voir si ce n'est d'aucune aide pour vous.

 -1
Author: AlmasB, 2016-01-11 19:11:04