主页 > 其他  > 

QT:GraphicsView的坐标系介绍

QT:GraphicsView的坐标系介绍

在 Qt 的 Graphics View 框架中,存在三种不同的坐标系,分别是 物品坐标系(Item Coordinates)、场景坐标系(Scene Coordinates) 和 视图坐标系(View Coordinates)。这三种坐标系在图形的绘制、定位和交互中起着关键作用,

物品坐标系(Item Coordinates)

定义:物品坐标系是每个 QGraphicsItem 自身的本地坐标系。物品的位置、大小和形状都是基于这个坐标系来定义的。物品坐标系的原点通常位于物品的左上角(对于大多数标准图形项),X 轴向右为正,Y 轴向下为正。 特点: 物品在自身坐标系中的位置是相对固定的,不依赖于其在场景中的位置。 当对物品进行变换(如平移、旋转、缩放)时,这些变换都是在物品坐标系中进行的。

#include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QPainter> #include <QPen> #include <QFont> // 自定义可绘制坐标系的矩形图形项类 class CoordinateRectItem : public QGraphicsRectItem { public: CoordinateRectItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent = nullptr) : QGraphicsRectItem(x, y, width, height, parent) {} protected: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override { // 先调用基类的 paint 方法绘制矩形 QGraphicsRectItem::paint(painter, option, widget); // 设置画笔和字体 QPen pen(Qt::red); painter->setPen(pen); QFont font; font.setPointSize(8); painter->setFont(font); // 绘制 X 轴 painter->drawLine(rect().left(), rect().top(), rect().right(), rect().top()); // 绘制 X 轴刻度和标签 for (int i = 0; i <= rect().width(); i += 20) { painter->drawLine(rect().left() + i, rect().top(), rect().left() + i, rect().top() + 5); painter->drawText(rect().left() + i - 5, rect().top() - 5, QString::number(i)); } // 绘制 Y 轴 painter->drawLine(rect().left(), rect().top(), rect().left(), rect().bottom()); // 绘制 Y 轴刻度和标签 for (int i = 0; i <= rect().height(); i += 20) { painter->drawLine(rect().left(), rect().top() + i, rect().left() + 5, rect().top() + i); painter->drawText(rect().left() - 20, rect().top() + i + 5, QString::number(i)); } } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建场景 QGraphicsScene scene; // 创建不旋转的矩形图形项 CoordinateRectItem *nonRotatedRectItem = new CoordinateRectItem(0, 0, 100, 50); // 设置不旋转矩形的位置,避免与旋转矩形重叠 nonRotatedRectItem->setPos(20, 20); // 让 nonRotatedRectItem 也旋转 60 度 nonRotatedRectItem->setRotation(60); scene.addItem(nonRotatedRectItem); // 创建不旋转的矩形图形项 CoordinateRectItem *nonRotatedRectItem1 = new CoordinateRectItem(0, 0, 100, 50); // 设置不旋转矩形的位置,避免与旋转矩形重叠 nonRotatedRectItem1->setPos(20, 20); scene.addItem(nonRotatedRectItem1); // 创建视图 QGraphicsView view(&scene); view.setWindowTitle("Two Rotated Rectangles with Coordinates"); view.resize(400, 300); view.show(); return app.exec(); }

