9

カスタムシェイプにテクスチャを適用したい。私はこれがうまくいくと思いました:

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

しかし、そうではありません!私は正しい形を手に入れましたが、テクスチャはありません。他のすべての領域は正しくテクスチャ化されているので、構文が正しいことがわかります。デフォルトでは長方形だからだと思います。

代わりに次のスタイルを使用する場合:

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

次に、正しい赤い背景が表示されます。

両方の属性に互換性がない場合、カスタムSVGパス形状にテクスチャを適用するにはどうすればよいですか?

PS:私のテクスチャPNGファイルは、小さな10 * 10ラスターで、領域を塗りつぶすために繰り返します。

4

2 に答える 2

5

私に関する限り-fx-shape-fx-background-image一緒に仕事をしていません。JavaFX CSSは多くのスタイリングオプションを提供します...しかし、いくつかの制限があり、いくつかのことはプログラミングでのみ可能です。JavaFX CSSはimpl_setShape()、Regionクラスを定義された形状に粗くするために使用します(これは、APIで非推奨として市場に出回っていますが、現在使用しているjavafx 2.2でも試すことができます)。背景画像を追加すると、形状が無視され、ペイン/領域全体が塗りつぶされます。addChildrenを使用してImageViewオブジェクトを追加した場合も、同じことが起こります。つまり、css文字列は希望する結果に変換されません。

したがって、カスタムSVGPathシェイプにパターンを適用する方法は少なくとも2つ考えられます。私が使用するのはImagePatternで行われます。まず、このような形を作ります

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

またはシェイプビルダーを使用する

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

次に、画像パターンを塗りつぶしとして設定します

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

別の方法として、クリッピング(cssスタイルで-fx-background-imageが設定されたペインにカスタムシェイプクリップを追加する)を使用します。これは、次のようになります。

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

これらの1つでうまくいくはずです。テクスチャのある背景で形を整えます。これは、スタイルのあるRegionまたはPaneクラスに期待するものと同等です。

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

したがって、SVGPathシェイプは、Region / Paneとは対照的に、サイズ変更不可能なすべてのShapeクラスと同様です。これが、ここで-fx-scale-shape属性をfalseに設定した理由です。デフォルト設定(trueに設定)を使用した場合、シェイプは親オブジェクト全体を塗りつぶします...これも望ましい結果になると思います。...ここでも、親オブジェクトに合わせて形状を拡大縮小する方法が複数あります。

Groupを使用して形状を埋め込み、グループを変換する方法で動作するようになりました(ImagePatternで画像サイズを調整して、テクスチャが形状に比例しないようにする必要があります)。私は小さな動作するアプリを追加しています。これは、すべてを正しく覚えていれば、上記の例で見たものです。(形状を比例的にスケーリングする場合は、addScaleメソッドでscalexとsclaeyの代わりに同じスケール係数を使用します)

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

    }
于 2013-03-06T01:37:08.277 に答える
5

cssを介して背景テクスチャをカスタムシェイプに適用できないことは、JavaFX 2.2(Java 7) のプラットフォームのバグでした。

Java 8では、プラットフォームのバグが修正されています。

サンプル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
   */
}

サンプルアプリ:

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

Java 7でサンプルコードを実行すると、シェイプは背景テクスチャに適用されません。

java7sample

Java 8b80で同じサンプルコードを実行すると、シェイプが背景テクスチャに適用されます。

java8sample

于 2013-03-11T20:09:22.770 に答える