2016-11-18 169 views
1

我創建了一個顯示渲染圖像的預覽。我使用Image Viewer Example來縮放功能 - 所以我有一個繼承QScrollArea的類,能夠在QLabel中顯示圖像,並且可以放大/縮小/適合特定的限制。我正在根據需要顯示滾動條。縮放和平移QScrollArea中的圖像

作爲一個新的要求,我一定能夠做到平移,並不顯示滾動條

我一直在尋找方法 - 並找到examples使用鼠標按下,移動和釋放事件以將圖像上的點與滾動條相關聯的人。
的問題是:
1)移動的方向,如果滾動條是不可見的,是意想不到的 - 在搖攝他物體移動在小鼠的指導下鼠標(停留),而滾動條在相反的方向上移動
2)我認爲這一舉措僅限於滾動條的大小,所以......如果我計算一個相反的舉動,我會撞牆,同時還有空間向一個方向移動。
3)這不適用於縮放,這正好是平移是必要的;需要更復雜的計算。

我可以交替使用QGraphicsView,並

setDragMode(ScrollHandDrag); 

它的工作與縮放以及不錯的,我就不會來實現它自己。
我還沒有這樣做的原因是,我需要添加一個QGraphicsScene以及一個包含我想要的圖像的QGraphicsPixmapItem - 然後找到如何禁用除平移之外的所有鼠標事件 - 並仍然使用QScrollArea來保存QGraphicsView;
它看起來太多了開銷(這對於速度和內存很小的嵌入式設備來說意味着非常輕便)。

什麼是最佳選擇?有沒有什麼方法可以在瀏覽器中縮放縮放的圖像,儘可能輕?

回答

2

鑑於paintEvent實現自定義縮放和可平移像素映射觀衆是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基於插件將僅略短,如果像素圖非常小,會有更多的開銷。對於大型像素圖,渲染像素圖所耗費的時間極大地掩蓋了由於機器而造成的任何開銷。畢竟,場景本身是靜態的,這是性能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(); 
}