QApplication:用于管理 Qt 应用程序的资源和事件循环。 QGraphicsScene:表示一个图形场景,用于管理和组织 QGraphicsItem 对象。 QGraphicsView:用于显示 QGraphicsScene 中的内容。 QGraphicsRectItem:表示一个矩形图形项。 QPainter:用于在图形项上进行绘制操作。 QPen:用于设置绘制线条的属性,如颜色、宽度等。 QFont:用于设置绘制文本的字体属性。 CoordinateRectItem : 继承自 QGraphicsRectItem,重写了 paint 方法。 paint 方法的实现步骤如下: 调用基类的 paint 方法绘制矩形。 设置画笔颜色为红色,字体大小为 8 号。 绘制 X 轴和 Y 轴。 以 20 为间隔绘制 X 轴和 Y 轴的刻度,并在刻度旁边绘制对应的坐标值。 创建 QApplication 对象,启动应用程序的事件循环。 创建 QGraphicsScene 对象,用于管理图形项。 创建第一个 CoordinateRectItem 对象 nonRotatedRectItem,设置其位置为 (20, 20),并将其旋转 60 度,然后添加到场景中。 创建第二个 CoordinateRectItem 对象 nonRotatedRectItem1,设置其位置为 (20, 20),不进行旋转操作,直接添加到场景中。 创建 QGraphicsView 对象,关联场景,设置窗口标题和大小,最后显示视图。

在一个图形场景中展示两个矩形,其中一个矩形旋转了 60 度,并且每个矩形内部都绘制了物品坐标系的坐标轴、刻度和标签,方便用户观察矩形的旋转效果和物品坐标系的情况。

场景坐标系(Scene Coordinates)

定义:场景坐标系是整个 QGraphicsScene 的全局坐标系。场景中的所有物品都通过其在场景坐标系中的位置来定位。场景坐标系的原点通常位于场景的左上角,X 轴向右为正,Y 轴向下为正。 特点: 场景坐标系是物品坐标系和视图坐标系之间的桥梁,物品在场景中的位置可以通过其在场景坐标系中的坐标来确定。 场景可以包含多个物品,每个物品在场景坐标系中都有唯一的位置。

#include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QGraphicsTextItem> #include <QPainter> #include <QPen> #include <QFont> // 自定义用于绘制场景坐标系的图形项 class SceneCoordinateItem : public QGraphicsItem { public: SceneCoordinateItem(QGraphicsItem *parent = nullptr) : QGraphicsItem(parent) {} // 定义图形项的边界矩形 QRectF boundingRect() const override { // 这里简单设置一个较大的边界矩形,以覆盖可能的场景范围 return QRectF(-300, -300, 600, 600); } // 绘制场景坐标系 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override { Q_UNUSED(option); Q_UNUSED(widget); // 设置画笔 QPen pen(Qt::black); pen.setWidth(2); painter->setPen(pen); // 设置字体 QFont font; font.setPointSize(10); painter->setFont(font); // 绘制 X 轴 painter->drawLine(-1000, 0, 1000, 0); // 绘制 X 轴箭头 painter->drawLine(980, 10, 1000, 0); painter->drawLine(980, -10, 1000, 0); // 绘制 X 轴刻度和标签 for (int i = -1000; i <= 1000; i += 100) { painter->drawLine(i, -5, i, 5); QString label = QString::number(i); painter->drawText(i - 10, 20, label); } // 绘制 Y 轴 painter->drawLine(0, -1000, 0, 1000); // 绘制 Y 轴箭头 painter->drawLine(-10, 980, 0, 1000); painter->drawLine(10, 980, 0, 1000); // 绘制 Y 轴刻度和标签 for (int i = -1000; i <= 1000; i += 100) { painter->drawLine(-5, i, 5, i); QString label = QString::number(i); painter->drawText(-30, i + 5, label); } } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); QGraphicsScene scene; QGraphicsRectItem *originalRectItem = new QGraphicsRectItem(0, 0, 100, 50); QPointF originalPos = QPointF(50, 50); // 记录矩形的原始位置 originalRectItem->setPos(originalPos); scene.addItem(originalRectItem); // 为原始矩形添加标记 QGraphicsTextItem *originalLabel = new QGraphicsTextItem("Original"); originalLabel->setPos(originalPos.x(), originalPos.y() - 20); scene.addItem(originalLabel); // 创建旋转后的矩形 QGraphicsRectItem *rotatedRectItem = new QGraphicsRectItem(0, 0, 100, 50); // 以场景坐标系原点为中心旋转矩形 90 度 // 先将矩形移动到场景原点 rotatedRectItem->setPos(0, 0); rotatedRectItem->setRotation(90); // 计算旋转后的位置 QTransform transform; transform.rotate(90); QPointF newPos = transform.map(originalPos); rotatedRectItem->setPos(newPos); scene.addItem(rotatedRectItem); // 为旋转后的矩形添加标记 QGraphicsTextItem *rotatedLabel = new QGraphicsTextItem("Rotated"); rotatedLabel->setPos(newPos.x(), newPos.y() - 20); scene.addItem(rotatedLabel); // 创建并添加场景坐标系图形项 SceneCoordinateItem *coordinateItem = new SceneCoordinateItem(); scene.addItem(coordinateItem); QGraphicsView view(&scene); view.show(); return app.exec(); }

