2013-02-23 10 views
8

Voglio applicare una trama a una forma personalizzata. Ho pensato che questo avrebbe funzionato:"-fx-shape" è compatibile con "-fx-background-image"?

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

Ma non è così! Ottengo la forma corretta ma senza la trama. Tutte le altre mie regioni sono texturizzate correttamente, quindi so che la sintassi è corretta. Immagino sia perché sono rettangolari di default.

Se uso lo stile seguente invece:

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

tanto sono un corretto sfondo rosso.

Se entrambi gli attributi sono incompatibili, come posso applicare una trama a una forma di tracciato SVG personalizzata?

P.S: Il mio file PNG texture, è un piccolo raster 10 * 10 che ripeto per riempire le mie regioni con.

+0

funziona se non si imposta '-fx-shape' e lasciare solo come un rettangolo? – Hbcdev

+0

Sì, senza -fx-shape l'immagine di sfondo viene applicata all'intero rettangolo. – Pigelvy

+1

Link tracker di problemi: [RT-28825 -fx-shape non compatibile con -fx-background-image] (http://javafx-jira.kenai.com/browse/RT-28825) – jewelsea

risposta

4

Per quanto mi riguarda, -fx-shape e -fx-background-image non funzionano insieme. JavaFX CSS offre molte opzioni di stile ... tuttavia ci sono alcune limitazioni e alcune cose sono possibili solo con la programmazione. JavaFX CSS usa impl_setShape() per rendere grezza la classe Region alla forma definita (che è market deprecata nell'api ma è ancora possibile provarla in javafx 2.2 - che sto usando al momento). L'aggiunta dell'immagine di sfondo ignora la forma e riempie l'intero riquadro/area, lo stesso accade se si utilizza addChildren per aggiungere oggetti ImageView al suo interno. Quindi - la stringa css non si tradurrà nel risultato che vorresti.

Quindi posso pensare almeno a 2 modi di applicare un modello a una forma SVGPath personalizzata. Quello che userei è fatto con ImagePattern. In primo luogo costruire la forma come questo

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

o utilizzando Crea forme

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

e quindi impostare il modello di immagine come riempire

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

Un'alternativa sarebbe usare clipping (l'aggiunta di una clip forma personalizzata in un pannello con -fx-background-image impostato nello stile css), che sarebbe un po 'come questo

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

Uno di questi dovrebbe fare il trucco: si ottiene la forma con lo sfondo con texture. Questo è l'equivalente di quello che ci si aspetta da una classe Regione o Pane con stile

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

Così la forma SVGPath è come tutte le classi Forma nonresizable, a differenza di Regione/Pane, questo è il motivo per cui ho impostato qui il -fx-scale-shape attributo a falso. Il modo in cui lo avevi era con l'impostazione di default - che lo imposta su true - che fa riempire la forma dell'intero oggetto genitore ... da cui suppongo che questo sarebbe anche il risultato desiderato. ... ora ci sono ancora diversi modi per rendere la scala della forma all'oggetto padre.

Ho ottenuto il lavoro utilizzando il gruppo per incorporare la forma e con un metodo di traduzione del gruppo (la dimensione dell'immagine deve essere regolata in ImagePattern, in modo che la trama non si riduca con la forma). Sto aggiungendo una piccola app di lavoro, che ho visto nell'esempio sopra se ricordo tutto correttamente.(Se si desidera la forma per scalare in modo proporzionale, si utilizza lo stesso fattore di scala, invece di scaleX e sclaey nel metodo 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); 
      } 

    } 
+0

[RT-28825] (http://javafx-jira.kenai.com/browse/RT -28825) dice che questo è possibile in JavaFX 8. La mia esperienza è stata con 2.2.6. Quale versione hai usato? – Pigelvy

+0

Sto usando l'ultima versione di javafx, che credo sia 2.2.7. Non ho ancora provato l'accesso iniziale di JDK8, quindi non so se include già un css javafx migliorato, ma la loro roadmap dice che JDK8 includerà javafx 8. In attesa di supporto migliorato css e html5 degli 8 - ma fino ad allora la mia soluzione alternativa dovrebbe farlo per te =) Ma aggiungerò cose alla mia risposta quando capirò qualcosa di nuovo. –

4

L'inablity di applicare una texture di sfondo a una forma personalizzata tramite CSS è stato un platform bug con JavaFX 2.2 (Java 7).

In Java 8, il bug della piattaforma è stato risolto.

Esempio 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 
    */ 
} 

Esempio App:

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

L'esecuzione del codice di esempio in Java 7, la forma non è applicata alla texture di sfondo:

java7sample

Eseguendo lo stesso codice di esempio su Java 8b80, lo sha ae viene applicato alla texture di sfondo:

java8sample

Problemi correlati