Wie füge ich ein Bild in javafx mit dem Scenebuilder ein, das automatisch mitgezogen wird, wenn das Fenster vergrößert wird oder Vollbildmodus

berserkerdq2

Bekanntes Mitglied
Mir hat einer gesagt, dass wenn er bei Javafx auf ein Panel ein Bild oder eine GUI ladet dass das Bild automatisch auf die Größe angepasst wird, wie das Fenster in dem Moment ist, egal ob Vollbild etc, aber wie geht das?
 
Beste Antwort
Also wenn ich den Scenebuilder nutze, was meint Anchor auf 0 setzen?

Wenn Du ein Element auf eine AnchotPane setzt, dann kannst Du Anchor Pane Constraints setzen. Damit wird die Größe immer relativ zu der Grenze angepasst. 0 bedeutet halt, dass zwischen der Grenze der AnchorPane hin zu dem Image immer genau 0 Pixel Platz sind.
1678460231733.png

Preserve Ratio ist direkt unter Properties zu finden und ist per default an:
1678460388150.png

Das wäre die Erläuterung zu dem, was ich da so geschrieben habe. Das ist aber so nicht ganz, was Du genau willst. Die ImageView setzt seine Größe auf diese fitHeight / fitWidth Größe. Daher bringen diese Anchors nicht so viel, wie ich ursprünglich dachte.

Ich habe keine Ahnung, was genau Du machen...
Ich weiß nicht, ob ich dich richtig verstehe.
Aber du kannst die Größe deines Fensters auslesen und mit deinem Objekt verbinden .bind(root.widthProperty().
Entsprechend deines gewünschten Verhältnis von deinem Bildschirm kannst du über eine Funktion dein ImageView auf die passende Größe skalieren.
Vom Prinzip genau so wie im folgenden Beispiel.


Java:
            Pane root = new Pane();

            Circle kreis1 = new Circle();
            kreis1.centerXProperty().bind(root.widthProperty().divide(2));
            kreis1.centerYProperty().bind(root.heightProperty().divide(2));
            kreis1.radiusProperty().bind(root.widthProperty().divide(4));

            root.getChildren().add(kreis1);
 
Zuletzt bearbeitet:
Da ist die Frage erst einmal, was Du wie nutzt. Generell kannst Du ein Bild mit einem ImageView darstellen. Wenn Du es auf einer AnchorPane darstellst, dann ist es einfach, weil Du da die Anchor einfach alle auf 0 setzt. Damit füllt die ImageView immer die ganze Pane aus.

Du kannst fitWidth und fitHeight nutzen um dafür zu sorgen, dass das Bild immer in der Größe verändert wird und preserveRatio falls Du sicher gehen willst, dass es nicht verzerrt wird.
 
Da ist die Frage erst einmal, was Du wie nutzt. Generell kannst Du ein Bild mit einem ImageView darstellen. Wenn Du es auf einer AnchorPane darstellst, dann ist es einfach, weil Du da die Anchor einfach alle auf 0 setzt. Damit füllt die ImageView immer die ganze Pane aus.

Du kannst fitWidth und fitHeight nutzen um dafür zu sorgen, dass das Bild immer in der Größe verändert wird und preserveRatio falls Du sicher gehen willst, dass es nicht verzerrt wird.
Danke, aber wie genau mache ich das? Also wenn ich den Scenebuilder nutze, was meint Anchor auf 0 setzen?
Und wie genau fitWidth und fitHeight? Soll ich das dann ohne Scenebuilder machen? Und preserveRatio, wie genau wird das genutzt? (Sorry bin totaler Anfänger in diesem Gebiet)
 
Also wenn ich den Scenebuilder nutze, was meint Anchor auf 0 setzen?

Wenn Du ein Element auf eine AnchotPane setzt, dann kannst Du Anchor Pane Constraints setzen. Damit wird die Größe immer relativ zu der Grenze angepasst. 0 bedeutet halt, dass zwischen der Grenze der AnchorPane hin zu dem Image immer genau 0 Pixel Platz sind.
1678460231733.png

Preserve Ratio ist direkt unter Properties zu finden und ist per default an:
1678460388150.png

Das wäre die Erläuterung zu dem, was ich da so geschrieben habe. Das ist aber so nicht ganz, was Du genau willst. Die ImageView setzt seine Größe auf diese fitHeight / fitWidth Größe. Daher bringen diese Anchors nicht so viel, wie ich ursprünglich dachte.

Ich habe keine Ahnung, was genau Du machen willst. Aber machen wir ein einfaches Beispiel: Wir machen nur ein einziges Fenster und da packen wir nur eine ImageView rein.

Das kannst Du noch mit dem SceneBuilder machen. Ebenso das Vergeben der fx:id und so. Und man kann oben und unten ein anchor mit Wert 0 setzen, wobei ein Setzenm auf Posiotion 0, 0 auch ausreichen sollte.

Dann brauchst Du einen Controller, den Du auch einträgst im fxml.

Danach ist abe rerst einmal Schluss mit SceneBuilder fürchte ich. Denn die fitHeight / fitWidth Werte müssen noch gelöscht werden. Dann sollte unter dem Strich das FXML so in etwa aussehen:
XML:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>

<AnchorPane fx:id="anchorPane" prefHeight="410.0" prefWidth="485.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.kneitzel.MainWindow">
   <children>
      <ImageView fx:id="imageView" layoutX="-2.0" layoutY="-1.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
   </children>
</AnchorPane>

Die anchorView und imageView wollen wir dann natürlich injecten lassen in den Controller. Dazu brauchen wir zwei Instanzvariablen, die mit @FXML Annotation versehen werden.

Dann implementieren wir noch Initializable und implementieren noch diese Methode.

Dort laden wir erst einmal ein Image und packen es in die ImageView.

Und dann wollen wir die ImageView in der Größe anpassen, wann immer die Breite des Fensters sich ändert. Dazu können wir die Properties verwenden - das wird dann richtig einfach und wir erhalten Code wie:
Java:
package de.kneitzel;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainWindow implements Initializable {

    @FXML
    private AnchorPane anchorPane;
    @FXML
    private ImageView imageView;
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        Image image = new Image(getClass().getResourceAsStream("/TestBild.png"));
        imageView.setImage(image);
        imageView.fitWidthProperty().bind(anchorPane.widthProperty());
    }

}