保留原始矩形: 创建 originalRectItem 表示原始矩形,并将其添加到场景中。 使用 QGraphicsTextItem 创建 originalLabel 作为原始矩形的标记,设置其位置在原始矩形上方,并添加到场景中。 创建旋转后的矩形: 创建 rotatedRectItem 作为旋转后的矩形。 对 rotatedRectItem 进行旋转操作,先将其移动到场景原点,旋转 90 度,再计算并设置旋转后的位置。 使用 QGraphicsTextItem 创建 rotatedLabel 作为旋转后矩形的标记,设置其位置在旋转后矩形上方,并添加到场景中。 绘制场景坐标系: 创建 SceneCoordinateItem 对象 coordinateItem 并添加到场景中,用于绘制场景坐标系。 显示视图: 创建 QGraphicsView 对象 view 并关联场景,最后显示视图。

视图坐标系(View Coordinates)

定义:视图坐标系是 QGraphicsView 窗口的坐标系。视图坐标系的原点位于视图窗口的左上角,X 轴向右为正,Y 轴向下为正。视图坐标系的单位是像素。 特点: 视图坐标系用于确定用户在视图窗口中看到的内容,它与场景坐标系之间通过视图的变换矩阵进行映射。 视图可以对场景进行缩放、平移、旋转等操作,这些操作会改变视图坐标系和场景坐标系之间的映射关系。

#include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QGraphicsTextItem> #include <QPainter> #include <QPen> #include <QFont> // 自定义用于绘制视图坐标系的图形项 class ViewCoordinateItem : public QGraphicsItem { public: ViewCoordinateItem(QGraphicsView* view, QGraphicsItem *parent = nullptr) : QGraphicsItem(parent), view(view) {} // 定义图形项的边界矩形 QRectF boundingRect() const override { // 根据视图大小设置边界矩形 QSize size = view->size(); return QRectF(0, 0, size.width(), size.height()); } // 绘制视图坐标系 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override { Q_UNUSED(option); Q_UNUSED(widget); // 设置画笔 QPen pen(Qt::red); pen.setWidth(2); painter->setPen(pen); // 设置字体 QFont font; font.setPointSize(10); painter->setFont(font); // 获取视图大小 QSize size = view->size(); // 绘制 X 轴 painter->drawLine(0, size.height() / 2, size.width(), size.height() / 2); // 绘制 X 轴箭头 painter->drawLine(size.width() - 20, size.height() / 2 - 10, size.width(), size.height() / 2); painter->drawLine(size.width() - 20, size.height() / 2 + 10, size.width(), size.height() / 2); // 绘制 X 轴刻度和标签 for (int i = 0; i <= size.width(); i += 50) { painter->drawLine(i, size.height() / 2 - 5, i, size.height() / 2 + 5); QString label = QString::number(i); painter->drawText(i - 10, size.height() / 2 + 20, label); } // 绘制 Y 轴 painter->drawLine(size.width() / 2, 0, size.width() / 2, size.height()); // 绘制 Y 轴箭头 painter->drawLine(size.width() / 2 - 10, size.height() - 20, size.width() / 2, size.height()); painter->drawLine(size.width() / 2 + 10, size.height() - 20, size.width() / 2, size.height()); // 绘制 Y 轴刻度和标签 for (int i = 0; i <= size.height(); i += 50) { painter->drawLine(size.width() / 2 - 5, i, size.width() / 2 + 5, i); QString label = QString::number(i); painter->drawText(size.width() / 2 - 30, i + 5, label); } } private: QGraphicsView* view; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); QGraphicsScene scene; // 设置场景范围小于视图,例如设置场景大小为 300x500 scene.setSceneRect(0, 0, 300, 500); // 创建原始矩形框 QGraphicsRectItem *originalRectItem = new QGraphicsRectItem(10, 10, 100, 50); originalRectItem->setPos(50, 50); scene.addItem(originalRectItem); // 为原始矩形框添加标记 QGraphicsTextItem *originalLabel = new QGraphicsTextItem("Original Rect"); originalLabel->setPos(originalRectItem->pos().x(), originalRectItem->pos().y() - 20); scene.addItem(originalLabel); // 创建平移后的矩形框 QGraphicsRectItem *translatedRectItem = new QGraphicsRectItem(10, 10, 100, 50); // 将矩形框向左平移 120 个单位 translatedRectItem->setPos(50 - 120, 50); scene.addItem(translatedRectItem); // 为平移后的矩形框添加标记 QGraphicsTextItem *translatedLabel = new QGraphicsTextItem("Translated Rect"); translatedLabel->setPos(translatedRectItem->pos().x(), translatedRectItem->pos().y() - 20); scene.addItem(translatedLabel); QGraphicsView view(&scene); // 对视图进行缩放操作 view.scale(2.0, 2.0); // 创建并添加视图坐标系图形项 ViewCoordinateItem *coordinateItem = new ViewCoordinateItem(&view); scene.addItem(coordinateItem); view.resize(400, 600); view.show(); return app.exec(); }

