diff --git a/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/batchrun/PdfPreviewPane.java b/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/batchrun/PdfPreviewPane.java index c59b4a1..5e3c11b 100644 --- a/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/batchrun/PdfPreviewPane.java +++ b/pdf-umbenenner-adapter-in-gui/src/main/java/de/gecheckt/pdf/umbenenner/adapter/in/gui/batchrun/PdfPreviewPane.java @@ -17,7 +17,6 @@ import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; -import javafx.animation.AnimationTimer; import javafx.application.Platform; import javafx.embed.swing.SwingFXUtils; import javafx.geometry.Bounds; @@ -244,6 +243,15 @@ public final class PdfPreviewPane { viewStack.addEventHandler(MouseEvent.MOUSE_PRESSED, this::onPanMousePressed); viewStack.addEventHandler(MouseEvent.MOUSE_DRAGGED, this::onPanMouseDragged); viewStack.addEventHandler(MouseEvent.MOUSE_RELEASED, this::onPanMouseReleased); + // viewStack ist immer mindestens so groß wie der Viewport. Ist der Inhalt + // (ImageView) kleiner als der Viewport, sorgt diese Mindestgröße zusammen + // mit StackPane.Pos.CENTER dafür, dass die ImageView automatisch zentriert + // wird – ohne manuelle setHvalue/setVvalue-Eingriffe. Ist der Inhalt größer, + // bleibt die Mindestgröße wirkungslos und der ScrollPane scrollt normal. + scrollPane.viewportBoundsProperty().addListener((obs, old, bounds) -> { + viewStack.setMinWidth(bounds.getWidth()); + viewStack.setMinHeight(bounds.getHeight()); + }); prevButton.setId("pdf-preview-prev-button"); prevButton.setOnAction(e -> navigateToPreviousPage()); @@ -726,33 +734,10 @@ public final class PdfPreviewPane { zoomLevel = effective; imageView.setFitWidth(naturalViewportWidth * zoomLevel); imageView.setFitHeight(0); - - if (wasInFitMode) { - // Erster Zoom-Schritt nach Verlassen des Fit-Modus: setFitToWidth(false) - // löst Layout-, CSS- und Property-Reset-Passes innerhalb desselben - // JavaFX-Frames aus. Ein AnimationTimer feuert handle() nach allen - // diesen Passes des aktuellen Frames; das ist der einzige Punkt, - // an dem setHvalue(0.5)/setVvalue(0.5) garantiert nicht mehr von - // einem nachträglichen Reset überschrieben werden. stop() im ersten - // handle()-Aufruf macht den Timer zum Single-Shot. - new AnimationTimer() { - @Override - public void handle(long now) { - stop(); - scrollPane.setHvalue(0.5); - scrollPane.setVvalue(0.5); - } - }.start(); - } else { - // Folge-Schritte: aktuelle Scroll-Position bewahren - double hval = scrollPane.getHvalue(); - double vval = scrollPane.getVvalue(); - Platform.runLater(() -> { - scrollPane.layout(); - scrollPane.setHvalue(hval); - scrollPane.setVvalue(vval); - }); - } + // Keine manuellen setHvalue/setVvalue-Eingriffe nötig: viewStack hat + // dank des viewportBoundsProperty-Listeners im Konstruktor mindestens + // Viewport-Größe, und Pos.CENTER sorgt für automatische Zentrierung, + // wenn der Inhalt kleiner als der Viewport ist. } /** @@ -787,14 +772,11 @@ public final class PdfPreviewPane { // den viewStack auf Viewport-Größe zurückrechnet scrollPane.setFitToWidth(true); scrollPane.setFitToHeight(true); - // 2./3. Bindings und H/V-Reset erst nach abgeschlossenem Layout-Pass, - // damit sie auf die zurückgerechneten Dimensionen wirken und - // Rounding-Reste aus Pan/Zoom die Zentrierung nicht verschieben + // 2. Bindings erst nach abgeschlossenem Layout-Pass, damit sie auf + // die zurückgerechneten viewStack-Dimensionen wirken Platform.runLater(() -> { imageView.fitWidthProperty().bind(viewStack.widthProperty()); imageView.fitHeightProperty().bind(viewStack.heightProperty()); - scrollPane.setHvalue(0.5); - scrollPane.setVvalue(0.5); }); } }