Das Bild muss natürlich als Ressource zur Verfügung stehen - da hatte ich jetzt einfach ein kleines Testbild genommen.

Jetzt hast Du aber ggf. unten eine weiße Fläche, wenn das Fenster zu hoch ist. Das muss natürlich auch nicht sein. Dazu könnten wir einfach auf Veränderungen der AnchorPane bei Breite und Höhe reagieren um dann entweder die Breite oder die Höhe fest zu setzen. Das sähe dann so aus:

Java:
package de.kneitzel;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainWindow implements Initializable {

    @FXML
    private AnchorPane anchorPane;
    @FXML
    private ImageView imageView;

    double ratio;
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        Image image = new Image(getClass().getResourceAsStream("/TestBild.png"));
        imageView.setImage(image);
        ratio = image.getWidth() / image.getHeight();
        anchorPane.widthProperty().addListener(e -> setSize());
        anchorPane.heightProperty().addListener(e -> setSize());
    }

    public void setSize() {
        if (anchorPane.getWidth() / anchorPane.getHeight() < ratio) {
            imageView.setFitWidth(0.);
            imageView.setFitHeight(anchorPane.getHeight());
        } else {
            imageView.setFitHeight(0.);
            imageView.setFitWidth(anchorPane.getWidth());
        }
    }

}

Das wäre die Variante, bei der immer entweder unten oder rechts etwas abgeschnitten wird. Wenn man in der Abfrage aus dem < ein > macht, dann würde man immer unten oder rechts einen weissen Streifen haben.
 
Beste Antwort
Wenn Du ein Element auf eine AnchotPane setzt, dann kannst Du Anchor Pane Constraints setzen. Damit wird die Größe immer relativ zu der Grenze angepasst. 0 bedeutet halt, dass zwischen der Grenze der AnchorPane hin zu dem Image immer genau 0 Pixel Platz sind.
Anhang anzeigen 20748

Preserve Ratio ist direkt unter Properties zu finden und ist per default an:
Anhang anzeigen 20750

Das wäre die Erläuterung zu dem, was ich da so geschrieben habe. Das ist aber so nicht ganz, was Du genau willst. Die ImageView setzt seine Größe auf diese fitHeight / fitWidth Größe. Daher bringen diese Anchors nicht so viel, wie ich ursprünglich dachte.

Ich habe keine Ahnung, was genau Du machen willst. Aber machen wir ein einfaches Beispiel: Wir machen nur ein einziges Fenster und da packen wir nur eine ImageView rein.

