Viewer: one overlay rebuild per pan/zoom, and only invalidate the image when it changed
Panning called updateOverlay() three times per mouse move: once for each scrollbar's valueChanged -> onScroll(), then once explicitly. Zooming was the same. Every one of those tore down and rebuilt every overlay item. Suppress onScroll() for the duration of the gesture instead, and let the gesture do its single rebuild at the end. Note this cannot be done by blocking the scrollbars' signals: QAbstractScrollArea drives the actual scrolling off valueChanged, so blocking it would stop the view moving at all. updateOverlay() also refreshed the image item unconditionally, which marks the whole item dirty and forces a full-viewport repaint even though pan and zoom never change the pixels. Track whether RenderImage has run since the last refresh and skip it otherwise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -64,6 +64,8 @@ JFJochImage::JFJochImage(QWidget *parent) : QGraphicsView(parent) {
|
||||
}
|
||||
|
||||
void JFJochImage::onScroll(int value) {
|
||||
if (suppress_overlay_update_)
|
||||
return;
|
||||
updateOverlay();
|
||||
}
|
||||
|
||||
@@ -134,6 +136,10 @@ void JFJochImage::wheelEvent(QWheelEvent *event) {
|
||||
changeForeground(new_foreground);
|
||||
emit foregroundChanged(foreground);
|
||||
} else {
|
||||
// Zooming and re-centering both move the scrollbars, and every move reaches
|
||||
// onScroll(); suppress those and rebuild the overlay once, below.
|
||||
suppress_overlay_update_ = true;
|
||||
|
||||
// Perform zooming
|
||||
if (event->angleDelta().y() > 0) {
|
||||
if (scale_factor * zoomFactor < 500.0) {
|
||||
@@ -152,6 +158,8 @@ void JFJochImage::wheelEvent(QWheelEvent *event) {
|
||||
QPointF delta = targetScenePos - updatedViewportCenter;
|
||||
translate(delta.x(), delta.y()); // Shift the view
|
||||
|
||||
suppress_overlay_update_ = false;
|
||||
|
||||
updateOverlay();
|
||||
emitViewportChanged();
|
||||
}
|
||||
@@ -248,8 +256,12 @@ void JFJochImage::mouseMoveEvent(QMouseEvent *event) {
|
||||
const QPoint viewDelta = event->pos() - lastMousePos;
|
||||
lastMousePos = event->pos();
|
||||
|
||||
// Each setValue() reaches onScroll(), so the overlay was rebuilt three times per
|
||||
// mouse move. Suppress those and rebuild once, below.
|
||||
suppress_overlay_update_ = true;
|
||||
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - viewDelta.x());
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->value() - viewDelta.y());
|
||||
suppress_overlay_update_ = false;
|
||||
|
||||
updateOverlay();
|
||||
emitViewportChanged();
|
||||
@@ -760,6 +772,8 @@ void JFJochImage::RenderImage() {
|
||||
scanLine[x] = qRgb(c.r, c.g, c.b);
|
||||
}
|
||||
});
|
||||
|
||||
image_dirty_ = true;
|
||||
}
|
||||
|
||||
void JFJochImage::centerOnSpot(QPointF point) {
|
||||
@@ -779,9 +793,12 @@ void JFJochImage::applyViewport(QTransform transform, QPointF center) {
|
||||
if (m_applyingViewport || !scene())
|
||||
return;
|
||||
m_applyingViewport = true;
|
||||
// As in wheelEvent: one rebuild, not one per scrollbar move
|
||||
suppress_overlay_update_ = true;
|
||||
setTransform(transform);
|
||||
scale_factor = transform.m11();
|
||||
centerOn(center);
|
||||
suppress_overlay_update_ = false;
|
||||
updateOverlay();
|
||||
m_applyingViewport = false;
|
||||
}
|
||||
@@ -882,13 +899,17 @@ void JFJochImage::updateOverlay() {
|
||||
qDeleteAll(overlay_items_);
|
||||
overlay_items_.clear();
|
||||
|
||||
// Ensure the image item exists and is up-to-date
|
||||
// Ensure the image item exists and is up-to-date. Refreshing it marks the whole item
|
||||
// dirty, which forces a full repaint of the viewport, so only do it when the image
|
||||
// really changed - not on every pan and zoom.
|
||||
if (!image_item_) {
|
||||
image_item_ = new JFJochImageItem(qimg_buffer_);
|
||||
image_item_->setZValue(0);
|
||||
scene()->addItem(image_item_);
|
||||
} else {
|
||||
image_dirty_ = false;
|
||||
} else if (image_dirty_) {
|
||||
image_item_->refresh();
|
||||
image_dirty_ = false;
|
||||
}
|
||||
|
||||
if (scale_factor > 30.0)
|
||||
|
||||
@@ -124,6 +124,10 @@ protected:
|
||||
// instead of queueing a full recolour per event.
|
||||
void ScheduleRenderImage();
|
||||
bool render_pending_ = false;
|
||||
bool image_dirty_ = false; // qimg_buffer_ changed since the item was last refreshed
|
||||
// Set while a pan/zoom moves the scrollbars, so onScroll() does not rebuild the overlay
|
||||
// once per scrollbar; the gesture rebuilds it once itself.
|
||||
bool suppress_overlay_update_ = false;
|
||||
void Redraw();
|
||||
void CalcROI();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user