2016-11-18 10 views
1

Я создал предварительный просмотр, который отображает рендер. Я использовал функцию Image Viewer Example для масштабирования - поэтому у меня есть класс, наследующий QScrollArea, способный отображать изображение в QLabel и масштабирование/выключение/соответствие определенным ограничениям. Я показывал полосы прокрутки «по мере необходимости».Масштабирование и панорамирование изображения в QScrollArea

В качестве нового требования, я должен быть в состоянии сделать панорамирование и не показывают скроллбары.

Я искал способы сделать это - и нашел examples людей, которые используют мышь, перемещают и отпускают события, чтобы связать точку на изображении с полосами прокрутки.
проблема:
1) направление движения, если полосы прокрутки являются невидимыми, является неожиданной - в панорамировании он объект двигается в направлении мышей (остается под мышью), в то время как полосы прокрутки двигаться в противоположном направлении
2) Я думаю, что этот ход ограничен размером полосы прокрутки, поэтому ... если я посчитаю обратный ход, я бы ударил по стене, пока еще есть место для перемещения в одном направлении.
3) Это не сработало бы с увеличением, что происходит именно тогда, когда требуется панорамирование; потребуются более сложные вычисления.

я мог поочередно использовать QGraphicsView и

setDragMode(ScrollHandDrag); 

Это будет работать хорошо с масштабирования, а также, и я не должен был бы реализовать его самостоятельно.
Причина, по которой я еще не сделал этого, должен добавить QGraphicsScene, а также QGraphicsPixmapItem, содержащий изображение, которое я хочу, - затем найти, как отключить все события мыши, кроме панорамирования, и по-прежнему использовать QScrollArea. QGraphicsView;
Кажется, что слишком много накладных расходов (и это должно быть очень легким, для встроенного устройства с небольшой скоростью и памятью).

Что является лучшим вариантом? есть ли способ, которым я могу панорамировать увеличенное изображение в телезрителе, насколько это возможно?

ответ

2

Учитывая, что paintEvent реализация для пользовательских масштабируемой и pannable просмотра пиксельной карты длиной 5 строк, один мог бы также реализовать его с нуля:

// https://github.com/KubaO/stackoverflown/tree/master/questions/image-panzoom-40683840 
#include <QtWidgets> 
#include <QtNetwork> 

class ImageViewer : public QWidget { 
    QPixmap m_pixmap; 
    QRectF m_rect; 
    QPointF m_reference; 
    QPointF m_delta; 
    qreal m_scale = 1.0; 
    void paintEvent(QPaintEvent *) override { 
     QPainter p{this}; 
     p.translate(rect().center()); 
     p.scale(m_scale, m_scale); 
     p.translate(m_delta); 
     p.drawPixmap(m_rect.topLeft(), m_pixmap); 
    } 
    void mousePressEvent(QMouseEvent *event) override { 
     m_reference = event->pos(); 
     qApp->setOverrideCursor(Qt::ClosedHandCursor); 
     setMouseTracking(true); 
    } 
    void mouseMoveEvent(QMouseEvent *event) override { 
     m_delta += (event->pos() - m_reference) * 1.0/m_scale; 
     m_reference = event->pos(); 
     update(); 
    } 
    void mouseReleaseEvent(QMouseEvent *) override { 
     qApp->restoreOverrideCursor(); 
     setMouseTracking(false); 
    } 
public: 
    void setPixmap(const QPixmap &pix) { 
     m_pixmap = pix; 
     m_rect = m_pixmap.rect(); 
     m_rect.translate(-m_rect.center()); 
     update(); 
    } 
    void scale(qreal s) { 
     m_scale *= s; 
     update(); 
    } 
    QSize sizeHint() const override { return {400, 400}; } 
}; 

QGraphicsView Сопоставимые основанное виджет будет лишь немного короче, и было бы немного более накладными, если бы pixmap был очень маленьким. Для больших pixmaps время, потраченное на рендеринг pixmap, значительно затмевает любые издержки из-за оборудования QGraphicsScene/QGraphicsView. В конце концов, сама сцена является статической, и это идеальная рабочая точка для производительности QGraphicsView.

class SceneImageViewer : public QGraphicsView { 
    QGraphicsScene m_scene; 
    QGraphicsPixmapItem m_item; 
public: 
    SceneImageViewer() { 
     setScene(&m_scene); 
     m_scene.addItem(&m_item); 
     setDragMode(QGraphicsView::ScrollHandDrag); 
     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
     setResizeAnchor(QGraphicsView::AnchorViewCenter); 
    } 
    void setPixmap(const QPixmap &pixmap) { 
     m_item.setPixmap(pixmap); 
     auto offset = -QRectF(pixmap.rect()).center(); 
     m_item.setOffset(offset); 
     setSceneRect(offset.x()*4, offset.y()*4, -offset.x()*8, -offset.y()*8); 
     translate(1, 1); 
    } 
    void scale(qreal s) { QGraphicsView::scale(s, s); } 
    QSize sizeHint() const override { return {400, 400}; } 
}; 

И тест Жгут:

int main(int argc, char *argv[]) 
{ 
    QApplication a{argc, argv}; 
    QWidget ui; 
    QGridLayout layout{&ui}; 
    ImageViewer viewer1; 
    SceneImageViewer viewer2; 
    QPushButton zoomOut{"Zoom Out"}, zoomIn{"Zoom In"}; 
    layout.addWidget(&viewer1, 0, 0); 
    layout.addWidget(&viewer2, 0, 1); 
    layout.addWidget(&zoomOut, 1, 0, 1, 1, Qt::AlignLeft); 
    layout.addWidget(&zoomIn, 1, 1, 1, 1, Qt::AlignRight); 

    QNetworkAccessManager mgr; 
    QScopedPointer<QNetworkReply> rsp(
       mgr.get(QNetworkRequest({"http://i.imgur.com/ikwUmUV.jpg"}))); 
    QObject::connect(rsp.data(), &QNetworkReply::finished, [&]{ 
     if (rsp->error() == QNetworkReply::NoError) { 
      QPixmap pixmap; 
      pixmap.loadFromData(rsp->readAll()); 
      viewer1.setPixmap(pixmap); 
      viewer2.setPixmap(pixmap); 
     } 
     rsp.reset(); 
    }); 
    QObject::connect(&zoomIn, &QPushButton::clicked, [&]{ 
     viewer1.scale(1.1); viewer2.scale(1.1); 
    }); 
    QObject::connect(&zoomOut, &QPushButton::clicked, [&]{ 
     viewer1.scale(1.0/1.1); viewer2.scale(1.0/1.1); 
    }); 
    ui.show(); 
    return a.exec(); 
}