Javafx:将 ImageView 绑定到 Anchorpane 或 VBox 并通过调整场景大小来缩放 ImageView

问题描述

我想通过调整场景(窗口)大小来缩放 ImageView,但我必须保持纵横比。是否可以通过调整窗口大小直接做到这一点? 谢谢您的帮助。问题是,ImageView 不会通过调整窗口大小来缩放。 我的另一个问题是:如何将图像绑定到背景,以便在调整窗口大小时它始终适合窗口并调整大小?

感谢您的帮助

这是我的 fxml 代码

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefheight="600.0" prefWidth="900.0" style="-fx-background-color: beige; -fx-border-color: black;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.GUI.Controller">
   <children>
      <VBox fx:id="vbRed" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefheight="200.0" prefWidth="101.0" style="-fx-border-color: black;" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="110.0">
         <children>
                  <ImageView fx:id="ivRed" disable="true" fitHeight="88.0" pickOnBounds="true" preserveRatio="true" VBox.vgrow="ALWAYS">
               <image>
                  <Image url="@Images/figurrot.png" />
               </image>
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="5.0" />
               </VBox.margin>
            </ImageView>
            <CheckBox fx:id="cbRed" mnemonicParsing="false" onAction="#handleCBRedAction" selected="true" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="40.0" right="10.0" top="10.0" />
               </VBox.margin></CheckBox>
            <TextField fx:id="tfNameRed" prefheight="25.0" prefWidth="88.0" promptText="Name" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="2.0" right="2.0" top="10.0" />
               </VBox.margin></TextField>
            <ChoiceBox fx:id="dbRed" prefheight="25.0" prefWidth="88.0" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="10.0" />
               </VBox.margin></ChoiceBox>
         </children>
         <opaqueInsets>
            <Insets />
         </opaqueInsets>
      </VBox>
      <VBox fx:id="vbYellow" layoutX="117.0" layoutY="110.0" prefheight="200.0" prefWidth="101.0" style="-fx-border-color: lightgrey;" AnchorPane.leftAnchor="115.0">
         <children>
            <ImageView fx:id="ivYellow" disable="true" fitHeight="88.0" opacity="0.5" pickOnBounds="true" preserveRatio="true" VBox.vgrow="ALWAYS">
               <image>
                  <Image url="@Images/figurgelb.png" />
               </image>
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="5.0" />
               </VBox.margin>
            </ImageView>
            <CheckBox fx:id="cbYellow" mnemonicParsing="false" onAction="#handleCBYellowAction" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="40.0" right="10.0" top="10.0" />
               </VBox.margin>
            </CheckBox>
            <TextField fx:id="tfNameYellow" disable="true" prefheight="25.0" prefWidth="88.0" promptText="Name" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="2.0" right="2.0" top="10.0" />
               </VBox.margin>
            </TextField>
            <ChoiceBox fx:id="dbYellow" disable="true" prefheight="25.0" prefWidth="88.0" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="10.0" />
               </VBox.margin>
            </ChoiceBox>
         </children>
      </VBox>
      <VBox fx:id="vbGreen" layoutX="227.0" layoutY="110.0" prefheight="200.0" prefWidth="101.0" style="-fx-border-color: lightgrey;" AnchorPane.leftAnchor="220.0">
         <children>
            <ImageView fx:id="ivGreen" disable="true" fitHeight="88.0" opacity="0.5" pickOnBounds="true" preserveRatio="true" VBox.vgrow="ALWAYS">
               <image>
                  <Image url="@Images/figurgruen.png" />
               </image>
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="5.0" />
               </VBox.margin>
            </ImageView>
            <CheckBox fx:id="cbGreen" mnemonicParsing="false" onAction="#handleCBGreenAction" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="40.0" right="10.0" top="10.0" />
               </VBox.margin>
            </CheckBox>
            <TextField fx:id="tfNameGreen" disable="true" prefheight="25.0" prefWidth="88.0" promptText="Name" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="2.0" right="2.0" top="10.0" />
               </VBox.margin>
            </TextField>
            <ChoiceBox fx:id="dbGreen" disable="true" prefheight="25.0" prefWidth="88.0" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="10.0" />
               </VBox.margin>
            </ChoiceBox>
         </children>
      </VBox>
      <VBox fx:id="vbBlue" layoutX="335.0" layoutY="110.0" prefheight="200.0" prefWidth="101.0" style="-fx-border-color: lightgrey;" AnchorPane.leftAnchor="325.0">
         <children>
            <ImageView fx:id="ivBlue" fitHeight="88.0" opacity="0.5" pickOnBounds="true" preserveRatio="true" VBox.vgrow="ALWAYS">
               <image>
                  <Image url="@Images/figurblau.png" />
               </image>
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="5.0" />
               </VBox.margin>
            </ImageView>
            <CheckBox fx:id="cbBlue" mnemonicParsing="false" onAction="#handleCBBlueAction" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="40.0" right="10.0" top="10.0" />
               </VBox.margin>
            </CheckBox>
            <TextField fx:id="tfNameBlue" disable="true" prefheight="25.0" prefWidth="88.0" promptText="Name" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="2.0" right="2.0" top="10.0" />
               </VBox.margin>
            </TextField>
            <ChoiceBox fx:id="dbBlue" disable="true" prefheight="25.0" prefWidth="88.0" VBox.vgrow="ALWAYS">
               <VBox.margin>
                  <Insets left="5.0" right="5.0" top="10.0" />
               </VBox.margin>
            </ChoiceBox>
         </children>
      </VBox>
      <VBox layoutX="441.0" layoutY="105.0" prefheight="200.0" prefWidth="100.0" AnchorPane.topAnchor="115.0">
         <children>
            <ImageView fx:id="ivNoOfTreasureCards" disable="true" fitHeight="38.0" fitWidth="176.0" opacity="0.0" pickOnBounds="true" preserveRatio="true" VBox.vgrow="ALWAYS">
               <image>
                  <Image url="@Images/AnzahlSchatzkarten2.png" />
               </image>
            </ImageView>
            <TextField fx:id="tfNumOfTreasurecards" disable="true" opacity="0.0" text="24" VBox.vgrow="ALWAYS">
               <font>
                  <Font size="22.0" />
               </font>
               <VBox.margin>
                  <Insets left="60.0" right="60.0" top="10.0" />
               </VBox.margin>
            </TextField>
            <Button fx:id="btnMinus" disable="true" mnemonicParsing="false" onAction="#handleBTNMinusAction" opacity="0.0" prefheight="38.0" prefWidth="38.0" text="-" VBox.vgrow="ALWAYS">
               <font>
                  <Font name="System Bold" size="9.0" />
               </font>
               <VBox.margin>
                  <Insets left="30.0" right="40.0" top="10.0" />
               </VBox.margin>
            </Button>
            <Button fx:id="btnPlus" disable="true" mnemonicParsing="false" onAction="#handleBTNPlusAction" opacity="0.0" prefheight="38.0" prefWidth="38.0" text="+" VBox.vgrow="ALWAYS">
               <font>
                  <Font name="System Bold" size="9.0" />
               </font>
               <VBox.margin>
                  <Insets left="100.0" />
               </VBox.margin>
            </Button>
         </children>
      </VBox>
      <Button fx:id="btnGo" disable="true" layoutX="519.0" layoutY="313.0" mnemonicParsing="false" onAction="#startGame" opacity="0.0" prefheight="48.0" prefWidth="88.0" text="Go!">
         <font>
            <Font name="Kristen ITC" size="20.0" />
         </font>
      </Button>
      <ImageView fitHeight="88.0" fitWidth="880.0" layoutX="12.0" layoutY="12.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="11.0" AnchorPane.rightAnchor="11.0" AnchorPane.topAnchor="11.0">
         <image>
            <Image url="@Images/titel3.png" />

         </image>
      </ImageView>
      <ImageView fx:id="ivReadyToPlay" disable="true" fitHeight="57.0" fitWidth="245.0" layoutX="310.0" layoutY="315.0" opacity="0.0" pickOnBounds="true" preserveRatio="true">
         <image>
            <Image url="@Images/ReadyToPlay2.png" />
         </image>
      </ImageView>
      <Button fx:id="btnConfirm" layoutX="170.0" layoutY="327.0" mnemonicParsing="false" onAction="#handleBTNConfirmAction" prefheight="48.0" prefWidth="88.0" text="Confirm">
         <font>
            <Font name="Kristen ITC" size="14.0" />
         </font></Button>
   </children>
