2016-11-18 10 views
1

レンダリングされた画像を表示するプレビューを作成しました。ズーム機能にはImage Viewer Exampleを使用しました。QScrollAreaを継承するクラスがあり、QLabelに画像を表示したり、特定の範囲でズームイン/アウト/フィットしたりすることができます。私は必要に応じてスクロールバーを表示していました。新しい要件としてQScrollAreaで画像を拡大/パンする

、私はをパンを行うことができなければならない、とは、スクロールバーを示していません。

私はそれを行う方法を探していました - そして、マウスのプレス、動き、およびリリースのイベントを使用している人々のexamplesが画像上の点をスクロールバーに関連付けることを発見しました。
問題:スクロールバーが見えない場合
1)移動の方向は、予想外である - 彼はマウスの方向にマウスの下(ステー)移動オブジェクトパニングに、スクロールバーが反対方向に移動しながら
2)私は動きがスクロールバーのサイズに制限されていると思うので...私は逆の動きを計算すると、私はまだ一方向に移動する余地がある間に壁を打つだろう
3)これは正確にパンニングが必要です。より複雑な計算が必要になります。

私は交互QGraphicsViewを使用することができ、かつ

setDragMode(ScrollHandDrag); 

それだけでなく、ズームで素敵な仕事だろう、と私はそれを自分自身を実装する必要はありません。
私がまだこれをしていないのは、QGraphicsSceneも追加する必要があります。QGraphicsPixmapItemには画像があります。次に、パン以外のすべてのマウスイベントを無効にする方法を見つけて、まだQScrollAreaQGraphicsView;
オーバーヘッドがあまりにも大きいようです(速度とメモリの少ない組み込みデバイスの場合、これは非常に軽量であることを意味します)。

最適なオプションは何ですか?できるだけ軽量で、ビューアーで拡大した画像をパンすることができる方法はありますか?

答えて

2

カスタムズーム可能とパン可能ピックスマップビューアのpaintEvent実装は5行の長さであることを考えると、1は同様に、最初からそれを実装するかもしれません:

// 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ベースのウィジェットがわずかに短くなり、ピクスマップが非常に小さかった場合、少しオーバーヘッドがあります。大きなピクスマップの場合、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(); 
}