2016-11-18 217 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(); 
}