Qt/C++面试【速通笔记九】—视图框架机制

在Qt中,QGraphicsViewQGraphicsScene是用于构建二维图形界面的核心组件。它们的设计使得开发者能够高效地管理和渲染图形项,支持丰富的用户交互,例如缩放、旋转、平移等。


1. QGraphicsScene和QGraphicsView的基本概念

QGraphicsScene

QGraphicsScene 是Qt中的图形场景类,它负责管理所有的图形项(即QGraphicsItem)。场景本身定义了一个坐标系统(场景坐标),用于描述所有图形项的位置、大小、状态等。可以理解为图形项的容器,所有图形项都可以添加到场景中。

QGraphicsView

QGraphicsView 是一个视图窗口,它通过渲染QGraphicsScene中的图形项将场景的内容显示到屏幕上。它提供了缩放、旋转、平移等功能,能够让用户与图形项进行交互。QGraphicsView将场景坐标转换为视图坐标,从而影响图形项在屏幕上的显示位置。


2. QGraphicsView框架的主要组件

  • QGraphicsScene:用于管理和存储图形项(如矩形、线条、图片等)。
  • QGraphicsItem:图形项,是场景中的具体内容,可以是任何可视化元素,如矩形、圆形、图片等。
  • QGraphicsView :用于显示QGraphicsScene,并为用户提供交互功能。

3. 坐标系统与坐标转换

QGraphicsView框架中,有三个常见的坐标系统:

  1. 场景坐标(Scene Coordinates):这是场景中的全局坐标系统,所有图形项的位置和大小都通过场景坐标来定义。
  2. 视图坐标(View Coordinates):这是视图窗口的局部坐标系统,表示图形项在屏幕上的显示位置。由于视图支持缩放、平移等操作,视图坐标会随着这些变换而变化。
  3. 项坐标(Item Coordinates):这是图形项内部的局部坐标系统,描述图形项内部元素的位置。例如,矩形项的左上角坐标。
坐标转换

Qt提供了几种方法来进行坐标系统之间的转换。通过这些转换,您可以方便地在不同坐标系统之间进行转换,确保图形项、场景和视图的协调。

从场景坐标到视图坐标

假设您有一个场景坐标scenePoint,可以使用QGraphicsView::mapFromScene()方法将其转换为视图坐标:

cpp 复制代码
QPointF scenePoint(50, 50);  // 场景中的点
QPointF viewPoint = view.mapFromScene(scenePoint);  // 转换为视图坐标
从视图坐标到场景坐标

如果您有一个视图坐标viewPoint,可以使用QGraphicsView::mapToScene()方法将其转换为场景坐标:

cpp 复制代码
QPointF viewPoint(200, 150);  // 视图中的点
QPointF scenePoint = view.mapToScene(viewPoint);  // 转换为场景坐标
从项坐标到场景坐标

对于图形项,假设您有一个局部坐标localPoint,可以使用QGraphicsItem::mapToScene()方法将其转换为场景坐标:

cpp 复制代码
QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 100);
QPointF localPoint(20, 20);  // 项坐标
QPointF scenePoint = rectItem->mapToScene(localPoint);  // 转换为场景坐标
从场景坐标到项坐标

如果您有场景坐标scenePoint,并且希望知道它相对于某个图形项的位置,可以使用QGraphicsItem::mapFromScene()方法:

cpp 复制代码
QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 100);
QPointF scenePoint(50, 50);  // 场景坐标
QPointF localPoint = rectItem->mapFromScene(scenePoint);  // 转换为项坐标

4. QGraphicsView的交互功能

QGraphicsView不仅用于显示场景,还提供了多种交互功能,例如缩放、平移、旋转等。这些功能可以大大增强用户体验,让应用程序更具交互性。

视图缩放

通过鼠标滚轮事件或者键盘快捷键,您可以实现视图的缩放。例如,可以使用scale()方法来缩放视图:

cpp 复制代码
view.scale(1.2, 1.2);  // 放大视图
view.scale(0.8, 0.8);  // 缩小视图
视图平移