Das kannst Du noch mit dem SceneBuilder machen. Ebenso das Vergeben der fx:id und so. Und man kann oben und unten ein anchor mit Wert 0 setzen, wobei ein Setzenm auf Posiotion 0, 0 auch ausreichen sollte.

Dann brauchst Du einen Controller, den Du auch einträgst im fxml.

Danach ist abe rerst einmal Schluss mit SceneBuilder fürchte ich. Denn die fitHeight / fitWidth Werte müssen noch gelöscht werden. Dann sollte unter dem Strich das FXML so in etwa aussehen:
XML:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>

<AnchorPane fx:id="anchorPane" prefHeight="410.0" prefWidth="485.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.kneitzel.MainWindow">
   <children>
      <ImageView fx:id="imageView" layoutX="-2.0" layoutY="-1.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
   </children>
</AnchorPane>

Die anchorView und imageView wollen wir dann natürlich injecten lassen in den Controller. Dazu brauchen wir zwei Instanzvariablen, die mit @FXML Annotation versehen werden.

Dann implementieren wir noch Initializable und implementieren noch diese Methode.

Dort laden wir erst einmal ein Image und packen es in die ImageView.

Und dann wollen wir die ImageView in der Größe anpassen, wann immer die Breite des Fensters sich ändert. Dazu können wir die Properties verwenden - das wird dann richtig einfach und wir erhalten Code wie:
Java:
package de.kneitzel;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainWindow implements Initializable {

    @FXML
    private AnchorPane anchorPane;
    @FXML
    private ImageView imageView;
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        Image image = new Image(getClass().getResourceAsStream("/TestBild.png"));
        imageView.setImage(image);
        imageView.fitWidthProperty().bind(anchorPane.widthProperty());
    }

}

Das Bild muss natürlich als Ressource zur Verfügung stehen - da hatte ich jetzt einfach ein kleines Testbild genommen.

Jetzt hast Du aber ggf. unten eine weiße Fläche, wenn das Fenster zu hoch ist. Das muss natürlich auch nicht sein. Dazu könnten wir einfach auf Veränderungen der AnchorPane bei Breite und Höhe reagieren um dann entweder die Breite oder die Höhe fest zu setzen. Das sähe dann so aus:

Java:
package de.kneitzel;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;

import java.net.URL;
import java.util.ResourceBundle;

public class MainWindow implements Initializable {

    @FXML
    private AnchorPane anchorPane;
    @FXML
    private ImageView imageView;

    double ratio;
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        Image image = new Image(getClass().getResourceAsStream("/TestBild.png"));
        imageView.setImage(image);
        ratio = image.getWidth() / image.getHeight();
        anchorPane.widthProperty().addListener(e -> setSize());
        anchorPane.heightProperty().addListener(e -> setSize());
    }

    public void setSize() {
        if (anchorPane.getWidth() / anchorPane.getHeight() < ratio) {
            imageView.setFitWidth(0.);
            imageView.setFitHeight(anchorPane.getHeight());
        } else {
            imageView.setFitHeight(0.);
            imageView.setFitWidth(anchorPane.getWidth());
        }
    }

}

Das wäre die Variante, bei der immer entweder unten oder rechts etwas abgeschnitten wird. Wenn man in der Abfrage aus dem < ein > macht, dann würde man immer unten oder rechts einen weissen Streifen haben.
Ich habe jetzt den Code teilweise versucht anzuwenden und das klappt auch, nur habe ich das Bild schon zugefügt, weshalb ich das hier nicht gemacht habe.

Bei mir funktioniert auch alles, nur habe ich ein Problem, ich habe das implements Initializbe entfernt und bei der Methode initialize rufe ich nur noch die Listener auf.

und es klappt auch alles weitere noch.

Was bei mir aber nun der Fall ist, wenn ich die Methodennamen so lasse geht es, wenn ich jedoch den Methodenname von initialize ändere, sagt er mir, die Methode wird nicht mehr genutzt und wenn ich dann das Programm starte, wird das Bild nicht skaliert, warum?
Also warum muss ich gezwungenermaßen die Methode nun initalize nennen?
 
Der FXMLLoader ruft nun einmal Initialize auf nachdem Komponenten injected wurden.

Und daher würde ich auch das Interface lassen, denn das macht diesen Umstand eben deutlich und verhindert, dass jemand die Methode umbenennt.
 

Zurück
Oben