QT中Graphics View程序基本结构和功能实现
功能介绍
程序参考《Qt5.9 C++开发指南》实现,有部分类名、变量名进行重命名。添加了场景坐标轴的绘制,为了更好体会视图坐标、场景坐标、绘图项坐标.
QPainter不能实现图件的选择、编辑、拖放、修改等功能
- QGraphicScene(场景):可以管理多个图形项
- QGraphicItems(图形项): 也就是图元,支持鼠标的事件响应
- QGraphicView(视图):关联场景可以让场景中的所有图形项可视化
代码实现
继承QGraphicsView实现自定义MyGraphicsView
实现了mouseMoveEvent()事件和mousePressEvent()事件,并把鼠标事件转换为信号,这样可以在主程序设计槽响应这些鼠标事件
MyGraphicsView.h代码实现
#pragma once
#include <QGraphicsView>
#include <QMouseEvent>
class MyGraphicsView :public QGraphicsView
{
Q_OBJECT
public:
MyGraphicsView(QWidget* parent = 0);
protected:
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* evment);
signals:
void mouseMovePoint(QPoint point);//自定义MouseMove信号
void mouseClicked(QPoint point);//自定义MouseClicked信号
};
MyGraphicsView.cpp代码实现
#include "MyGraphicsView.h"
MyGraphicsView::MyGraphicsView(QWidget* parent) :QGraphicsView(parent)
{
}
/*
此事件相应代码里,通过事件的pos()函数获取鼠标光标在视图中的坐标point
然后作为参数发射mouseMovePoint(point)信号.这样若在其它地方编写槽函数与此信号关联,就可以对鼠标移动事件做出响应
*/
void MyGraphicsView::mouseMoveEvent(QMouseEvent* event)
{
//鼠标移动事件
QPoint point = event->pos();//QGraphicsView的坐标
emit mouseMovePoint(point);//发射信号
QGraphicsView::mouseMoveEvent(event);
}
/*
此事件响应代码里,首先判断是否是鼠标左键按下,然后通过事件的pos()函数获取鼠标光标在视图中的坐标point
然后作为参数发射mouseClicked(point)信号
*/
void MyGraphicsView::mousePressEvent(QMouseEvent* event)
{
//鼠标左键按下事件
if (event->button() == Qt::LeftButton)
{
QPoint point = event->pos();//QGraphicsView的坐标
emit mouseClicked(point);//发射信号
}
QGraphicsView::mousePressEvent(event);
}
继承QGraphicsLineItem实现自定义ArrowLineItem带箭头直线用于后面的画坐标轴
ArrowLineItem.h代码实现
#ifndef ARROWLINEITEM_H
#define ARROWLINEITEM_H
#include <QGraphicsLineItem>
#include <QPen>
class ArrowLineItem : public QGraphicsLineItem
{
public:
ArrowLineItem(const QLineF& line, QGraphicsItem* parent = nullptr);
ArrowLineItem(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem* parent = nullptr);
void setArrowSize(qreal size) { m_arrowSize = size; update(); }
qreal arrowSize() const { return m_arrowSize; }
void setFillArrow(bool fill) { m_fillArrow = fill; update(); }
bool fillArrow() const { return m_fillArrow; }
protected:
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
private:
qreal m_arrowSize;
bool m_fillArrow;
};
#endif // ARROWLINEITEM_H
ArrowLineItem.cpp代码实现
#include "arrowlineitem.h"
#include <QPainter>
#include <QtMath>
ArrowLineItem::ArrowLineItem(const QLineF& line, QGraphicsItem* parent)
: QGraphicsLineItem(line, parent), m_arrowSize(10), m_fillArrow(true)
{
}
ArrowLineItem::ArrowLineItem(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem* parent)
: QGraphicsLineItem(x1, y1, x2, y2, parent), m_arrowSize(10), m_fillArrow(true)
{
}
void ArrowLineItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
// 绘制主线
painter->setPen(pen());
painter->drawLine(line());
// 计算箭头方向角度
QLineF line = this->line();
double angle = qAtan2(line.dy(), line.dx());
// 计算箭头的两个侧边点
QPointF arrowP1 = line.p2() - QPointF(
qCos(angle - M_PI / 6) * m_arrowSize,
qSin(angle - M_PI / 6) * m_arrowSize
);
QPointF arrowP2 = line.p2() - QPointF(
qCos(angle + M_PI / 6) * m_arrowSize,
qSin(angle + M_PI / 6) * m_arrowSize
);
// 创建箭头三角形
QPolygonF arrowHead;
arrowHead << line.p2() << arrowP1 << arrowP2;
// 绘制箭头
if (m_fillArrow) {
// 填充箭头
QBrush originalBrush = painter->brush();
painter->setBrush(painter->pen().color());
painter->drawPolygon(arrowHead);
painter->setBrush(originalBrush);
}
else {
// 只绘制轮廓
painter->drawPolygon(arrowHead);
}
}
继承自QMainWindow的MainWindow
MainWindow.h代码实现
#pragma once
#include <QtWidgets/QMainWindow>
#include <QGraphicsScene>
#include <QLabel>
#include "MyGraphicsView.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void resizeEvent(QResizeEvent* event);//窗口改变事件
private slots:
void on_mouseMovePoint(QPoint point);
void on_mouseClicked(QPoint point);
private:
void iniGraphicsSystem();//初始化场景信息
void drawSceneCooridate(QGraphicsScene* scene);//绘制Scene的坐标系
MyGraphicsView* m_graphView;
QGraphicsScene* m_scene;
QLabel* labViewCord;//用于显示视图坐标
QLabel* labSceneCord;//用于显示场景坐标
QLabel* labItemCord;//用于显示图形项的局部坐标
};
MainWindow.cpp代码实现
#include "MainWindow.h"
#include <QGraphicsItem>
#include <QPen>
#include <QObject>
#include <qmath.h>
#include <QStatusBar>
#include "ArrowLineItem.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{ //指定MyGraphicsView对象为MainWindow的CentralWidget
m_graphView = new MyGraphicsView();
this->setCentralWidget(m_graphView);
labViewCord = new QLabel("View 坐标:");
labViewCord->setMinimumWidth(150);
this->statusBar()->addWidget(labViewCord);
labSceneCord = new QLabel("Scene 坐标:");
labSceneCord->setMinimumWidth(150);
this->statusBar()->addWidget(labSceneCord);
labItemCord = new QLabel("Item 坐标:");
labItemCord->setMinimumWidth(150);
this->statusBar()->addWidget(labItemCord);
m_graphView->setCursor(Qt::CrossCursor);
m_graphView->setMouseTracking(true);
m_graphView->setDragMode(QGraphicsView::RubberBandDrag);
QObject::connect(m_graphView, SIGNAL(mouseMovePoint(QPoint)), this, SLOT(on_mouseMovePoint(QPoint)));
QObject::connect(m_graphView, SIGNAL(mouseClicked(QPoint)), this, SLOT(on_mouseClicked(QPoint)));
iniGraphicsSystem();//初始化
this->showMaximized();//窗口最大化
}
MainWindow::~MainWindow()
{
}
/*
窗口的resizeEvent()事件的响应函数,以便在窗口变化大小时,显示视图区域的大小和场景信息大小
*/
void MainWindow::resizeEvent(QResizeEvent* event)
{
//窗口变化的大小的事件
//显示视图区域坐标信息
QString graphViewInfo = QString::asprintf("Graphics View坐标,左上角总是(0,0),宽度=%d,高度=%d",m_graphView->width(), m_graphView->height());
this->setWindowTitle(graphViewInfo);
//Scene场景坐标信息
QRectF rectF = m_graphView->sceneRect();
QString sceneInfo = QString::asprintf("QGraphicsView::sceneRect=(Left,Top,Width,Height)=%0.0f,%0.0f,%0.0f,%0.0f", rectF.left(),rectF.top(),rectF.width(),rectF.height());
QString info = QString("%1.%2").arg(graphViewInfo).arg(sceneInfo);
this->setWindowTitle(info);
}
void MainWindow::iniGraphicsSystem()
{
//构建Graphics View的各项
QRectF rect(-200, -100, 400, 200);//左上角坐标,宽度和高度
m_scene = new QGraphicsScene(rect);//scene逻辑坐标系定义
m_graphView->setScene(m_scene);//画一个矩形框,大小等于scene;
QGraphicsRectItem* item = new QGraphicsRectItem(rect);
item->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
QPen pen;
pen.setWidth(2);
item->setPen(pen);
m_scene->addItem(item);
//画一个位于scene中心的椭圆,测试局部坐标
QGraphicsEllipseItem* item2 = new QGraphicsEllipseItem(-100, -50, 200, 100);
item2->setPos(0, 0);
item2->setBrush(QBrush(Qt::blue));
//setFlags设置图形项的操作标记,包括可选择、可移动、可获取焦点
item2->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
m_scene->addItem(item2);
//画一个圆,中心位于scene的边缘
QGraphicsEllipseItem* item3 = new QGraphicsEllipseItem(-50, -50, 100, 100);
item3->setPos(rect.right(), rect.bottom());
item3->setBrush(QBrush(Qt::red));
//
item3->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
m_scene->addItem(item3);
//画Scene场景的坐标轴信息
drawSceneCooridate(m_scene);
m_scene->clearSelection();
}
void MainWindow::drawSceneCooridate(QGraphicsScene* scene)
{
QRectF rectScene=scene->sceneRect();
//画横轴(X轴)
QPointF xlineStart(rectScene.left(), (rectScene.topLeft().y() + rectScene.bottomLeft().y()) / 2);
QPointF xlineEnd(rectScene.right(), (rectScene.topLeft().y() + rectScene.bottomLeft().y()) / 2);
QLineF xline(xlineStart, xlineEnd);
ArrowLineItem* xArrowLine = new ArrowLineItem(xline);
xArrowLine->setPos(0, 0);
xArrowLine->setPen(QPen(Qt::black, 4));
scene->addItem(xArrowLine);
//画竖轴(Y轴)
QPointF ylineStart((rectScene.topLeft().x() + rectScene.topRight().x()) / 2, rectScene.top());
QPointF ylineEnd((rectScene.topLeft().x() + rectScene.topRight().x()) / 2, rectScene.bottom());
QLineF yline(ylineStart,ylineEnd );
ArrowLineItem* yArrowLine = new ArrowLineItem(yline);
yArrowLine->setPos(0, 0);
yArrowLine->setPen(QPen(Qt::black, 4));
scene->addItem(yArrowLine);
//画X轴文字
QGraphicsTextItem* xArrowlineText = new QGraphicsTextItem();
xArrowlineText->setPlainText("X");
xArrowlineText->setPos(xlineEnd);
scene->addItem(xArrowlineText);
//画Y轴文字
QGraphicsTextItem* yArrowlineText = new QGraphicsTextItem();
yArrowlineText->setPlainText("Y");
yArrowlineText->setPos(ylineEnd);
scene->addItem(yArrowlineText);
//画中心点文字
QGraphicsTextItem* centerText = new QGraphicsTextItem();
centerText->setPlainText("(0,0)");
centerText->setPos(0,0);
scene->addItem(centerText);
//标识是场景的坐标系文字
QGraphicsTextItem* sceneText = new QGraphicsTextItem();
sceneText->setPlainText("Scene");
//sceneText->setFont(QFont())
sceneText->setPos(rectScene.topLeft());
scene->addItem(sceneText);
}
void MainWindow::on_mouseClicked(QPoint point)
{
//鼠标单击事件
QPointF pointScene = m_graphView->mapToScene(point);//转换到Scene坐标
QGraphicsItem* item = nullptr;
item = m_scene->itemAt(pointScene, m_graphView->transform());//获取光标下的图形项
if (item != nullptr)
{
QPointF pointItem = item->mapFromScene(pointScene);//将场景坐标转换为图形项的局部坐标
labItemCord->setText(QString::asprintf("Item 坐标:%.0f,%0.0f", pointItem.x(), pointItem.y()));
}
}
void MainWindow::on_mouseMovePoint(QPoint point)
{
//鼠标移动事件,point是GraphicView的坐标,物理坐标
labViewCord->setText(QString::asprintf("View坐标:%d,%d", point.x(), point.y()));
QPointF pointScene = m_graphView->mapToScene(point);//转到Scene坐标(物理坐标转场景坐标)
labSceneCord->setText(QString::asprintf("Scene坐标:%0.0f,%0.0f", pointScene.x(), pointScene.y()));
}
结果展示

浙公网安备 33010602011771号