11 Stimmen

Wie man ein Bild verkleinert, wenn man das Fenster in JavaFX verkleinert

Ich möchte, dass ein Bild automatisch verkleinert wird, wenn der Benutzer das Hauptfenster zieht. Ist das möglich?

Ich habe folgenden Code, der ein Fenster mit einer bestimmten Größe festlegt. Es lädt auch das Bild von einer externen URL.

@Override
public void start(Stage primaryStage) {

    MenuBar menuBar=new MenuBar();
    Menu menuGame = new Menu("Spiel");
    MenuItem newGame = new MenuItem("Neues Spiel                F1");
    MenuItem exit = new MenuItem("Beenden                            F2");
    exit.setOnAction(new EventHandler() {

        @Override
        public void handle(ActionEvent event) {
            primaryStage.close();
        }

    });
    menuGame.getItems().addAll(newGame,new SeparatorMenuItem(),exit);
    menuBar.getMenus().addAll(menuGame);

    Image image = new Image("http://docs.oracle.com/javafx/"
    + "javafx/images/javafx-documentation.png");
    ImageView imageView = new ImageView();
    imageView.setImage(image);

    VBox vbox=new VBox();
    StackPane root=new StackPane();
    root.getChildren().addAll(imageView);

    vbox.getChildren().addAll(menuBar,root);

    Scene scene= new Scene(vbox,400,400);
    primaryStage.setScene(scene);

    primaryStage.setMaxHeight(800);
    primaryStage.setMinHeight(400);
    primaryStage.setMaxWidth(1000);
    primaryStage.setMinWidth(800);

    primaryStage.setTitle("Minesweeper");
    primaryStage.show();

}

16voto

jewelsea Punkte 139897

Die Anwendung der Lösung für JavaFx Bildgrößenänderung an Ihrem Beispielcode und die Änderung der Fenstergröße führen bei mir zu unterschiedlichen Bildgrößen.

sizedefault sizeresize

