在Visio和MindManager等类似的图元操作软件中,很多时候我们会通过鼠标操作来添加自定义的图元。这里就介绍一下如何在QT的图形视图框架中通过鼠标绘制来添加图元。
在实现的时候我们先添加一个自定义图元用来响应鼠标操作,自定义图元的实现如下所示.

绘制辅助图元

辅助图元类似于标尺线,用来标记用户鼠标框选的范围和位置。实现如下:

//canvasitembase.h
#ifndef _CANVASE_ITEM_BASE_
#define _CANVASE_ITEM_BASE_#include <QObject>
#include <QGraphicsItem>
#include <QPixmap>
#include <QGraphicsObject>class CanvaseItemBase : public QObject, public QGraphicsItem
{Q_OBJECT
public:CanvaseItemBase(QGraphicsItem* parentItem = nullptr);public://修改图元尺寸void set_item_size(int width,int height);void get_item_size(int& width,int& height);protected://边界矩形QRectF boundingRect() const override;//绘制事件void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) final;//获取形状QPainterPath shape() const override;//鼠标事件void mousePressEvent(QGraphicsSceneMouseEvent *event) override;void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;//自定义元素绘制virtual void customPaint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);//获取自定义绘制所需要的矩形QRectF getCustomRect(void) const;private://图元的宽和高int m_rect_width = 0;int m_rect_height = 0;// 画笔设置QColor m_cPenColor;int m_nPenWidth = 1;// 画刷设置QColor m_cBrushColor;
};
#endif
//canvasitembase.cpp
#include "canvasitembase.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QVector2D>
#include <QVector3D>#define PI 3.14159265358979CanvaseItemBase::CanvaseItemBase(QGraphicsItem* parentItem):QGraphicsItem(parentItem),m_cPenColor(255, 0, 0),m_cBrushColor(200, 100, 100)
{//设置图元可以选中this->setFlag(QGraphicsItem::ItemIsSelectable, false);m_rect_width = 0;m_rect_height = 0;
}void CanvaseItemBase::set_item_size(int width, int height)
{m_rect_width = width;m_rect_height = height;
}void CanvaseItemBase::get_item_size(int &width, int &height)
{width = m_rect_width;height = m_rect_height;
}QRectF CanvaseItemBase::boundingRect() const
{QRectF rectF = getCustomRect();return rectF;
}void CanvaseItemBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{painter->setRenderHint(QPainter::Antialiasing, true);painter->setRenderHint(QPainter::SmoothPixmapTransform, true);painter->setRenderHint(QPainter::TextAntialiasing, true);// 自定义绘制customPaint(painter, option, widget);
}QPainterPath CanvaseItemBase::shape() const
{QPainterPath path;path.addRect(boundingRect());return path;
}void CanvaseItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event)
{return QGraphicsItem::mousePressEvent(event);
}void CanvaseItemBase::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{return QGraphicsItem::mouseMoveEvent(event);
}void CanvaseItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{return QGraphicsItem::mouseReleaseEvent(event);
}QVariant CanvaseItemBase::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{if (change == QGraphicsItem::ItemSelectedChange)prepareGeometryChange();return QGraphicsItem::itemChange(change, value);
}void CanvaseItemBase::customPaint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{QPen pen;pen.setWidth(m_nPenWidth);pen.setColor(m_cPenColor);pen.setStyle(Qt::DashLine);pen.setWidth(2);painter->setPen(pen);QRectF itemRect = this->getCustomRect();QRectF outLintRect = itemRect;if((m_rect_width == 0) ||(m_rect_width == 0)){painter->setCompositionMode(QPainter::CompositionMode_Clear);painter->eraseRect(outLintRect);return;}else{painter->setCompositionMode(QPainter::CompositionMode_SourceOver);painter->drawRect(outLintRect);}
}QRectF CanvaseItemBase::getCustomRect(void) const
{return QRectF(0,0,m_rect_width,m_rect_height);
}

在视图中当鼠标框选范围发生变化的时候,自定义图元会通过绘制红色的虚线框来标记鼠标的框选范围。

自定义视图

