【问题标题】:Zooming and panning an image in a QScrollArea在 QScrollArea 中缩放和平移图像
【发布时间】:2017-04-02 16:53:12
【问题描述】:

我创建了一个显示渲染图像的预览。我使用Image Viewer Example 进行缩放功能 - 所以我有一个继承QScrollArea 的类,能够在QLabel 中显示图像,并放大/缩小/适应特定限制。我正在“根据需要”显示滚动条。

作为一项新要求,我必须能够平移,并且不显示滚动条

我一直在寻找方法 - 并发现 examples 的人使用鼠标按下、移动和释放事件将图像上的点与滚动条相关联。
问题:
1) 如果滚动条不可见,则移动方向是出乎意料的 - 在平移时,对象沿鼠标方向移动(停留在鼠标下方),而滚动条沿相反方向移动
2)我认为移动仅限于滚动条大小,所以......如果我计算反向移动,我会撞到墙,同时仍有空间向一个方向移动
3)这不适用于缩放,这正是需要平移的时候;需要更复杂的计算。

我可以交替使用QGraphicsView

setDragMode(ScrollHandDrag);

它也适用于缩放,我不必自己实现它。
我还没有这样做的原因是,我还需要添加一个QGraphicsScene,以及一个包含我想要的图像的QGraphicsPixmapItem——然后找到如何禁用除平移之外的所有鼠标事件——并且仍然使用@ 987654329@持有QGraphicsView;
似乎开销太大(对于速度和内存很小的嵌入式设备,这意味着非常轻量级)。

什么是最好的选择?有什么方法可以在查看器中平移缩放的图像,尽可能轻吗?

【问题讨论】:

    标签: qt zooming panning qscrollarea


    【解决方案1】:

    鉴于自定义可缩放和可平移像素图查看器的 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 的小部件只会稍短一些,并且如果像素图非常小,则会产生更多开销。对于大型像素图,由于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();
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-19
      • 2016-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-10
      • 2023-03-11
      相关资源
      最近更新 更多