概述

用Qt鼠标事件实现基本几何图形的绘制,支持直线、矩形、圆形、椭圆。后期可以在此基础上进行扩展。


​本文Demo下载地址​


效果图

Qt鼠标拖动绘制基本几何图形_下载地址

实现

本示例使用QGraphics体系来实现,因为要移动对象,所以生成的图形必须是一个单独的对象,鼠标拖动绘制的过程是在临时层中完成,release后生成一个矢量的图形item并添加到场景中。

关键代码

主场景中有一个父rootItem,在scene中将鼠标或触控事件传到rooitem后动态绘制临时的图形,release事件后生成一个标准的图形对象:

void GsRootItem::drawPress(int id, const QPointF &p)
{
ShapeInfo info;
info.firstPos = p;
info.type = getCurType();
m_Objs.insert(id,info);
}

void GsRootItem::drawMove(int id, const QPointF &lastPoint, const QPointF &curPoint)
{
if(!m_Objs.contains(id)){
return;
}
ShapeInfo info = m_Objs.value(id);
m_pTempLayer->drawShape(info.type,info.firstPos,curPoint);
}

void GsRootItem::drawRelease(int id, const QPointF &point)
{
if(!m_Objs.contains(id)){
return;
}
ShapeInfo info = m_Objs.value(id);
drawRealShape(info.type,info.firstPos,point);
m_Objs.remove(id);
m_pTempLayer->clear();
}

...
void GsRootItem::drawRealShape(GsShapeType type, QPointF p1, QPointF p2)
{
//计算图形绘制区域
QRectF rect;
rect.setX(qMin(p1.x(),p2.x()));
rect.setY(qMin(p1.y(),p2.y()));
if(type == Shape_Circle){
rect.setWidth(qAbs(p1.y() - p2.y()));
rect.setHeight(qAbs(p1.y() - p2.y()));
}
else{
rect.setWidth(qAbs(p1.x() - p2.x()));
rect.setHeight(qAbs(p1.y() - p2.y()));
}
rect.adjust(-5,-5,5,5);
GsShapeBaseItem * item = m_pShapeFactory->getShapeItem(type,rect,this);
item->drawShape(p1,p2);
}

drawRealShape函数就是用与创建一个独立的几何图形,通过以下的工厂模式来生成

 GsShapeBaseItem * item = m_pShapeFactory->getShapeItem(type,rect,this);

工厂代码:

GsShapeBaseItem *GsShapeFactory::getShapeItem(GsShapeType type,QRectF rectF,
QGraphicsObject *parent)
{
GsShapeBaseItem * item = nullptr;
switch (type) {
case Shape_Line:
item = new GsShapeLineItem(rectF,parent);
break;
case Shape_Rectange:
item = new GsShapeRectangeItem(rectF,parent);
break;
case Shape_Circle:
item = new GsShapeCircleItem(rectF,parent);
break;
case Shape_Oval:
item = new GsShapeOvalItem(rectF,parent);
break;
default:
break;
}
item->setZValue(10);
return item;
}

在工厂类中会创建不同的图形对象。每一个图形对象是继承于QGraphicsObject然后重写paint函数去进行绘制,比如说原型:

void GsShapeCircleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setRenderHint(QPainter::Antialiasing);
QColor color = Qt::red;//(rand()%255,rand()%255,rand()%255);
painter->setBrush(color);
if(m_bTap){
painter->setPen(QPen(Qt::yellow,5,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
}
else{
painter->setPen(QPen(color,3,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
}
painter->drawEllipse(m_firstPoint.x(),m_firstPoint.y(),
qAbs(m_lastPoint.y() - m_firstPoint.y()),
qAbs(m_lastPoint.y() - m_firstPoint.y()));
}

其他图形类似。

实现图形的选择和拖动,需要在item中添加以下两句:

setFlag(ItemIsSelectable,true);
setFlag(ItemIsMovable,true);

然后就可以自由拖动啦。

基本逻辑都很简单。


​本文Demo下载地址​