Perf: PDF-Thumbnails progressiv rendern statt alle auf einmal
Placeholder-Labels werden sofort erstellt, das eigentliche Rendern erfolgt asynchron über QTimer.singleShot(0) — ein Thumbnail pro Event-Loop-Iteration. UI friert nicht mehr ein; RAM-Spitze wird verteilt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+32
-24
@@ -14,7 +14,7 @@ import logging
|
|||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PySide6.QtCore import Qt, QSize, QUrl
|
from PySide6.QtCore import Qt, QSize, QTimer, QUrl
|
||||||
from PySide6.QtGui import QCursor, QPixmap, QPainter, QDesktopServices
|
from PySide6.QtGui import QCursor, QPixmap, QPainter, QDesktopServices
|
||||||
from PySide6.QtWidgets import QLabel, QMessageBox, QSpacerItem, QSizePolicy
|
from PySide6.QtWidgets import QLabel, QMessageBox, QSpacerItem, QSizePolicy
|
||||||
from PySide6.QtPdf import QPdfDocument
|
from PySide6.QtPdf import QPdfDocument
|
||||||
@@ -206,6 +206,27 @@ class PdfViewerMixin:
|
|||||||
painter.end()
|
painter.end()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _schedule_thumbnail_rendering(self, diff_doc, pdf_basename, thumbnail_labels, page_num):
|
||||||
|
"""Rendert Thumbnails progressiv — ein Thumbnail pro Event-Loop-Iteration."""
|
||||||
|
if page_num >= len(thumbnail_labels):
|
||||||
|
return
|
||||||
|
|
||||||
|
thumbnail = thumbnail_labels[page_num]
|
||||||
|
# Prüfe ob das Label noch existiert (Benutzer könnte inzwischen anderes PDF geöffnet haben)
|
||||||
|
if thumbnail_labels[page_num] not in self.thumbnail_to_page:
|
||||||
|
return
|
||||||
|
|
||||||
|
page_size = diff_doc.pagePointSize(page_num)
|
||||||
|
scale_factor = 200.0 / page_size.width()
|
||||||
|
page_image = diff_doc.render(
|
||||||
|
page_num,
|
||||||
|
QSize(int(page_size.width() * scale_factor), int(page_size.height() * scale_factor)),
|
||||||
|
)
|
||||||
|
thumbnail.setPixmap(QPixmap.fromImage(page_image).scaledToWidth(200, Qt.TransformationMode.SmoothTransformation))
|
||||||
|
thumbnail.setMinimumHeight(0)
|
||||||
|
|
||||||
|
QTimer.singleShot(0, lambda: self._schedule_thumbnail_rendering(diff_doc, pdf_basename, thumbnail_labels, page_num + 1))
|
||||||
|
|
||||||
def _clear_layout(self, layout):
|
def _clear_layout(self, layout):
|
||||||
"""Entfernt alle Widgets aus einem Layout."""
|
"""Entfernt alle Widgets aus einem Layout."""
|
||||||
if layout is not None:
|
if layout is not None:
|
||||||
@@ -395,43 +416,30 @@ class PdfViewerMixin:
|
|||||||
# Nehme die Seitenzahl der diff-PDF als Basis
|
# Nehme die Seitenzahl der diff-PDF als Basis
|
||||||
max_pages = diff_doc.pageCount()
|
max_pages = diff_doc.pageCount()
|
||||||
|
|
||||||
# Erstelle Thumbnails für alle Seiten
|
# Erstelle Placeholder-Labels für alle Seiten (sofort, ohne Rendern)
|
||||||
|
thumbnail_labels = []
|
||||||
for page_num in range(max_pages):
|
for page_num in range(max_pages):
|
||||||
# Nur diff-Seite für Thumbnail rendern
|
|
||||||
page_size = diff_doc.pagePointSize(page_num)
|
|
||||||
|
|
||||||
# Skalierung für Thumbnail
|
|
||||||
scale_factor = 200.0 / page_size.width() # 200 Pixel Breite
|
|
||||||
|
|
||||||
# Seite rendern
|
|
||||||
page_image = diff_doc.render(
|
|
||||||
page_num,
|
|
||||||
QSize(int(page_size.width() * scale_factor), int(page_size.height() * scale_factor)),
|
|
||||||
)
|
|
||||||
|
|
||||||
diff_pixmap = QPixmap.fromImage(page_image)
|
|
||||||
|
|
||||||
# Thumbnail erstellen und zur linken Spalte hinzufügen
|
|
||||||
thumbnail = QLabel()
|
thumbnail = QLabel()
|
||||||
thumbnail.setObjectName(f"thumbnail_{pdf_basename}_page_{page_num + 1}")
|
thumbnail.setObjectName(f"thumbnail_{pdf_basename}_page_{page_num + 1}")
|
||||||
thumbnail.setPixmap(diff_pixmap.scaledToWidth(200, Qt.TransformationMode.SmoothTransformation))
|
thumbnail.setText(f"Seite {page_num + 1}\n…")
|
||||||
thumbnail.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
thumbnail.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
||||||
thumbnail.setMouseTracking(True)
|
thumbnail.setMouseTracking(True)
|
||||||
thumbnail.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
thumbnail.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
thumbnail.setMinimumHeight(150)
|
||||||
self.ui.verticalLayout_2.addWidget(thumbnail)
|
self.ui.verticalLayout_2.addWidget(thumbnail)
|
||||||
|
|
||||||
# Seitennummer für Thumbnail anzeigen
|
|
||||||
thumbnail_info = QLabel(f"Seite {page_num + 1}")
|
thumbnail_info = QLabel(f"Seite {page_num + 1}")
|
||||||
thumbnail_info.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
thumbnail_info.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
thumbnail_info.setMaximumHeight(18) # Kompakte Höhe
|
thumbnail_info.setMaximumHeight(18)
|
||||||
thumbnail_info.setContentsMargins(0, 0, 0, 0) # Keine Ränder
|
thumbnail_info.setContentsMargins(0, 0, 0, 0)
|
||||||
self.ui.verticalLayout_2.addWidget(thumbnail_info)
|
self.ui.verticalLayout_2.addWidget(thumbnail_info)
|
||||||
|
|
||||||
# Beziehung zwischen Thumbnail und Seitennummer speichern
|
|
||||||
self.thumbnail_to_page[thumbnail] = {"pdf_filename": pdf_basename, "page_num": page_num}
|
self.thumbnail_to_page[thumbnail] = {"pdf_filename": pdf_basename, "page_num": page_num}
|
||||||
|
|
||||||
# Click-Event für das Thumbnail einrichten
|
|
||||||
thumbnail.mousePressEvent = lambda event, t=thumbnail: self.on_thumbnail_clicked(event, t)
|
thumbnail.mousePressEvent = lambda event, t=thumbnail: self.on_thumbnail_clicked(event, t)
|
||||||
|
thumbnail_labels.append(thumbnail)
|
||||||
|
|
||||||
|
# Thumbnails progressiv rendern (nicht blockierend)
|
||||||
|
self._schedule_thumbnail_rendering(diff_doc, pdf_basename, thumbnail_labels, 0)
|
||||||
|
|
||||||
# Füge expandierenden Spacer am Ende hinzu, damit Thumbnails oben bleiben
|
# Füge expandierenden Spacer am Ende hinzu, damit Thumbnails oben bleiben
|
||||||
spacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
spacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
||||||
|
|||||||
Reference in New Issue
Block a user