9 votes

L'option "-fx-shape" est-elle compatible avec "-fx-background-image" ?

Je veux appliquer une texture à une forme personnalisée. J'ai pensé que cela pourrait fonctionner :

.myTextureShape {
-fx-shape: "M0 0 L0 50 L25 25 L50 50 L50 0 Z";
-fx-background-image: url("resources/texture_bg.png");
-fx-background-repeat: repeat;
}

Mais ce n'est pas le cas ! J'obtiens la forme correcte mais sans la texture. Toutes mes autres régions sont correctement texturées, je sais donc que la syntaxe est correcte. Je suppose que c'est parce qu'elles sont rectangulaires par défaut.

Si j'utilise le style suivant à la place :

.myTextureShape {
 -fx-shape: "M0 0 L0 50 L25 25 L50 50 L50 0 Z";
 -fx-background-color: red;
}

J'obtiens alors un fond rouge correct.

Si les deux attributs sont incompatibles, comment puis-je appliquer une texture à une forme personnalisée SVG-pathed-shape ?

P.S : Mon fichier PNG de texture, est une petite trame 10*10 que je répète pour remplir mes régions avec.

5voto

Martin Turjak Points 9767

En ce qui me concerne -fx-shape y -fx-background-image ne travaillent pas ensemble. JavaFX CSS offre un grand nombre d'options de style ... mais il y a quelques limitations et certaines choses ne sont possibles qu'avec la programmation. JavaFX CSS utilise impl_setShape() pour faire correspondre la classe Region à la forme définie (ce qui est considéré comme déprécié dans l'api mais vous pouvez toujours l'essayer dans javafx 2.2 - que j'utilise en ce moment). L'ajout de l'image de fond ignore la forme et remplit l'ensemble du panneau/de la région, la même chose se produit si vous utilisez addChildren pour ajouter des objets ImageView. Donc - la chaîne css ne se traduira pas par le résultat que vous souhaitez.

Je peux donc penser à au moins deux façons d'appliquer un motif à une forme SVGPath personnalisée. Celle que j'utiliserais est faite avec ImagePattern. D'abord, construisez la forme comme ceci

SVGPath shape = new SVGPath();
shape.setContent("M0 0 L0 50 L25 25 L50 50 L50 0 Z");

ou en utilisant le shape builder

SVGPath shape = SVGPathBuilder.create()
    .content("M0 0 L0 50 L25 25 L50 50 L50 0 Z")
    .build();

et ensuite définir le motif de l'image comme remplissage

Image img = new Image("myjavafxapp/resources/texture_bg.png");
shape.setFill(new ImagePattern(img,0,0,10,10,false));

Une autre solution consisterait à utiliser l'écrêtage (en ajoutant un écrêtage de forme personnalisée à un volet avec le paramètre -fx-background-image défini dans le style css), ce qui ressemblerait à ceci

Pane test = new Pane(); 
test.setStyle(" -fx-background-image: url(\"myjavafxapp/res/index.jpeg\");");
SVGPath shape = new SVGPath();
shape.setContent("M0 0 L0 50 L25 25 L50 50 L50 0 Z");
test.setClip(shape);

L'une d'entre elles devrait faire l'affaire - vous obtenez votre forme avec l'arrière-plan texturé. C'est l'équivalent de ce que vous attendez d'une classe Region ou Pane avec le style

.myTextureShape {
    -fx-shape: "M0 0 L0 50 L25 25 L50 50 L50 0 Z";
    -fx-scale-shape: false;
    -fx-background-image: url("myjavafxapp/resources/texture_bg.png");
    -fx-background-repeat: repeat; 
}

Ainsi, la forme SVGPath est, comme toutes les classes Shape, non redimensionnable, contrairement à Region/Pane, c'est pourquoi j'ai défini ici l'attribut -fx-scale-shape à false. Dans votre cas, il s'agissait du paramètre par défaut, c'est-à-dire la valeur true, qui fait que la forme remplit tout l'objet parent... Je suppose que c'est également le résultat que vous souhaitez. ... il y a maintenant plusieurs façons de mettre la forme à l'échelle de l'objet parent.

J'ai réussi à le faire fonctionner en utilisant Group pour intégrer la forme et avec une méthode traduisant le groupe (la taille de l'image doit être ajustée dans ImagePattern, afin que la texture ne soit pas mise à l'échelle avec la forme). J'ajoute une petite application fonctionnelle, que je voyais sur l'exemple ci-dessus si je me souviens bien de tout. (si vous souhaitez que la forme soit mise à l'échelle proportionnellement, vous utilisez le même facteur d'échelle au lieu de scalex et sclaey dans la méthode addScale)

    package myjavafxapp;

    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.scene.Group;
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.StackPane;
    import javafx.scene.shape.SVGPath;
    import javafx.scene.shape.SVGPathBuilder;
    import javafx.scene.image.Image;
    import javafx.scene.paint.*;
    import javafx.scene.transform.Scale;
    import javafx.scene.transform.Translate;
    import javafx.stage.Stage;
    /**
     * @author martint
     */
    public class MyJavaFXApp extends Application {

            private final static String svg = "M0 0 L0 50 L25 25 L50 50 L50 0 Z";
            private SVGPath shape;
            private Image img;
            private Pane resizePane;
            private Group shapeGroup;
            private Node content;

        @Override
        public void start(final Stage primaryStage) {

            //build the SVGPath shape
            shape = SVGPathBuilder.create().content(svg).build();
            img = new Image("myjavafxapp/res/index.jpeg");
            resizePane = new Pane();
            shapeGroup = new Group();
            resizePane.getChildren().add(shapeGroup);

            StackPane root = new StackPane();
            root.getChildren().add(resizePane);

            Scene scene = new Scene(root, 200, 200); 
            primaryStage.setScene(scene);
            primaryStage.show();
            //fill node content
            content = nodeCont();
            shapeGroup.getChildren().add(content);
            //resizing listening
            resizePane.widthProperty().addListener(new ChangeListener<Number>(){
                            @Override
                            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                                    addScaling();
                            }});
            resizePane.heightProperty().addListener(new ChangeListener<Number>(){
                            @Override
                            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                                    addScaling();
                            }});
            Platform.runLater(new Runnable() {          
                            @Override
                            public void run() {
                                    addScaling();
                            }
                    });
            }
            private Node nodeCont() {
                    Group cont = new Group();
                    cont.getChildren().add(shape);
                    return cont;
            }
            private void addScaling() {
                    shapeGroup.getTransforms().clear();           
                    //shape boundary
                    double cx = content.getBoundsInParent().getWidth();
                    double cy = content.getBoundsInParent().getHeight();
                    //resizePane boundary
                    double px = resizePane.getWidth();
                    double py = resizePane.getHeight();
                    //if pane set
                    if (px > 0.0 && py > 0.0) {
                            //scale
                            double scalex = px/cx;
                            double scaley = py/cy;
                            //center
                            double centerx = 0.5 * (px - cx*scalex);
                            double centery = 0.5 * (py - cy*scaley);            
                            //transform
                            shapeGroup.getTransforms().add(new Translate(centerx, centery));
                            shapeGroup.getTransforms().add(new Scale(scalex, scaley));
                            shape.setFill(new ImagePattern(img,0,0,10/scalex,10/scaley,false));
                    }
            }
            public static void main(String[] args) {
                    launch(args);
            }

    }

