You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用两个QGraphicsView选择性显示同一QGraphicsScene的指定区域?

单QGraphicsScene配合双QGraphicsView实现全局预览+局部细节视图方案

完全可以基于单个QGraphicsScene实现需求,严格遵循MVC架构,无需额外创建多个场景。核心思路是通过自定义QGraphicsView子类,分别实现全局预览的小地图视图和仅渲染指定区域的局部视图,所有视图共享同一个场景模型,避免数据冗余。

实现步骤与代码示例

1. 局部视图(LocalView):仅渲染选中区域+支持缩放平移

自定义QGraphicsView子类,通过裁剪渲染区域实现仅显示选中部分,同时重写交互事件支持局部缩放和平移:

#include <QGraphicsView>
#include <QPaintEvent>
#include <QWheelEvent>
#include <QMouseEvent>

class LocalView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit LocalView(QWidget *parent = nullptr) : QGraphicsView(parent) {}

    // 设置要聚焦的场景区域
    void setFocusRect(const QRectF &rect) {
        m_focusRect = rect;
        fitInView(m_focusRect, Qt::KeepAspectRatio);
        update();
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        // 仅裁剪并渲染选中的场景区域
        QPainter painter(viewport());
        painter.setClipRect(mapFromScene(m_focusRect).boundingRect());
        QGraphicsView::paintEvent(event);
    }

    // 滚轮缩放:以鼠标位置为中心缩放局部区域
    void wheelEvent(QWheelEvent *event) override {
        const double scaleFactor = event->angleDelta().y() > 0 ? 1.15 : 1/1.15;
        scale(scaleFactor, scaleFactor);
        event->accept();
    }

    // 鼠标拖拽平移
    void mousePressEvent(QMouseEvent *event) override {
        if (event->button() == Qt::LeftButton) {
            m_lastMousePos = event->pos();
            setDragMode(QGraphicsView::ScrollHandDrag);
        }
        QGraphicsView::mousePressEvent(event);
    }

    void mouseMoveEvent(QMouseEvent *event) override {
        if (event->buttons() & Qt::LeftButton) {
            const QPoint delta = event->pos() - m_lastMousePos;
            translate(delta.x(), delta.y());
            m_lastMousePos = event->pos();
        }
        QGraphicsView::mouseMoveEvent(event);
    }

private:
    QRectF m_focusRect;
    QPoint m_lastMousePos;
};

2. 全局小地图视图(MiniMapView):显示完整图像+选中区域指示器

自定义QGraphicsView子类,始终显示完整场景,同时在视图层绘制选中区域的红色指示器,点击视图可更新选中区域:

#include <QGraphicsView>
#include <QPaintEvent>
#include <QMouseEvent>

class MiniMapView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit MiniMapView(QWidget *parent = nullptr) : QGraphicsView(parent) {
        // 隐藏滚动条,始终显示完整场景
        setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    }

    void setFocusRect(const QRectF &rect) {
        m_focusRect = rect;
        update();
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        QGraphicsView::paintEvent(event);
        // 在视图上叠加绘制选中区域指示器(不修改场景模型)
        QPainter painter(viewport());
        painter.setPen(QPen(Qt::red, 2));
        painter.setBrush(Qt::transparent);
        const QRectF viewRect = mapFromScene(m_focusRect).boundingRect();
        painter.drawRect(viewRect);
    }

    // 点击小地图更新选中区域(示例为固定大小的矩形,可按需调整)
    void mousePressEvent(QMouseEvent *event) override {
        const QPointF scenePos = mapToScene(event->pos());
        const QRectF newFocusRect(scenePos.x() - 50, scenePos.y() - 50, 100, 100);
        // 确保选中区域不超出场景边界
        emit focusRectChanged(newFocusRect.intersected(scene()->sceneRect()));
        QGraphicsView::mousePressEvent(event);
    }

signals:
    void focusRectChanged(const QRectF &rect);

private:
    QRectF m_focusRect;
};

3. 主窗口整合:绑定共享场景与视图

在主窗口中创建单个QGraphicsScene,同时绑定两个自定义视图,通过信号同步选中区域状态:

#include <QMainWindow>
#include <QHBoxLayout>
#include <QGraphicsScene>
#include <QPixmap>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
        // 创建共享场景与图像元素(模型层)
        QGraphicsScene *scene = new QGraphicsScene(this);
        const QPixmap pixmap("your_image_path.png");
        scene->addPixmap(pixmap);

        // 初始化小地图视图
        MiniMapView *miniMap = new MiniMapView(this);
        miniMap->setScene(scene);
        miniMap->setFixedSize(200, 200);
        miniMap->fitInView(scene->sceneRect(), Qt::KeepAspectRatio);

        // 初始化局部视图
        LocalView *localView = new LocalView(this);
        localView->setScene(scene);

        // 同步选中区域状态
        connect(miniMap, &MiniMapView::focusRectChanged, localView, &LocalView::setFocusRect);
        connect(miniMap, &MiniMapView::focusRectChanged, miniMap, &MiniMapView::setFocusRect);

        // 初始化默认选中区域(图像中心)
        const QRectF initRect(pixmap.width()/2 - 50, pixmap.height()/2 - 50, 100, 100);
        miniMap->setFocusRect(initRect);

        // 布局
        QHBoxLayout *layout = new QHBoxLayout();
        layout->addWidget(localView, 1);
        layout->addWidget(miniMap);
        QWidget *centralWidget = new QWidget(this);
        centralWidget->setLayout(layout);
        setCentralWidget(centralWidget);
    }
};

方案优势

  • 严格MVC架构:单个QGraphicsScene作为唯一模型,仅存储原始图像数据;两个QGraphicsView作为视图层,分别负责不同的展示逻辑,完全分离数据与视图。
  • 无数据冗余:无需创建多个场景拷贝,所有视图共享同一数据源,避免版本不一致问题。
  • 灵活扩展:可按需调整选中区域的大小、形状,或添加更多交互逻辑(如拖拽调整选中区域),均无需修改模型层。

内容的提问来源于stack exchange,提问作者Connor Spangler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:10:04