QGraphicsView, QGraphicsObject ,QQGraphicsSvgItem 图片接收鼠标事件 拖拉 收放
由于项目要求,需要加载svg格式图片和pixmap图片,并根据指定坐标在图上进行勾画,并且对相应位置接收鼠标事件。
-继承QGraphicsObject,实现加载pixmap的项
myimageitem.h
#ifndef MYIMAGEITEM_H #define MYIMAGEITEM_H #include <QGraphicsObject> #include <QPainter> #include <QVector> #include <QGraphicsSceneMouseEvent> #include <QMap> class myimageitem: public QGraphicsObject { Q_OBJECT public: myimageitem(QRectF, rect,const QPixmap &image,QGraphicsObject *parent = nullptr);//rect 项的边框尺寸,image 图像 ~myimageitem(); void setRect(const QRectF &rect); QRectF boundingRect()const override; void paint(QPainter *panter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; public slots: void onSyn(int id); signals: void syn(int id); private: QRectF m_rect; QPixmap m_pixmap; float deltaX; // 显示窗口大小与实际图片横轴比例 float deltaY; // 显示窗口大小与实际图片竖轴比例 QMap<int, bool> _rectPointSelected;// 标记矩形是否被鼠标事件选中 QMap<int,QRectF> _rectPoint; // 保存矩形数据 }; #endif // MYIMAGEITEM_H
#include "myimageitem.h" myimageitem::myimageitem(QRectF rect,const QPixmap &image, QGraphicsObject * parent):QGraphicsObject(parent),m_pixmap(image) { deltaX = rect.width()/m_pixmap.width(); deltaY = rect.height()/m_pixmap.height(); QRectF rect1(0,0,200*deltaX,200*deltaY); QRectF rect2(200*deltaX, 200*deltaY, 200*deltaX, 200*deltaY);
// 初始化测试坐标数据 _rectPoint.insert(0, rect1); _rectPointSelected.insert(0,false); _rectPoint.insert(1,rect2); _rectPointSelected.insert(1,false); setRect(rect); } myimageitem::~myimageitem(){ } void myimageitem::setRect(const QRectF &rect) { if(m_rect == rect){ return; } prepareGeometryChange(); m_rect = rect; update(); // 通知重绘图片 } QRectF myimageitem::boundingRect() const{ return m_rect; // 边界尺寸 } void myimageitem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){ Q_UNUSED(option); Q_UNUSED(widget); painter->setRenderHint(QPainter::Antialiasing, true); // 打开抗锯齿 painter->save(); painter->drawPixmap(m_rect, m_pixmap,QRectF()); // 画图 for(QMap<int, bool>::iterator it = _rectPointSelected.begin(); it != _rectPointSelected.end(); ++it){ if(!it.value()){ painter->setPen(Qt::blue); // 如果未被选中 }else { painter->setPen(Qt::red); // 如果被选中 it.value() = false; // 重绘之后选中状态重置 } painter->drawRect(_rectPoint[it.key()]); // 绘制矩形 } painter->restore(); } void myimageitem::mousePressEvent(QGraphicsSceneMouseEvent *event){ // 接收鼠标事件 if(event->button() == Qt::LeftButton){ for(QMap<int, QRectF>::iterator it = _rectPoint.begin(); it != _rectPoint.end(); ++it){ if(it.value().contains(event->pos())){ prepareGeometryChange();// 保持项的索引,即使改变了项的尺寸,如果有必要会调用update() _rectPointSelected[it.key()] = true; // 选中矩形 // emit syn(it.key()); } } } } void myimageitem::onSyn(int id){ prepareGeometryChange(); _rectPointSelected[id] = true; update(); }
-继承QGraphicsSvgItem
mygriditem.h
#ifndef MYGRIDITEM_H
#define MYGRIDITEM_H #include <QtSvg/QGraphicsSvgItem> #include <QGraphicsSceneMouseEvent> #include <QtSvg/QSvgRenderer> #include <QPainter> class mygriditem :public QGraphicsSvgItem { Q_OBJECTpublic: mygriditem(QRectF boundRect,const QString &svgFile,const QSize svgSize,QGraphicsSvgItem *parent = nullptr);// 导入svg格式图片文件 和尺寸 ~mygriditem(); QRectF boundingRect()const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)override; signals: void syn(int id); public slots: void onSyn(int id); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; private: QRectF _boundRect; // 边界矩形 QSvgRenderer *_svgRender; float _xDelta; float _yDelta; QMap<int, bool> _rectPointSelected; QMap<int,QRectF> _rectPoint; }; #endif // MYGRIDITEM_H
#include "mygriditem.h" mygriditem::mygriditem(QRectF boundRect,const QString &svgFile,const QSize svgSize ,QGraphicsSvgItem *parent):QGraphicsSvgItem(parent), _boundRect(boundRect) { _svgRender = new QSvgRenderer(svgFile); //加载svg图 _xDelta = _boundRect.width()/svgSize.width(); _yDelta = _boundRect.height()/ svgSize.height(); QRectF rect1(0*_xDelta,0*_yDelta,60*_xDelta,60*_yDelta); QRectF rect2(60*_xDelta,60*_yDelta,60*_xDelta,60*_yDelta); _rectPoint.insert(0, rect1); _rectPoint.insert(1 ,rect2); _rectPointSelected.insert(0, false); _rectPointSelected.insert(1, false); } mygriditem::~mygriditem(){ } void mygriditem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){ Q_UNUSED(option); Q_UNUSED(widget); painter->setRenderHint(QPainter::Antialiasing, true); painter->save(); _svgRender->render(painter, _boundRect); // 绘制svg图片 // QGraphicsSvgItem::paint(painter, option, widget); for(QMap<int,bool>::iterator it = _rectPointSelected.begin(); it != _rectPointSelected.end() ;++it){ if(it.value()){ painter->setPen(Qt::red); it.value() = false; }else { painter->setPen(Qt::green); } painter->setBrush(Qt::green); painter->drawRect(_rectPoint[it.key()]); } painter->restore(); } QRectF mygriditem::boundingRect() const{ return _boundRect; } void mygriditem::mousePressEvent(QGraphicsSceneMouseEvent *event){ if(event->button() == Qt::LeftButton){ for(QMap<int, QRectF>::iterator it = _rectPoint.begin(); it != _rectPoint.end(); ++ it){ if(it.value().contains(event->pos())){ prepareGeometryChange(); _rectPointSelected[it.key()] = true; update(); // emit syn(it.key()); } } } } void mygriditem::onSyn(int id){ prepareGeometryChange(); _rectPointSelected[id] = true; update(); }
-继承QGraphicsView 实现缩放 拖拽(这部分参考其它博主)
mygraphicsview.h
#ifndef MYGRAPHICSVIEW_H #define MYGRAPHICSVIEW_H #include <QGraphicsView> #include <QKeyEvent> class mygraphicsview:public QGraphicsView { public: explicit mygraphicsview(QWidget *parent = nullptr); ~mygraphicsview(); // 平移速度 void setTranslateSpeed(qreal speed); qreal translateSpeed() const; // 缩放的增量 void setZoomDelta(qreal delta); qreal zoomDelta() const; protected: // 上/下/左/右键向各个方向移动、加/减键进行缩放、空格/回车键旋转 void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; // 平移 void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; // 放大/缩小 void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; public Q_SLOTS: void zoomIn(); // 放大 void zoomOut(); // 缩小 void zoom(float scaleFactor); // 缩放 - scaleFactor缩放的比例因子 void translate(QPointF delta); // 平移 private: Qt::MouseButton m_translateButton; // 平移按钮 qreal m_translateSpeed; // 平移速度 qreal m_zoomDelta; // 缩放的增量 bool m_bMouseTranslate; // 平移标识 QPoint m_lastMousePos; // 鼠标最后按下的位置 qreal m_scale; // 缩放值 }; #endif // MYGRAPHICSVIEW_H
#include "mygraphicsview.h" #define VIEW_CENTER viewport()->rect().center() #define VIEW_WIDTH viewport()->rect().width() #define VIEW_HEIGHT viewport()->rect().height() mygraphicsview::mygraphicsview(QWidget *parent):QGraphicsView(parent), m_translateButton(Qt::LeftButton), m_scale(1.0), m_zoomDelta(0.1), m_translateSpeed(1.0), m_bMouseTranslate(false) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setCursor(Qt::PointingHandCursor); setRenderHint(QPainter::Antialiasing); // setSceneRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX); // setSceneRect(0,0,5472, 3648); // centerOn(0, 0); } mygraphicsview::~mygraphicsview(){ } // 平移速度 void mygraphicsview::setTranslateSpeed(qreal speed) { // 建议速度范围 Q_ASSERT_X(speed >= 0.0 && speed <= 2.0, "InteractiveView::setTranslateSpeed", "Speed should be in range [0.0, 2.0]."); m_translateSpeed = speed; } qreal mygraphicsview::translateSpeed() const { return m_translateSpeed; } // 缩放的增量 void mygraphicsview::setZoomDelta(qreal delta) { // 建议增量范围 Q_ASSERT_X(delta >= 0.0 && delta <= 1.0, "InteractiveView::setZoomDelta", "Delta should be in range [0.0, 1.0]."); m_zoomDelta = delta; } qreal mygraphicsview::zoomDelta() const { return m_zoomDelta; } // 上/下/左/右键向各个方向移动、加/减键进行缩放、空格/回车键旋转 void mygraphicsview::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Up: translate(QPointF(0, -2)); // 上移 break; case Qt::Key_Down: translate(QPointF(0, 2)); // 下移 break; case Qt::Key_Left: translate(QPointF(-2, 0)); // 左移 break; case Qt::Key_Right: translate(QPointF(2, 0)); // 右移 break; case Qt::Key_Plus: // 放大 zoomIn(); break; case Qt::Key_Minus: // 缩小 zoomOut(); break; case Qt::Key_Space: // 逆时针旋转 rotate(-5); break; case Qt::Key_Enter: // 顺时针旋转 case Qt::Key_Return: rotate(5); break; default: QGraphicsView::keyPressEvent(event); } } // 平移 void mygraphicsview::mouseMoveEvent(QMouseEvent *event) { if (m_bMouseTranslate){ QPointF mouseDelta = mapToScene(event->pos()) - mapToScene(m_lastMousePos); translate(mouseDelta); } m_lastMousePos = event->pos(); QGraphicsView::mouseMoveEvent(event); } void mygraphicsview::mousePressEvent(QMouseEvent *event) { if (event->button() == m_translateButton) { // 当光标底下没有 item 时才能移动 QPointF point = mapToScene(event->pos()); if (scene()->itemAt(point, transform()) != NULL) { m_bMouseTranslate = true; m_lastMousePos = event->pos(); } } QGraphicsView::mousePressEvent(event); } void mygraphicsview::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == m_translateButton) m_bMouseTranslate = false; QGraphicsView::mouseReleaseEvent(event); } // 放大/缩小 void mygraphicsview::wheelEvent(QWheelEvent *event) { // 滚轮的滚动量 QPoint scrollAmount = event->angleDelta(); // 正值表示滚轮远离使用者放大负值表示朝向使用者缩小 scrollAmount.y() > 0 ? zoomIn() : zoomOut(); } // 放大 void mygraphicsview::zoomIn() { zoom(1 + m_zoomDelta); } // 缩小 void mygraphicsview::zoomOut() { zoom(1 - m_zoomDelta); } // 缩放 - scaleFactor缩放的比例因子 void mygraphicsview::zoom(float scaleFactor) { // 防止过小或过大 qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width(); if (factor < 0.5 || factor > 100) return; scale(scaleFactor, scaleFactor); m_scale *= scaleFactor; } // 平移 void mygraphicsview::translate(QPointF delta) { // 根据当前 zoom 缩放平移数 delta *= m_scale; delta *= m_translateSpeed; // view 根据鼠标下的点作为锚点来定位 scene setTransformationAnchor(QGraphicsView::AnchorUnderMouse); QPoint newCenter(VIEW_WIDTH / 2 - delta.x(), VIEW_HEIGHT / 2 - delta.y()); centerOn(mapToScene(newCenter)); // scene 在 view 的中心点作为锚点 setTransformationAnchor(QGraphicsView::AnchorViewCenter); }
-测试代码
cview.h
#ifndef CVIEW_H #define CVIEW_H #include <QWidget> #include <QGraphicsScene> #include <QtSvg/QSvgRenderer> #include <QtSvg/QGraphicsSvgItem> #include<QGraphicsGridLayout> #include <QGraphicsLayout> #include "mygraphicsview.h" #include "myimageitem.h" #include "mygriditem.h" QT_BEGIN_NAMESPACE namespace Ui { class CView; } QT_END_NAMESPACE class CView : public QWidget { Q_OBJECT public: CView(QWidget *parent = nullptr); ~CView(); private: Ui::CView *ui; QGraphicsScene *_scene; QGraphicsObject *_codeImgae; }; #endif // CVIEW_H
#include "cview.h" #include "./ui_cview.h" CView::CView(QWidget *parent) : QWidget(parent), ui(new Ui::CView), _scene(new QGraphicsScene) { ui->setupUi(this); QPixmap pixmap; pixmap.load("XXX.png"); // 传入自己的图片 float pixWidth = pixmap.width(); float pixHeight = pixmap.height(); float deltaX = ui->graphicsView_2->width()/pixWidth; float deltaY = ui->graphicsView_2->height()/pixHeight; int viewW = ui->graphicsView_2->width(); int viewH = ui->graphicsView_2->height(); _codeImgae = new myimageitem(QRectF(0, 0,viewH, viewH),pixmap); _scene->addItem(_codeImgae); ui->graphicsView_2->setScene(_scene); float w = ui->graphicsView->width(); float h = ui->graphicsView->height(); mygriditem *svg_render = new mygriditem(QRectF(0,0,w,h),QString("XXX.svg"));// 传入自己的图片 QGraphicsScene *svgScene = new QGraphicsScene(); svgScene->addItem(svg_render); QList<QGraphicsItem*> items = svgScene->items(); ui->graphicsView->setScene(svgScene); } CView::~CView() { delete ui; }