坐标系之间的转换

在 Graphics View 框架中,可以使用以下方法进行坐标系之间的转换: 物品坐标系和场景坐标系之间的转换: QGraphicsItem::mapToScene(const QPointF &point):将物品坐标系中的点转换为场景坐标系中的点。 QGraphicsItem::mapFromScene(const QPointF &point):将场景坐标系中的点转换为物品坐标系中的点。 场景坐标系和视图坐标系之间的转换: QGraphicsView::mapToScene(const QPoint &point):将视图坐标系中的点转换为场景坐标系中的点。 QGraphicsView::mapFromScene(const QPointF &point):将场景坐标系中的点转换为视图坐标系中的点。

QGraphicsItem::mapToScene #include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QGraphicsTextItem> #include <QDebug> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建场景 QGraphicsScene scene; // 创建一个矩形图形项 QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 50); // 设置矩形在场景中的位置 rectItem->setPos(50, 50); scene.addItem(rectItem); // 在物品坐标系中定义一个点 QPointF itemPoint(20, 30); // 将物品坐标系中的点转换为场景坐标系中的点 QPointF scenePoint = rectItem->mapToScene(itemPoint); // 输出转换后的场景坐标 qDebug() << "Item Coordinate: (" << itemPoint.x() << ", " << itemPoint.y() << ")"; qDebug() << "Scene Coordinate: (" << scenePoint.x() << ", " << scenePoint.y() << ")"; // 创建一个文本图形项来显示场景坐标 QGraphicsTextItem *textItem = new QGraphicsTextItem(QString("Scene Point: (%1, %2)").arg(scenePoint.x()).arg(scenePoint.y())); textItem->setPos(scenePoint); scene.addItem(textItem); // 创建视图 QGraphicsView view(&scene); view.show(); return app.exec(); }