5voto

jewelsea Points 40435

L'impossibilité d'appliquer une texture d'arrière-plan à une forme personnalisée par le biais de css était un problème. bug de la plateforme avec JavaFX 2.2 (Java 7).

Dans Java 8, le bogue de la plate-forme est corrigé.

Exemple de css :

/** 
 * file textured-shape.css
 * place in same directory as TexturedShape.java and ensure build system copies 
 * this file to the build output directory.
 */
.textured-shape {
  /** (a square with the bottom triangle chunk taken out of it) */
  -fx-shape: "M0 0 L0 50 L25 25 L50 50 L50 0 Z";
  -fx-background-image: url('http://icons.iconarchive.com/icons/tooschee/misc/128/Present-icon.png');
  /** 
   * Image license:  
   *   CC Attribution-Noncommercial 3.0 http://creativecommons.org/licenses/by-nc/3.0/
   *   Buy commercial license here: http://tooschee.com/portfolio?worksCategory=icons
   */
}

Exemple d'application :

import static javafx.application.Application.launch;
import javafx.application.*;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class TexturedShape extends Application {
  @Override public void start(Stage stage) {
    Pane pane = new Pane();
    pane.setPrefSize(128, 128);
    pane.getStyleClass().add("textured-shape");

    Scene scene = new Scene(pane);
    scene.getStylesheets().add(
      getClass().getResource("textured-shape.css").toExternalForm()
    );
    stage.setScene(scene);
    stage.show();
  }

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

En exécutant l'exemple de code sur Java 7, la forme n'est pas appliquée à la texture de fond :

java7sample

En exécutant le même exemple de code sur Java 8b80 la forme est appliquée à la texture de l'arrière-plan :

java8sample

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X