JavaFX 将 ImageView 裁剪为 AnchorPane 中的椭圆

Posted

技术标签:

【中文标题】JavaFX 将 ImageView 裁剪为 AnchorPane 中的椭圆【英文标题】:JavaFX Clipping an ImageView to an Ellipse within an AnchorPane 【发布时间】:2014-09-10 08:05:51 【问题描述】:

我一直在构建一个应用程序,我想在椭圆内显示一个大图像以模仿天文馆的屋顶。 使用 myImageView.setClip(myEllipse) 将 ImageView 显示图像剪辑到椭圆上一直运行良好,直到我添加椭圆的 AnchorPane 的应用程序的最后一个版本似乎不欣赏我在其中剪辑图像。

myImageView.setClip(myEllipse) 行的错误如下:

原因:

java.lang.IllegalArgumentException:节点的剪辑设置为不正确的值 (节点已连接,节点 = ImageView@a13b0a6,剪辑 = ObjectProperty [bean: ImageView@a13b0a6, name: clip, value: null])。

我的理解是我在场景图中创建了某种循环,但我不知道在哪里。

这是我的代码(整个界面是“硬编码”的)

package opinarium3;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import static javafx.scene.layout.VBox.setMargin;
import javafx.scene.shape.Ellipse;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 *
 * @author Admin
 */
public class Opinarium3 extends Application 
    private Ellipse ceiling;
    private ImageView ceiling_image;
    private VBox nav;
    private HBox buttonSet;
    private Label presentation_title;
    private TextArea info;
    private Button previous;
    private Button comment;
    private Button next;
    private double sx;
    private double sy;
    private DoubleProperty coordX = new SimpleDoubleProperty(0);
    private DoubleProperty coordY = new SimpleDoubleProperty(0);

    @Override
    public void start(Stage primaryStage) throws IOException 
        AnchorPane root = new AnchorPane();
        Scene primaryScene = new Scene(root, 900, 800);
        primaryScene.getStylesheets().add(Opinarium3.class.getResource("Opinarium3.css").toExternalForm());
        initializeCeiling(root);
        initializeNav(root);
        initializeContent();
        initializePrimaryStage(primaryStage, primaryScene);
        primaryStage.show();
    

    private void initializePrimaryStage(Stage primaryStage, Scene primaryScene) 
        primaryStage.setTitle("Planetario de San José - Cartelera de Presentaciones");
        primaryStage.setScene(primaryScene);
        primaryStage.setWidth(900);
        primaryStage.setHeight(800);
        primaryStage.minHeightProperty().setValue(800);
        primaryStage.minWidthProperty().setValue(900);
    

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) 
        launch(args);
    

    private void initializeCeiling(AnchorPane root) 
        ceiling = new Ellipse();
        ceiling.centerXProperty().bind(root.widthProperty().multiply(0.5));
        ceiling.centerYProperty().setValue(0);
        ceiling.radiusXProperty().bind(root.widthProperty().multiply(0.8));
        ceiling.radiusYProperty().bind(root.heightProperty().multiply(0.6));
        root.getChildren().add(ceiling);
    

    private void initializeNav(AnchorPane root) 
        nav = new VBox();
        initializeControls(nav);
        AnchorPane.setBottomAnchor(nav, 20.0);
        AnchorPane.setLeftAnchor(nav, 120.0);
        AnchorPane.setRightAnchor(nav, 120.0);
        root.getChildren().add(nav);
    

    private void initializeControls(VBox nav) 
        info = new TextArea();
        setMargin(info, new Insets(10, 0, 0, 0));
        info.setWrapText(true);
        info.setEditable(false);
        buttonSet = new HBox();
        initializeButtonSet(nav);
        presentation_title = new Label("Título de la Presentación");
        presentation_title.setId("titulo");
        nav.alignmentProperty().setValue(Pos.CENTER);
        nav.getChildren().addAll(presentation_title, info, buttonSet);
    

    private void initializeButtonSet(VBox nav) 
        previous = new Button("<");
        comment = new Button("Doy mi opinión");
        comment.setId("comment_button");
        next = new Button(">");
        buttonSet.spacingProperty().bind(nav.widthProperty().multiply(0.15));
        buttonSet.setAlignment(Pos.CENTER);
        setMargin(buttonSet, new Insets(10, 0, 0, 0));
        buttonSet.getChildren().addAll(previous, comment, next);
    

    private void initializeContent() throws IOException 
        try 
            BufferedReader br = new BufferedReader(new FileReader("src/opinarium3/media/joyas/joyas.txt"));
            String title = br.readLine();
            String length = br.readLine();
            String description = br.readLine();
            this.presentation_title.setText(title);
            this.info.setText("\n"+description+"\n\nDuración: "+length);
            br.close();


            ceiling_image = new ImageView(new Image(Opinarium3.class.getResourceAsStream("media/joyas/joyas.jpg")));
            ceiling_image.setClip(ceiling);
            /*
            ceiling_image.setOnMousePressed(new EventHandler<MouseEvent>() 
                @Override
                public void handle(MouseEvent t) 
                    sx = t.getSceneX() - coordX.doubleValue();
                    sy = t.getSceneY() - coordY.doubleValue();
                
            );
            ceiling_image.setOnMouseDragged(new EventHandler<MouseEvent>()
                @Override
                public void handle(MouseEvent t)
                    if(t.getSceneX() - sx < 0)
                        coordX.setValue(t.getSceneX() - sx);
                    
                    if(t.getSceneY() - sy < 0)
                        coordY.setValue(t.getSceneY() - sy);
                    
                
            );
            ceiling_image.xProperty().bind(coordX);
            ceiling_image.yProperty().bind(coordY);
                    */
        catch(IOException e)
    