QGraphicsItem::mapFromScene #include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QGraphicsTextItem> #include <QDebug> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建场景 QGraphicsScene scene; // 创建一个矩形图形项 QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 50); // 设置矩形在场景中的位置 rectItem->setPos(50, 50); scene.addItem(rectItem); // 在场景坐标系中定义一个点 QPointF scenePoint(80, 70); // 将场景坐标系中的点转换为物品坐标系中的点 QPointF itemPoint = rectItem->mapFromScene(scenePoint); // 输出转换后的物品坐标 qDebug() << "Scene Coordinate: (" << scenePoint.x() << ", " << scenePoint.y() << ")"; qDebug() << "Item Coordinate: (" << itemPoint.x() << ", " << itemPoint.y() << ")"; // 创建一个文本图形项来显示物品坐标,并将矩形作为其父项 QGraphicsTextItem *textItem = new QGraphicsTextItem(QString("Item Point: (%1, %2)").arg(itemPoint.x()).arg(itemPoint.y()), rectItem); textItem->setPos(itemPoint); // 创建视图 QGraphicsView view(&scene); view.show(); return app.exec(); }

QGraphicsView::mapToScene #include <QApplication> #include <QGraphicsView> #include <QGraphicsScene> #include <QMouseEvent> #include <QDebug> // 自定义的 QGraphicsView 类,用于处理鼠标点击事件 class CustomGraphicsView : public QGraphicsView { public: CustomGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr) : QGraphicsView(scene, parent) {} protected: // 重写鼠标按下事件处理函数 void mousePressEvent(QMouseEvent *event) override { // 获取鼠标在视图中的位置 QPoint viewPos = event->pos(); // 使用 mapToScene 函数将视图坐标转换为场景坐标 QPointF scenePos = mapToScene(viewPos); qDebug() << "View Position: " << viewPos; qDebug() << "Scene Position: " << scenePos; QGraphicsView::mousePressEvent(event); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); // 创建一个 QGraphicsScene QGraphicsScene scene; // 在场景中添加一个矩形,方便可视化 scene.addRect(10, 10, 200, 200); // 创建自定义的 QGraphicsView,并将场景设置给它 CustomGraphicsView view(&scene); view.setScene(&scene); view.resize(500,500); view.show(); return a.exec(); }

#include :引入 QApplication 类,它是 Qt 应用程序的核心类,负责管理应用程序的资源和事件循环,每个 Qt GUI 应用程序都必须有且仅有一个 QApplication 对象。 #include :引入 QGraphicsView 类,它是一个用于显示 QGraphicsScene 内容的部件,提供了视图的滚动、缩放等功能。 #include :引入 QGraphicsScene 类,它是一个用于管理和组织图形项(如矩形、椭圆等)的容器,提供了图形项的添加、删除、查找等操作。 #include :引入 QMouseEvent 类,它用于处理鼠标事件,例如鼠标按下、释放、移动等。 #include :引入 QDebug 类,它用于在调试时输出信息,方便开发者查看程序的运行状态。 class CustomGraphicsView : public QGraphicsView 表示 CustomGraphicsView 类继承自 QGraphicsView 类,这样 CustomGraphicsView 就拥有了 QGraphicsView 的所有功能,并且可以对其进行扩展。

void mousePressEvent(QMouseEvent *event) override 重写了 QGraphicsView 的 mousePressEvent 函数,用于处理鼠标按下事件。 QPoint viewPos = event->pos(); 获取鼠标在视图中的位置,event->pos() 返回一个 QPoint 对象,表示鼠标相对于视图窗口的坐标。 QPointF scenePos = mapToScene(viewPos); 使用 mapToScene 函数将视图坐标转换为场景坐标,mapToScene 是 QGraphicsView 提供的一个成员函数,用于将视图坐标系中的点映射到场景坐标系中。 qDebug() << "View Position: " << viewPos; 和 qDebug() << "Scene Position: " << scenePos; 使用 qDebug 输出鼠标在视图和场景中的坐标,方便调试。 QGraphicsView::mousePressEvent(event); 调用基类的 mousePressEvent 函数,确保基类的默认处理逻辑也能正常执行