import javafx.application.Application;
import javafx.beans.property.*;
import javafx.beans.value.*;
import javafx.event.*;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class ImageResizer extends Application {
    @Override
    public void start(Stage primaryStage) {
        MenuBar menuBar=new MenuBar();
        Menu menuGame = new Menu("Spiel");
        MenuItem newGame = new MenuItem("Neues Spiel                F1");
        MenuItem exit = new MenuItem("Beenden                            F2");
        exit.setOnAction(new EventHandler() {
            @Override
            public void handle(ActionEvent event) {
                primaryStage.close();
            }
        });
        menuGame.getItems().addAll(newGame,new SeparatorMenuItem(),exit);
        menuBar.getMenus().addAll(menuGame);

        Image image = new Image("http://docs.oracle.com/javafx/"
                + "javafx/images/javafx-documentation.png");
        ImageView imageView = new ImageView();
        imageView.setImage(image);

        ImageViewPane viewPane = new ImageViewPane(imageView);

        VBox vbox=new VBox();
        StackPane root=new StackPane();
        root.getChildren().addAll(viewPane);

        vbox.getChildren().addAll(menuBar,root);
        VBox.setVgrow(root, Priority.ALWAYS);

        Scene scene= new Scene(vbox,200,200);
        primaryStage.setScene(scene);

        primaryStage.setMaxHeight(400);
        primaryStage.setMinHeight(200);
        primaryStage.setMaxWidth(500);
        primaryStage.setMinWidth(400);

        primaryStage.setTitle("Minesweeper");
        primaryStage.show();

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

/*
 * Urheberrecht (c) 2012, Oracle und/oder seine verbundenen Unternehmen. Alle Rechte vorbehalten.
 * ÄNDERN ODER ENTFERNEN SIE KEINE URHEBERRECHTSVERMERKE ODER DIESER DATEIKOPF.
 */

/**
 *
 * @autor akouznet
 */
class ImageViewPane extends Region {

    private ObjectProperty imageViewProperty = new SimpleObjectProperty();

    public ObjectProperty 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, 0, 0, getWidth(), getHeight(), 0, HPos.CENTER, VPos.CENTER);
        }
        super.layoutChildren();
    }

    public ImageViewPane(ImageView imageView) {
        imageViewProperty.addListener(new ChangeListener() {

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

Alternative Ansätze und zusätzliche Informationen basierend auf Kommentaren

Wenn Sie das alles tun müssen, dann ist das eine Schwäche der JavaFX-Plattform. Idealerweise würde ich erwarten, dass es eine Skalierungseigenschaft des Bildes gäbe, die man setzen könnte, so dass es seine Größe mithilfe des Szenengraphen bestimmt.

Die oben gezeigte Lösung ist nur eine Antwort, es gibt auch andere Möglichkeiten. Der Szenengraph kann verwendet werden, indem verschiedene Eigenschaften an die Breite und Höhe des übergeordneten Knotens gebunden werden oder indem layoutChildren im übergeordneten Knoten überschrieben wird.

Zugehörige Eigenschaften:

Ich bevorzuge den Ansatz mit der Region-Unterklasse gegenüber einer Skalierungseigenschaft oder einem transformationsbasierten Ansatz, weil das Bild dann automatisch auf Grund des Layout-Managers dimensioniert wird. Die obige ImageViewPane ist nur eine einmalige Definitionsklasse, die beliebig oft wiederverwendet werden kann, der tatsächliche Anwendungscode zur Verwendung eines ImageView oder ImageViewPane ist weitgehend äquivalent.

Ein weiterer möglicher Ansatz besteht darin, eine Region-Unterklasse (wie z. B. ein Pane) zu verwenden, die eine definierte CSS-Stilklasse oder ID hat, und dann das Bild in CSS als Hintergrund zu definieren. Das Schöne an einem per CSS definierten Bild ist, dass Sie dann zusätzliche CSS-basierte Attribute verwenden können, um Dinge wie Größenänderung, Skalierung, Positionierung und Wiederholungen für das Bild festzulegen. Dieser Hintergrund kann auch programmgesteuert festgelegt werden, wenn gewünscht, anstatt über CSS.

Zugehörige Frage:

Um das Verhältnis von Höhe und Breite des Bildes beizubehalten

Der folgende Code kann in der ImageViewPane-Klasse verwendet werden, die oben bereitgestellt wurde:

if (imageView.isPreserveRatio()) {
    if (getHeight() > getWidth()) {
        imageView.setFitWidth(getWidth());
        imageView.setFitHeight(0);
    } else {
        imageView.setFitWidth(0);
        imageView.setFitHeight(getHeight());
    }
} else {
    imageView.setFitWidth(getWidth());
    imageView.setFitHeight(getHeight());
}

6voto

Andrew S Punkte 2535

Ich weiß, dass dies alt ist, aber jemand wie ich könnte darauf stoßen, also hier ist meine Lösung. Ich gehe davon aus, dass root der Wurzelknoten Ihrer Szene ist. Diese sollte jedoch funktionieren, wenn der Elternknoten des ImageView ein Kind von Pane ist.

imv = new ImageView();  
root.getChildren().add(imv);
Image image = new Image(Main.class.getResourceAsStream("image.png"))
imv.setImage(image);

imv.fitWidthProperty().bind(center.widthProperty());
imv.fitHeightProperty().bind(center.heightProperty());

3voto

Blu Punkte 31

Verwenden Sie einfach ein normales Fenster mit einem Hintergrundbild, hier der benötigte CSS-Code.

#titleImage{
    -fx-background-image: url("../img/logo.png");
    -fx-background-repeat: stretch; 
    -fx-background-position: center center;
}

0voto

Georgian Punkte 8745

Sind Sie auf der Suche danach, ein tatsächliches Bild zu verkleinern oder nur, um es zu zentrieren?

Sie können dies versuchen: VBox.setVgrow(root, Priority.ALWAYS); und sehen, ob das das ist, was Sie wollen.

Seien Sie auch vorsichtig mit Ihrem Bild, denn es handelt sich um ein png Bild. Ich bin etwas skeptisch, was dort verkleinert wird (das tatsächliche Bild oder der transparente Hintergrund).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X