赞
踩
需求:
基于视频进行 图形的绘制。
方案:
上一篇文章分享了如何将视频实时渲染到QGraphicsScene 系统里,并简单讲述了如何进行绘图,但在实际使用时还是发现了一些技巧,现在总结一下。
直线:
矩形:
圆:
弧:
2,实现
定义一个控制点,用于旋转或者改变大小。开始也尝试了 通过hover事件 来改变鼠标形状,但是这样判断地方有点多,通过使用控制点的方式,实现起来相对简单,使用上也还可以。
- #ifndef BPOINTITEM_H
- #define BPOINTITEM_H
-
- #include <QObject>
- #include <QAbstractGraphicsShapeItem>
- #include <QPointF>
- #include <QPen>
- #include <QPainter>
- #include <QGraphicsSceneMouseEvent>
- #include <QGraphicsScene>
- #include <QCursor>
- #include <QKeyEvent>
- #include <QList>
- #include <QMutex>
- #include <QThread>
-
- //控制点
- class EPointItem :public QObject, public QGraphicsItem {
- Q_OBJECT
-
- public:
- enum class PointType{
- MovePoint=0,
- RotatePoint=1
- };
-
- EPointItem(QGraphicsItem* parent, QPointF p,PointType type = PointType::MovePoint);
-
- public:
- virtual QRectF boundingRect() const override;
- virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
- virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
- virtual void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
- virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;
-
- signals:
- void posMove(QPointF curPos, QPointF lastPos);
- void posRotate(QPointF curPos,QPointF lastPos);
- void posRelease();
-
- private:
- PointType m_type;
-
- };
- #endif // BPOINTITEM_H
-
-
-
- #include "bpointitem.h"
- #include <QDebug>
- #include <QtMath>
-
- EPointItem::EPointItem(QGraphicsItem* parent, QPointF p,PointType type)
- : QGraphicsItem(parent),m_type(type)
- {
- this->setPos(p);
- this->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
- this->setCursor(Qt::PointingHandCursor);
- }
-
- QRectF EPointItem::boundingRect() const
- {
- if(m_type==PointType::MovePoint){
- return QRectF(-4, -4, 8, 8);
- }else if(m_type==PointType::RotatePoint){
- return QRectF(-8, -8, 16, 16);
- }else{
- return QRectF(-4, -4, 8, 8);
- }
- }
-
- void EPointItem::mousePressEvent(QGraphicsSceneMouseEvent* event) {
- setSelected(true);
- QGraphicsItem::mousePressEvent(event);
- }
-
- void EPointItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
- emit posRelease();
- setSelected(false);
- QGraphicsItem::mouseReleaseEvent(event);
- }
-
- void EPointItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
- {
- Q_UNUSED(option);
- Q_UNUSED(widget);
- if (isSelected()) {
- painter->setBrush(QBrush(Qt::green));
- }
- else {
- painter->setBrush(QBrush(Qt::white));
- }
-
- if(m_type==PointType::MovePoint){
- painter->setPen(QPen(Qt::gray, 1));
- painter->drawEllipse(-4, -4, 8, 8);
- }else if(m_type==PointType::RotatePoint){
- painter->setPen(QPen(Qt::gray, 2));
- painter->drawEllipse(-8, -8, 16, 16);
- painter->drawEllipse(-4, -4, 8, 8);
- }
-
- }
-
- void EPointItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
- if (event->buttons() == Qt::LeftButton) {
- if(m_type==PointType::MovePoint)
- emit posMove(event->scenePos(), event->lastScenePos());
- else if(m_type==PointType::RotatePoint){
- emit posRotate(event->scenePos(), event->lastScenePos());
- }
- }
- }
-
以直线为例,实现的时候 先画一个普通的矩形,然后添加两个控制点,用于改变大小和旋转,通过控制点中 推拽的信号 来改变矩形的大小和旋转的角度,并且在矩形的paint函数中,更新控制点的位置。
- class EItemUtil{
- public:
- void rotateItem(QGraphicsItem* item,QPointF &curPos, QPointF &lastPos){
- // 设置中心点为原点
- QPointF originPos = item->boundingRect().center();
- // 从原点延伸出去两条线
- QLineF p1 = QLineF(originPos, item->mapFromScene(lastPos));
- QLineF p2 = QLineF(originPos, item->mapFromScene(curPos));
- // 两条线的夹角 为旋转角度
- qreal dRotateAngle = p2.angleTo(p1);
- item->setTransformOriginPoint(originPos);
- qreal dCurAngle = item->rotation() + dRotateAngle;
-
- while (dCurAngle > 360.0) {
- dCurAngle -= 360.0;
- }
- item->setRotation(dCurAngle);
- item->update();
- }
- };
-
- //直线
- class ELine : public QObject, public QGraphicsRectItem
- {
- Q_OBJECT
- public:
- ELine(const QRectF& rect, QGraphicsItem* parent = nullptr);
-
- protected:
- void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
-
- private:
- EPointItem* resizeItem;
- EPointItem* rotateItem;
-
- EItemUtil util;
-
- private:
- //改变大小后 旋转中心会改变,这里要处理一下
- void resetCenter();
- };
-
- ELine::ELine(const QRectF& rect, QGraphicsItem* parent)
- : QGraphicsRectItem(rect, parent)
- {
- setFlag(QGraphicsItem::ItemIsMovable);
- setFlag(QGraphicsItem::ItemSendsGeometryChanges);
- setAcceptHoverEvents(true);
-
- //定义一个旋转的控制点
- rotateItem = new EPointItem(this,QPointF(this->rect().x()+this->rect().width(), this->rect().y()),EPointItem::PointType::RotatePoint);
- connect(rotateItem, &EPointItem::posRotate, this, [this](QPointF curPos, QPointF lastPos) {
- util.rotateItem(this,curPos,lastPos);
- });
-
- //定义一个改变大小的控制点
- resizeItem = new EPointItem(this, QPointF(this->rect().x(), this->rect().y()));
- resizeItem->setParentItem(this);
- connect(resizeItem, &EPointItem::posMove, this, [&](QPointF curPos, QPointF lastPos) {
- this->prepareGeometryChange();
- QRectF newRect = this->rect();
-
- qreal dMouseX = mapFromScene(curPos).x();
- qreal dMouseY = mapFromScene(curPos).y();
-
- double dRemainWidth = newRect.width();
- double dRemainHeight = newRect.height();
-
- dRemainWidth = newRect.right() - dMouseX;
- dRemainHeight = newRect.bottom() - dMouseY;
- if(dRemainHeight<0||dRemainWidth<0)
- return;
-
- newRect.setTopLeft(QPointF(newRect.right() - dRemainWidth, newRect.bottom() - dRemainHeight));
- this->setRect(newRect);
- });
-
- connect(resizeItem, &EPointItem::posRelease, this, [this]{
- resetCenter();
- });
-
- }
-
- void ELine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
- {
- QPen mPen = QPen(Qt::red, 1);
- painter->setPen(mPen);
- painter->drawRect(rect());
-
- //更新两个控制点的位置
- resizeItem->setPos(QPointF(this->rect().x(), this->rect().y()));
- rotateItem->setPos(QPointF(this->rect().x()+this->rect().width(), this->rect().y()));
- }
-
- void ELine::resetCenter()
- {
- //处理旋转后,改变大小的导致的旋转中心位置偏差
- auto rr = this->boundingRect();
- auto angle = this->rotation()*PI/180;
- auto p1 = rr.center();
- auto origin = this->transformOriginPoint();
- QPointF p2 = QPointF(0, 0);
-
- p2.setX(origin.x() + qCos(angle) * (p1.x() - origin.x()) - qSin(angle) * (p1.y() - origin.y()));
- p2.setY(origin.y() + qSin(angle) * (p1.x() - origin.x()) + qCos(angle) * (p1.y() - origin.y()));
-
- auto diff = p1 - p2;
-
- this->setRect(rr.adjusted(-diff.x(), -diff.y(), -diff.x(), -diff.y()));
- this->setTransformOriginPoint(this->boundingRect().center());
- this->update();
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。