可以使用translate()方法平移视图的内容:

cpp 复制代码
view.translate(50, 50);  // 将视图内容平移50个像素
视图旋转

QGraphicsView还支持视图的旋转操作:

cpp 复制代码
view.rotate(45);  // 旋转视图45度

5. 完整示例:QGraphicsView的使用

下面是一个完整的Qt示例,展示了如何创建一个QGraphicsSceneQGraphicsView,并实现一些基本功能,如坐标转换、鼠标点击事件、缩放等:

cpp 复制代码
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QMouseEvent>
#include <QDebug>

class MyView : public QGraphicsView {
public:
    MyView(QGraphicsScene *scene) : QGraphicsView(scene) {
        setRenderHint(QPainter::Antialiasing);
        setRenderHint(QPainter::SmoothPixmapTransform);
    }

protected:
    void mousePressEvent(QMouseEvent *event) override {
        QPointF viewPoint = event->pos();  // 获取视图坐标
        QPointF scenePoint = mapToScene(viewPoint);  // 转换为场景坐标
        qDebug() << "Mouse clicked at view point:" << viewPoint << ", scene point:" << scenePoint;
    }

    void wheelEvent(QWheelEvent *event) override {
        if (event->angleDelta().y() > 0) {
            scale(1.2, 1.2);  // 放大
        } else {
            scale(0.8, 0.8);  // 缩小
        }
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QGraphicsScene scene;
    QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 100);
    rectItem->setBrush(Qt::blue);  // 设置矩形颜色为蓝色
    scene.addItem(rectItem);

    MyView view(&scene);  // 使用自定义视图类
    view.show();

    return app.exec();
}

6. QGraphicsView常用函数一览

在使用QGraphicsView时,您将会用到一些常见的函数。下面是一些QGraphicsView类的主要函数及其功能:

分组 函数 功能描述
场景 void setScene() 设置关联显示的场景
void setSceneRect() 设置场景在视图中可见的部分的矩形区域
void setAlignment() 设置场景在视图中的对齐方式,缺省是上左对齐
外观 void setBackgroundBrush() 设置场景的背景画刷
void setForegroundBrush() 设置场景的前景画刷
void setRenderHints() 设置视图的绘制选项
交互 void setInteractive() 是否允许场景可交互,如果禁用交互,则任何键盘盘或鼠标操作都被忽略
QRect rubberBandRect() 返回选择矩形框区域
void setRubberBandSelectionMode() 选择模式,参数为枚举类型Qt::ItemSelectionMode
坐标 QPoint mapFromScene() 将场景中的点转换为视图中的坐标
QPointF mapToScene() 将视图中的点转换为场景中的坐标

相关推荐
DjangoJason1 小时前
C++ 仿RabbitMQ实现消息队列项目
开发语言·c++·rabbitmq
oe10192 小时前
读From GPT-2 to gpt-oss: Analyzing the Architectural Advances(续)
笔记·gpt·学习
奇树谦3 小时前
QT|windwos桌面端应用程序开发,当连接多个显示器的时候,如何获取屏幕编号?
开发语言·qt
weixin_307779133 小时前
VS Code配置MinGW64编译GNU 科学库 (GSL)
开发语言·c++·vscode·算法
Include everything5 小时前
Rust学习笔记(三)|所有权机制 Ownership
笔记·学习·rust
蒋星熠5 小时前
C++零拷贝网络编程实战:从理论到生产环境的性能优化之路
网络·c++·人工智能·深度学习·性能优化·系统架构
CHANG_THE_WORLD5 小时前
# C++ 中的 `string_view` 和 `span`:现代安全视图指南
开发语言·c++
雨落倾城夏未凉5 小时前
9.c++new申请二维数组
c++·后端
Franklin6 小时前
Python界面设计【QT-creator基础编程 - 01】如何让不同分辨率图像自动匹配graphicsView的窗口大小
开发语言·python·qt
雨落倾城夏未凉6 小时前
8.被free回收的内存是立即返还给操作系统吗?为什么?
c++·后端