</AnchorPane>

解决方法

我在图像及其调整大小行为方面遇到了类似的问题,我找到了一个代码片段来帮助我解决调整大小问题。请看here

您可能想要使用的附加 ImageViewPane.java 文件:

/*
 * Copyright (c) 2012,Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 */



import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Region;


/**
 *
 * @author akouznet
 */
public class ImageViewPane extends Region {
    
    private ObjectProperty<ImageView> imageViewProperty = new SimpleObjectProperty<ImageView>();
    
    public ObjectProperty<ImageView> imageViewProperty() {
        return imageViewProperty;
    }
    
    public ImageView getImageView() {
        return imageViewProperty.get();
    }
    
    public void setImageView(ImageView imageView) {
        this.imageViewProperty.set(imageView);
    }

    public ImageViewPane() {
        this(new ImageView());
    }

    @Override
    protected void layoutChildren() {
        ImageView imageView = imageViewProperty.get();
        if (imageView != null) {
            imageView.setFitWidth(getWidth());
            imageView.setFitHeight(getHeight());
            layoutInArea(imageView,getWidth(),getHeight(),HPos.CENTER,VPos.CENTER);
        }
        super.layoutChildren();
    }
    
    public ImageViewPane(ImageView imageView) {
        imageViewProperty.addListener(new ChangeListener<ImageView>() {

            @Override
            public void changed(ObservableValue<? extends ImageView> arg0,ImageView oldIV,ImageView newIV) {
                if (oldIV != null) {
                    getChildren().remove(oldIV);
                }
                if (newIV != null) {
                    getChildren().add(newIV);
                }
            }
        });
        this.imageViewProperty.set(imageView);
    }
}