【问题讨论】:

对于您的下一个问题,请尝试将代码发布为mcve;即仍然可执行的最小代码,不依赖于本地文件并且只有足够的代码来证明问题。最重要的是,不要在不打印或重新抛出异常的情况下将异常吞入 catch 块中。谢谢 我明白...我会尽量记住所有这些。感谢您的观察。 【参考方案1】:

您只能在场景中使用该形状一次,不能将其设置为剪辑并添加为元素的子元素。

您正在将剪辑添加到场景中,而不是正在剪辑到场景中的项目。

import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.shape.Ellipse;
import javafx.stage.Stage;

import static javafx.scene.layout.VBox.setMargin;

public class Opinarium3 extends Application 
    private Ellipse ceiling;
    private ImageView ceiling_image;
    private VBox nav;
    private HBox buttonSet;
    private Label presentation_title;
    private TextArea info;
    private Button previous;
    private Button comment;
    private Button next;

    @Override
    public void start(Stage primaryStage) 
        AnchorPane root = new AnchorPane();
        Scene primaryScene = new Scene(root, 900, 800);
        initializeCeiling(root);
        initializeNav(root);
        initializeContent(root);
        initializePrimaryStage(primaryStage, primaryScene);
        primaryStage.show();
    

    private void initializePrimaryStage(Stage primaryStage, Scene primaryScene) 
        primaryStage.setTitle("Planetario de San José - Cartelera de Presentaciones");
        primaryStage.setScene(primaryScene);
        primaryStage.setWidth(900);
        primaryStage.setHeight(800);
        primaryStage.minHeightProperty().setValue(800);
        primaryStage.minWidthProperty().setValue(900);
    

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

    private void initializeCeiling(AnchorPane root) 
        ceiling = new Ellipse();
        ceiling.centerXProperty().bind(root.widthProperty().multiply(0.5));
        ceiling.centerYProperty().setValue(0);
        ceiling.radiusXProperty().bind(root.widthProperty().multiply(0.8));
        ceiling.radiusYProperty().bind(root.heightProperty().multiply(0.6));
    

    private void initializeNav(AnchorPane root) 
        nav = new VBox();
        initializeControls(nav);
        AnchorPane.setBottomAnchor(nav, 20.0);
        AnchorPane.setLeftAnchor(nav, 120.0);
        AnchorPane.setRightAnchor(nav, 120.0);
        root.getChildren().add(nav);
    

    private void initializeControls(VBox nav) 
        info = new TextArea();
        setMargin(info, new Insets(10, 0, 0, 0));
        info.setWrapText(true);
        info.setEditable(false);
        buttonSet = new HBox();
        initializeButtonSet(nav);
        presentation_title = new Label("Título de la Presentación");
        presentation_title.setId("titulo");
        nav.alignmentProperty().setValue(Pos.CENTER);
        nav.getChildren().addAll(presentation_title, info, buttonSet);
    

    private void initializeButtonSet(VBox nav) 
        previous = new Button("<");
        comment = new Button("Doy mi opinión");
        comment.setId("comment_button");
        next = new Button(">");
        buttonSet.spacingProperty().bind(nav.widthProperty().multiply(0.15));
        buttonSet.setAlignment(Pos.CENTER);
        setMargin(buttonSet, new Insets(10, 0, 0, 0));
        buttonSet.getChildren().addAll(previous, comment, next);
    

    private void initializeContent(AnchorPane root) 
        Image image = new Image(
                "http://takeinsocialmedia.com/wp-content/uploads/2014/05/landscape-art-painting-wallpaper-images-photos-0517193352.jpg"
        );
        ceiling_image = new ImageView(image);
        ceiling_image.setClip(ceiling);
        root.getChildren().add(ceiling_image);
    

【讨论】:

以上是关于JavaFX 将 ImageView 裁剪为 AnchorPane 中的椭圆的主要内容,如果未能解决你的问题,请参考以下文章

如何制作 Javafx 图像裁剪应用程序

iOS 设置图片imageView圆角——对图片进行裁剪

如何在 javafx 中调整 imageview 图像的大小?

在 JavaFX 中将 BlendMode 添加到裁剪节点

JavaFX ImageView 没有任何平滑

如何在不创建新位图的情况下拥有圆形、中心裁剪的 imageView?