diff --git a/viewer/image_viewer/JFJochImage.cpp b/viewer/image_viewer/JFJochImage.cpp index f1452e44..1f7a9479 100644 --- a/viewer/image_viewer/JFJochImage.cpp +++ b/viewer/image_viewer/JFJochImage.cpp @@ -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) diff --git a/viewer/image_viewer/JFJochImage.h b/viewer/image_viewer/JFJochImage.h index 623f8125..7bf2f6e3 100644 --- a/viewer/image_viewer/JFJochImage.h +++ b/viewer/image_viewer/JFJochImage.h @@ -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();