问题描述
我想通过调整场景(窗口)大小来缩放 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();
}
}