通过重写QGraphicsView,我们来响应对应的鼠标键盘消息,从而实现对应的绘制操作,自定义视图类的实现如下所示:

//mygraphicsview.h
#ifndef _MY_GRAPHICS_VIEW_H_
#define _MY_GRAPHICS_VIEW_H_#include <QGraphicsView>
#include "canvasitembase.h"
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QResizeEvent>class MyGraphicsView : public QGraphicsView
{Q_OBJECTpublic:explicit MyGraphicsView(QWidget *parent = nullptr);~MyGraphicsView();protected:void mousePressEvent(QMouseEvent* event);void mouseMoveEvent(QMouseEvent* event);void mouseReleaseEvent(QMouseEvent* event);void resizeEvent(QResizeEvent* event);private://绘制辅助图元CanvaseItemBase* m_custom_item;//主场景QGraphicsScene m_main_scene;//鼠标起始点和结束点QPoint m_start_point;QPoint m_end_point;//鼠标左键是否按下bool m_is_leftbtn_pressed = false;
};#endif
//mygraphicsview.cpp
#include "mygraphicsview.h"MyGraphicsView::MyGraphicsView(QWidget *parent) :QGraphicsView(parent)
{//屏蔽显示滚动条this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//添加自定义m_custom_item  = new CanvaseItemBase();m_main_scene.addItem(m_custom_item);this->setScene(&m_main_scene);//跟踪鼠标移动this->setMouseTracking(true);int view_width = this->width();int view_height = this->height();this->setSceneRect(-0.5*view_width,-0.5*view_height,view_width,view_height);
}MyGraphicsView::~MyGraphicsView()
{}void MyGraphicsView::mousePressEvent(QMouseEvent *event)
{QGraphicsView::mousePressEvent(event);if(event->button() == Qt::LeftButton){m_start_point = m_end_point = event->pos();QList<QGraphicsItem*> items = this->items(m_end_point);//依据鼠标点击的控件位置设置元素的位置if(items.empty()){m_is_leftbtn_pressed = true;//将控件坐标映射到场景坐标QPointF view_point = this->mapToScene(m_start_point);m_custom_item->setPos(view_point);m_custom_item->set_item_size(0,0);m_custom_item->update();this->viewport()->update();}}//右键添加图元else if(event->button() == Qt::RightButton){int width,height;m_custom_item->get_item_size(width,height);QPointF scene_pos = m_custom_item->scenePos();QGraphicsRectItem* rect_item = new QGraphicsRectItem(scene_pos.x(),scene_pos.y(),width,height);m_main_scene.addItem(rect_item);}
}void MyGraphicsView::mouseMoveEvent(QMouseEvent *event)
{//鼠标移动过程中计算元素的宽高并更新显示if(m_is_leftbtn_pressed){m_end_point = event->pos();int width = m_end_point.x() - m_start_point.x();int height = m_end_point.y() - m_start_point.y();m_custom_item->set_item_size(width,height);m_custom_item->update();this->viewport()->update();}this->update();QGraphicsView::mouseMoveEvent(event);
}void MyGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){if(m_start_point != m_end_point){m_custom_item->update();}m_is_leftbtn_pressed = false;}QGraphicsView::mouseReleaseEvent(event);
}void MyGraphicsView::resizeEvent(QResizeEvent *event)
{//将场景和控件完全重合,这样坐标就一一对应了int view_width = this->width();int view_height = this->height();this->setSceneRect(-0.5*view_width,-0.5*view_height,view_width,view_height);
}

添加了自定义视图之后,我们就可以通过鼠标操作来添加自定义图元了。鼠标在视图上左键框选一个范围,然后松开鼠标左键点击鼠标右键便可以添加一个对应范围内的图元元素了。

示例效果图

使用效果如下图所示:

QGraphicsView通过鼠标操作来绘制图元相关推荐

  1. Qt (高仿Visio)流程图组件开发(二) 基本图元绘制 图元间连线绘制

    文章目录 本系列目录 前言 一.如何绘制图元 二.两图元之间如何连线 三.如何实现线跟随图元移动 四.线的位置判断 总结 本系列目录 Qt (高仿Visio)流程图组件开发(一) 效果展示及基本开发框 ...

  2. HighGUI图像用户界面初步(滑动条、鼠标操作)

    文章目录 1.Mat类简析 2.图像的载入:imread()函数 3.图像的显示:imshow()函数 4.创建窗口:namedWindow()函数 5.输出图像到文件:imwrite()函数 6.综 ...

  3. opencv鼠标操作,画矩形

    opencv鼠标操作,画矩形 效果图 主要两个函数在作用 //-------------------全局函数声明部分------------------------- //描述:全局函数的声明 //- ...

  4. 【OpenCV】OpenCV函数精讲之 -- 鼠标操作

    指定鼠标操作消息回调函数的函数为SetMouseCallback 函数原型: void setMouseCallback(conststring& winname, MouseCallback ...

  5. OpenCV之鼠标操作

    先上代码 #include <iostream> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> ...

  6. 【学习OpenCV4】键盘鼠标操作总结

    本文分享内容来自图书<学习OpenCV 4:基于Python的算法实战>,该书内容如下: 第1章 OpenCV快速入门: 第2章 图像读写模块imgcodecs: 第3章 核心库模块cor ...

  7. OpenCV利用鼠标操作测量角度

    前言 本文介绍一种在OpenCV中定义鼠标事件来进行对两条直线之间夹角的计算以及输出. 一.本文内容 利用OpenCV设置鼠标操作来进行测量角度,基本思路是通过定义鼠标事件得到三角形的三个点的坐标位置 ...

  8. 游戏扫雷 鼠标操作 C语言

    前言   这篇文章是我学习C语言后实现自己给自己定的小目标的记录性博客,这是第一篇比较系统的.但更多的是从我自身的角度出发写的博客. ​  在决定开始做这个小游戏后,我在网上找了很多资料.在这个版本之 ...

  9. Opencv2.4.9鼠标操作

    class Rect 成员变量有 x   y      width      heigh x y  表示左上角的坐标     width heigh 矩形的宽和高 成员函数Size Size() 面积 ...

最新文章

  1. amaze ui各个模块简单说明
  2. Tomcat8中的并发ConcurrentDateFormat的实现
  3. 关于wordpress中更换CKEditor编辑器
  4. Redis对象的refcount与lru属性(内存回收、对象共享、空转时长)
  5. Visual Studio Code搭建NodeJs的开发环境
  6. oracle中创建一个用户,只能查看指定的视图,如何授权,创建别名
  7. PostgreSQL 10.1 手册_部分 II. SQL 语言_第 9 章 函数和操作符_9.23. 行和数组比较
  8. 如何从零构建你的自动化运维体系?——从制度到技术
  9. python面向对象——类(上)
  10. 大佬对Maven进行深度讲解:什么是Maven?POM.XML如何解读?
  11. [原创]C#之探索发现:在WinForm上写的一个模拟分页小程序
  12. Apktool 使用详解
  13. B站高管解读财报:要更快实现盈亏平衡 陈睿亲自盯减亏工作
  14. 在uniapp中如何使用icon图标
  15. 学大伟业 2017 国庆 Day1
  16. 天津化工杂志天津化工杂志社天津化工编辑部2022年第3期目录
  17. 数量关系-排列组合和概率
  18. 【开发日志-已归档】2021-07
  19. 堡垒机前戏:paramiko模块
  20. 蜂鸣器(HC6800-EM3 V2.2开发板)

热门文章

  1. 软件公司的咨询顾问和售前顾问怎么区分
  2. 我理解的企业技术管理(三)——如何做好技术管理
  3. 记一次修改阿里云DNS解析问题
  4. Vue项目启动内存溢出 js stack overflow
  5. 杰理之探测芯片最高稳定运行频率【篇】
  6. 【转】Principles of User Interface Design
  7. 不小心删除文件夹怎么恢复,怎么恢复误删文件?
  8. 误删计算机桌面图标怎么恢复,大神为你解答win7系统恢复误删桌面计算机图标的步骤...
  9. win10的高占用CPU的进程wsappx关闭指南+解决win10应用商店打不开
  10. unity中使用AO贴图和自发光emission的简单应用