Behebe Zoom-Sprung und Zentrierung nach Rauszoomen
Bug 1: deltaY vor Akkumulation auf einen Notch-Wert begrenzen. Plattformspezifische Scroll-Multiplikatoren (Windows-Mausgeschwindigkeit, hohe DPI-Mäuse) können Werte wie 120 statt 40 liefern. Ohne Normierung akkumuliert sich ein Überlaufwert, der Folge-Events sofort auslöst. Bug 2: resetToFitView() setzt nach setFitToWidth(true) explizit scrollPane.setHvalue(0.5) und setVvalue(0.5) (nach layout()-Aufruf), damit vorherige Pan-Scroll-Werte die Zentrierung nicht nachwirken. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+24
-4
@@ -631,12 +631,19 @@ public final class PdfPreviewPane {
|
|||||||
* Pro Raste (ca. {@value #ZOOM_NOTCH_THRESHOLD} Einheiten) ändert sich der Zoom
|
* Pro Raste (ca. {@value #ZOOM_NOTCH_THRESHOLD} Einheiten) ändert sich der Zoom
|
||||||
* um {@value #ZOOM_STEP}. Pro ScrollEvent wird maximal eine Zoom-Stufe angewendet.
|
* um {@value #ZOOM_STEP}. Pro ScrollEvent wird maximal eine Zoom-Stufe angewendet.
|
||||||
*
|
*
|
||||||
|
* <p>Der Rohwert von {@code deltaY} wird vor der Akkumulation auf einen
|
||||||
|
* Notch-Wert ({@value #ZOOM_NOTCH_THRESHOLD}) begrenzt. Plattformspezifische
|
||||||
|
* Scroll-Multiplikatoren (z. B. Windows-Mausgeschwindigkeit, hohe DPI-Mäuse)
|
||||||
|
* können sonst Werte wie 120 oder mehr pro Raste liefern, was einen
|
||||||
|
* Akkumulator-Überlauf in Folge-Events verursacht.
|
||||||
|
*
|
||||||
* @param deltaY vertikaler Scroll-Delta des {@link ScrollEvent}
|
* @param deltaY vertikaler Scroll-Delta des {@link ScrollEvent}
|
||||||
*/
|
*/
|
||||||
private void accumulateAndApplyZoomDelta(double deltaY) {
|
private void accumulateAndApplyZoomDelta(double deltaY) {
|
||||||
zoomAccumulator += deltaY;
|
// Normierung: maximal einen Notch-Wert pro Event akkumulieren, um
|
||||||
// 32a: Pro Mausrad-Raste genau eine Zoom-Stufe (if statt while verhindert
|
// plattformspezifische deltaY-Überhöhungen (z. B. 120 statt 40) abzufangen
|
||||||
// mehrfaches Springen bei großen deltaY-Werten)
|
double capped = Math.signum(deltaY) * Math.min(Math.abs(deltaY), ZOOM_NOTCH_THRESHOLD);
|
||||||
|
zoomAccumulator += capped;
|
||||||
if (zoomAccumulator >= ZOOM_NOTCH_THRESHOLD) {
|
if (zoomAccumulator >= ZOOM_NOTCH_THRESHOLD) {
|
||||||
zoomAccumulator -= ZOOM_NOTCH_THRESHOLD;
|
zoomAccumulator -= ZOOM_NOTCH_THRESHOLD;
|
||||||
applyZoom(Math.min(ZOOM_MAX, zoomLevel + ZOOM_STEP));
|
applyZoom(Math.min(ZOOM_MAX, zoomLevel + ZOOM_STEP));
|
||||||
@@ -700,12 +707,18 @@ public final class PdfPreviewPane {
|
|||||||
/**
|
/**
|
||||||
* Setzt Zoom, Akkumulator und Pan-Zustand zurück und reaktiviert den Fit-to-View-Modus.
|
* Setzt Zoom, Akkumulator und Pan-Zustand zurück und reaktiviert den Fit-to-View-Modus.
|
||||||
* Wird beim Laden einer neuen Datei und beim Leeren der Komponente aufgerufen.
|
* Wird beim Laden einer neuen Datei und beim Leeren der Komponente aufgerufen.
|
||||||
|
*
|
||||||
|
* <p>Nach dem Reaktivieren von {@code fitToWidth} werden H- und V-Scroll-Werte
|
||||||
|
* explizit auf 0.5 gesetzt (nach einem {@code layout()}-Aufruf, damit die neuen
|
||||||
|
* Inhaltsgrenzen bekannt sind). Ohne diesen Schritt trägt der ScrollPane ggf. noch
|
||||||
|
* die H/V-Werte aus dem vorherigen Zoom-/Pan-Zustand und zeigt die PDF nach dem
|
||||||
|
* Reset nicht zentriert an.
|
||||||
*/
|
*/
|
||||||
private void resetToFitView() {
|
private void resetToFitView() {
|
||||||
zoomLevel = 1.0;
|
zoomLevel = 1.0;
|
||||||
zoomAccumulator = 0.0;
|
zoomAccumulator = 0.0;
|
||||||
naturalViewportWidth = 0.0;
|
naturalViewportWidth = 0.0;
|
||||||
// 32e: Pan-Zustand und Mauszeiger zurücksetzen
|
// Pan-Zustand und Mauszeiger zurücksetzen
|
||||||
panStartX = -1;
|
panStartX = -1;
|
||||||
panStartY = -1;
|
panStartY = -1;
|
||||||
viewStack.setCursor(null);
|
viewStack.setCursor(null);
|
||||||
@@ -714,6 +727,13 @@ public final class PdfPreviewPane {
|
|||||||
imageView.fitHeightProperty().bind(viewStack.heightProperty());
|
imageView.fitHeightProperty().bind(viewStack.heightProperty());
|
||||||
scrollPane.setFitToWidth(true);
|
scrollPane.setFitToWidth(true);
|
||||||
scrollPane.setFitToHeight(true);
|
scrollPane.setFitToHeight(true);
|
||||||
|
// Zentrierung sicherstellen: nach layout() H/V auf Mitte setzen,
|
||||||
|
// damit verbleibende Scroll-Werte aus dem Zoom-/Pan-Modus nicht nachwirken
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
scrollPane.layout();
|
||||||
|
scrollPane.setHvalue(0.5);
|
||||||
|
scrollPane.setVvalue(0.5);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user