QApplication a(argc, argv); 创建一个 QApplication 对象,用于管理应用程序的资源和事件循环。 QGraphicsScene scene; 创建一个 QGraphicsScene 对象,用于管理图形项。 scene.addRect(10, 10, 200, 200); 在场景中添加一个矩形,矩形的左上角坐标为 (10, 10),宽度为 200,高度为 200,这样可以方便我们可视化场景的内容。 CustomGraphicsView view(&scene); 创建一个 CustomGraphicsView 对象,并将之前创建的 QGraphicsScene 对象的指针传递给它。 view.setScene(&scene); 将 QGraphicsScene 对象设置给 CustomGraphicsView,这样 CustomGraphicsView 就可以显示 QGraphicsScene 中的内容。 view.resize(500,500); 将 CustomGraphicsView 的大小调整为 500x500 像素。 view.show(); 显示 CustomGraphicsView 窗口。 return a.exec(); 启动应用程序的事件循环,程序会一直运行,直到用户关闭窗口或调用 QApplication::quit() 函数。

创建一个带有自定义鼠标点击事件处理的 QGraphicsView 窗口,显示一个 QGraphicsScene 中的矩形,并在鼠标点击时输出鼠标在视图和场景中的坐标。

QGraphicsView::mapFromScene

函数用于将场景坐标系中的点映射到视图坐标系中。

自定义 CustomGraphicsView 类 继承 QGraphicsView:通过继承 QGraphicsView 类,并重写 mouseMoveEvent 函数来处理鼠标移动事件。 mouseMoveEvent 函数: QPoint viewPos = event->pos();:获取鼠标在视图中的原始位置。 QPointF scenePos = mapToScene(viewPos);:使用 mapToScene 函数将视图坐标转换为场景坐标。 QPoint convertedViewPos = mapFromScene(scenePos);:使用 mapFromScene 函数将场景坐标转换回视图坐标。 使用 qDebug 输出原始视图坐标、场景坐标以及转换后的视图坐标,方便调试查看。 2. main 函数 创建 QApplication 对象,用于管理应用程序的事件循环。 创建 QGraphicsScene 对象,并添加一个矩形到场景中,方便可视化。 创建 CustomGraphicsView 对象,将场景设置给它,并调整大小和显示。 view.setMouseTracking(true);:启用鼠标跟踪,这样即使鼠标按钮未按下,移动鼠标时也会触发 mouseMoveEvent 函数。

#include <QApplication> #include <QGraphicsView> #include <QGraphicsScene> #include <QMouseEvent> #include <QDebug> // 自定义的 QGraphicsView 类,用于处理鼠标移动事件 class CustomGraphicsView : public QGraphicsView { public: CustomGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr) : QGraphicsView(scene, parent) {} protected: // 重写鼠标移动事件处理函数 void mouseMoveEvent(QMouseEvent *event) override { // 获取鼠标在视图中的位置 QPoint viewPos = event->pos(); // 使用 mapToScene 函数将视图坐标转换为场景坐标 QPointF scenePos = mapToScene(viewPos); // 使用 mapFromScene 函数将场景坐标转换回视图坐标 QPoint convertedViewPos = mapFromScene(scenePos); qDebug() << "Original View Position: " << viewPos; qDebug() << "Scene Position: " << scenePos; qDebug() << "Converted View Position: " << convertedViewPos; QGraphicsView::mouseMoveEvent(event); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); // 创建一个 QGraphicsScene QGraphicsScene scene; // 在场景中添加一个矩形,方便可视化 scene.addRect(10, 10, 200, 200); // 创建自定义的 QGraphicsView,并将场景设置给它 CustomGraphicsView view(&scene); view.setScene(&scene); view.resize(500, 500); view.show(); // 启用鼠标跟踪,这样才能触发 mouseMoveEvent view.setMouseTracking(true); return a.exec(); }

使用 Qt 编译器进行编译和运行。运行程序后,当你移动鼠标时,控制台会输出鼠标在视图和场景中的坐标,以及从场景坐标转换回的视图坐标。

标签:

QT:GraphicsView的坐标系介绍由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“QT:GraphicsView的坐标系介绍