Wie kann man die Darstellung eines Bildes mit JavaFX anpassen?
Das Beispiel zeigt eine einfache JavaFX
-Anwendung,
in der ein Bild angezeigt wird, dessen Darstellung nach Klick
auf entsprechende Buttons skaliert, gedreht und beschnitten
werden kann.
In start()
wird als erstes ein Bild geladen und
durch Übergabe an den Konstruktor auf eine ImageView
gesetzt. Dieser wird dann ein Schatteneffekt in Form eines DropShadow
hinzugefügt. Der Konstruktor bekommt zwei Parameter
übergeben: die Breite des Schattenverlaufs und die Farbe.
Es folgt die Deklaration vierer Button
-Objekte, die
jeweils bei EventHandlern angemeldet werden. In deren Methoden handle()
findet der Aufruf jeweils einer Methode für das Rotieren,
Skalieren, Beschneiden der Bilddarstellung und das
Zurücksetzen der Manipulationen statt.
Mit einem Abstand
von fünf Pixeln werden die Buttons in eine HBox
gesetzt und in dieser durch setAlignment(Pos.CENTER)
zentriert.
Das Layout wird durch ein GridPane
gemanaged. Durch
die Übergabe entsprechender Parameter an add()
werden die ImageView
auf die oberste Zelle und die
HBox
darunter gesetzt.
Die Formatierung der
Rasterzellen findet auf zweierlei Weisen statt. Zunächst
wird die ImageView
durch die statischen Methoden GridPane.setHalignment()
und GridPane.setValignment()
horizontal und
vertikal zentriert. Dann werden die Zeilen durch die
Übergabe von Constraints hinsichtlich ihrer Höhe
festgelegt. Hierbei wird der ersten Zeile, derjenigen mit der ImageView
,
eine flexible Höhe zugewiesen um sicherzustellen, dass die
Fläche immer den Großteil der Scene
einnimmt
und die Buttons sich am unteren Fensterrand befinden.
Vorsicht
übrigens bei gleichzeitiger Verwendung von absoluten und
relativen Angaben innerhalb eines Constraintsystems. Dies ist
nicht unproblematisch und kann zu unvorhersehbaren Ergebnissen
führen.
Auf ähnliche Weise wird die Breite der ImageView
-Darstellung
gewährleistet. Da im Fenster eine GridPane
mit
einer einzigen Spalte dargestellt ist, kann deren Breite durch
eine Zuweisung von 100% Spaltenbreite auf diejenige der
Fensterbreite festgelegt werden.
Die Erzeugung einer Scene
, deren Setzen auf die Stage
,
das Anpassen der Fenstergröße an die Scene
und das Anzeigen der Application
schließen den
Quelltext ab.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class BildManipulieren extends Application {
@Override
public void start(Stage primaryStage) {
Image image = new Image("img/wien.jpg");
ImageView imgView = new ImageView(image);
imgView.setEffect(new DropShadow(20, Color.BLACK));
Button rotButt = new Button("drehen");
rotButt.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
imgView.setRotate(imgView.getRotate() + 90);
}
});
Button scaleButt = new Button("skalieren");
scaleButt.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
scale(imgView, 200);
}
});
Button clipButt = new Button("beschneiden");
clipButt.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
clip(imgView);
}
});
Button resetButt = new Button("reset");
resetButt.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
reset(imgView);
}
});
HBox buttBox = new HBox(5);
buttBox.getChildren().addAll(rotButt, scaleButt, clipButt, resetButt);
buttBox.setPadding(new Insets(.5));
buttBox.setAlignment(Pos.CENTER);
GridPane grid = new GridPane();
grid.add(imgView, 0, 0);
grid.add(buttBox, 0, 1);
grid.setGridLinesVisible(false);
GridPane.setHalignment(imgView, HPos.CENTER);
GridPane.setValignment(imgView, VPos.CENTER);
RowConstraints row1 = new RowConstraints();
row1.setVgrow(Priority.ALWAYS);
grid.getRowConstraints().add(row1);
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth(100);
grid.getColumnConstraints().add(col1);
Scene scene = new Scene(grid, Color.RED);
primaryStage.setTitle("ImageView Beispiel");
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
private void scale(ImageView view, double trans) {
Image img = view.getImage();
if (img == null)
return;
double imgW = view.getFitWidth() > 0 ? view.getFitWidth() : img.getWidth();
double imgH = view.getFitHeight() > 0 ? view.getFitHeight() : img.getHeight();
double deltaX = img.getWidth() / trans;
double deltaY = img.getHeight() / trans;
double delta = deltaX >= deltaY ? deltaX : deltaY;
double newW = imgW / delta;
double newH = imgH / delta;
double oldW = view.getFitWidth();
double oldH = view.getFitHeight();
view.setFitWidth(newW);
view.setFitHeight(newH);
view.setPreserveRatio(true);
view.setX((oldW - newW) / 2);
view.setY((oldH - newH) / -2);
}
private void clip(ImageView view) {
Rectangle2D rect = new Rectangle2D(50, 50, 200, 200);
view.setViewport(rect);
}
private void reset(ImageView view) {
Image img = view.getImage();
view.setRotate(0);
view.setFitWidth(img.getWidth());
view.setFitHeight(img.getHeight());
view.setPreserveRatio(true);
view.setViewport(null);
}
public static void main(String[] args) {
Application.launch(args);
}
}
Werfen wir einen Blick auf die drei Methoden zur Manipulation der Anzeige in der Reihenfolge ihrer Deklaration.
Rotation
Zur Rotation der ImageView
genügt es, die
Methode rotate()
der ImageView
aufzurufen. Ihr wird der aktuelle Rotationsgrad plus 90 Grad als
Parameter übergeben, sodass bei jedem Klick eine
Viertelumdrehung in Uhrzeigerrichtung erfolgt. Die
Bilddarstellung bleibt dabei unskaliert, sodass ggf. nicht die
vollständige Abbildung erfolgt.
Skalierung
Die Methode scale()
dient zum Skalieren der ImageView
.
Sie bekommt die ImageView
selbst und einen
Skalierungsfaktor als Parameter übergeben. Von dieser wird
das geladene Image
-Objekt ermittelt. Ist keines
vorhanden, so terminiert die Methode ergebnislos. Es gilt zu
beachten, dass das Image
selbst nicht skaliert
wird, sondern mit seinen Kantenlängen lediglich die
Berechnungsgrundlage darstellt.
Ist ein Bild geladen, so
werden Breite und Höhe der Darstellung ermittelt und zwar
so, dass bei bereits erfolgter Skalierung die Werte der
skalierten Darstellung, ansonsten die Werte des Ausgangsbildes
verwendet werden.
Der Quotient der Kantenlängen des
Ausgangsbildes und des Skalierungsfaktors wird errechnet und der
größere von beiden in der Variablen delta
abgelegt. Bildbreite und -höhe werden durch delta
dividiert, um die Zielgröße des Bildes zu erreichen.
Durch die Methode setPreserveRatio()
wird erreicht,
dass die korrekte Proportionierung des Bildes erhalten bleibt.
In
den letzten beiden Zeilen der Methode wird die Mittelposition
der ImageView
auf der Scene errechnet und diese
entsprechend gesetzt.
Beschneidung
Die Methode clip()
ist recht einfach gestaltet.
Hier wird ein Rechteck in Form eines Rectangle
-Objektes
in der gewünschten Ausschnittgröße erstellt und
durch setViewport()
auf die ImageView
gesetzt.
Zurücksetzen
Zum Zurücksetzen der Ansicht auf den Ausgangszustand wird
der Rotationswinkel auf 0 gesetzt, die ImageView
wieder auf die Kantenlängen des Ausgangsbildes gebracht und
die Viewporteinschränkung entfernt.
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.