如何用两个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
相关产品推荐
相关产品推荐