我编写了一个简单的示例应用程序,因此您可以随意调整窗口大小并进行测试,并亲自查看图像是否根据您自己的项目需要调整大小。它还展示了一种如何添加背景图片来回答您的第二个问题的方法:

package org.example;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.Collections;


public class App extends Application {

    @Override
    public void start(Stage stage) {

        // Create necessary nodes to show an image and to illustrate its resizing behavior when user resizes the window:
        Image image = new Image("https://images.unsplash.com/photo-1613665287214-25b49c103a4f?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=687&q=80");
        ImageView imageView = new ImageView(image);
        ImageViewPane imageViewPane = new ImageViewPane(imageView);

        // Create a check box and a binding to be able to toggle the preserve ratio property of the image view:
        CheckBox checkBox = new CheckBox("Preserve Ratio");
        checkBox.selectedProperty().bindBidirectional(imageView.preserveRatioProperty());

        // Create a root container for the nodes and add them to it:
        GridPane rootPane = new GridPane();
        rootPane.add(imageViewPane,0);
        rootPane.add(checkBox,1,0);

        // Create and add a column constraint so that the image view pane takes always 30 % of the width:
        ColumnConstraints columnConstraint = new ColumnConstraints();
        columnConstraint.setPercentWidth(30);
        rootPane.getColumnConstraints().add(columnConstraint);

        // Create and add a row constraint so that the nodes are in the center:
        RowConstraints rowConstraint = new RowConstraints();
        rowConstraint.setVgrow(Priority.ALWAYS);
        rowConstraint.setValignment(VPos.CENTER);
        rootPane.getRowConstraints().add(rowConstraint);

        // Set the background image of the root pane (alternatively you can create and use a css stylesheet for this,// see https://stackoverflow.com/a/9739698/13561971 for an example):
        String backgroundUrl = "https://images.unsplash.com/photo-1497211419994-14ae40a3c7a3?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80";
        rootPane.setBackground(new Background(Collections.singletonList(new BackgroundFill(
                Color.WHITE,new CornerRadii(0),new Insets(0))),Collections.singletonList(new BackgroundImage(
                        new Image(backgroundUrl,100,false,true),BackgroundRepeat.NO_REPEAT,BackgroundPosition.DEFAULT,new BackgroundSize(1.0,1.0,true,false)))));

        // Create scene and show:
        stage.setScene(new Scene(rootPane,800,600));
        stage.show();
    }

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