在使用QGraphicsRectItem时,涉及到需要缩放控件,于是在网上查找相关代码。很幸运的很快就找到了一个python写的旋转方法,效果也正是我想要的,于是我将代码改为C++的,测试成功。后来增加旋转需求,很幸运,这部分代码同样支持旋转,即旋转后仍然可以进行缩放。至于界面效果,我大概完整地实现了同PS上操作矩形的方式。
python参考地址:http://www.chinaoc.com.cn/p/1177045.html

效果demo展示

接口文件及说明

实现思路

放缩部分:我只是对python原文进行了python到C++转译而已,思路参见http://www.chinaoc.com.cn/p/1177045.html。

旋转部分思路:在view的mouseMoveEvent中调用getRotateCursor,获取指针形状。针对item设置c_rotate_tolerance 旋转容忍度,只有接近item周围才会支持旋转。mousePressEvent中设置setRotateStart,表示鼠标已按下,开始旋转。同时为了实现动态旋转,在mouseMoveEvent重复调用setRotateEnd,设置鼠标实时位置。

注1:使用时,应将mapCursors中的地址换成正确有效的地址。
注2:由于上述的放缩是基于item内部坐标完成的放缩,所以旋转并不会影响其效果。所以,你大可以重新实现更好的旋转效果,如果可以的话,也可以分享给我你的想法。

#include <QGraphicsRectItem>
#include <QStyleOptionGraphicsItem>
#include <QStyleOption>
#include <QCursor>const Qt::CursorShape handleCursors[] = {Qt::SizeFDiagCursor,Qt::SizeVerCursor,Qt::SizeBDiagCursor,Qt::SizeHorCursor,Qt::SizeFDiagCursor,Qt::SizeVerCursor,Qt::SizeBDiagCursor,Qt::SizeHorCursor,
};const QString mapCursors[] = {"",":/QtGuiApplication4/Resources/rotate_top_left.png",":/QtGuiApplication4/Resources/rotate_top_middle.png",":/QtGuiApplication4/Resources/rotate_top_right.png",":/QtGuiApplication4/Resources/rotate_middle_right.png",":/QtGuiApplication4/Resources/rotate_bottom_right.png",":/QtGuiApplication4/Resources/rotate_bottom_middle.png",":/QtGuiApplication4/Resources/rotate_bottom_left.png",":/QtGuiApplication4/Resources/rotate_middle_left.png"
};class CustomRectItem : public QGraphicsRectItem
{enum MOUSEHANDLE {handleNone = 0,handleTopLeft = 1,handleTopMiddle = 2,handleTopRight = 3,handleMiddleRight = 4,handleBottomRight = 5,handleBottomMiddle = 6,handleBottomLeft = 7,handleMiddleLeft = 8,};enum MOUSEROTATEHANDLE {handleRotateNone = 0,handleRotateTopLeft = 1,handleRotateTopMiddle = 2,handleRotateTopRight = 3,handleRotateMiddleRight = 4,handleRotateBottomRight = 5,handleRotateBottomMiddle = 6,handleRotateBottomLeft = 7,handleRotateMiddleLeft = 8,};const float c_handle_size = 8.0;const float c_handle_space = -4.0;const float c_rotate_tolerance = 20.0;const int c_handle_cursors_size = 8;   // handleCursors[] sizeconst int c_rotate_cursors_size = 9;    // MOUSEROTATEHANDLE sizeconst QSize c_rotate_cursor_size = QSize(20, 20);public:CustomRectItem(QGraphicsItem *parent = Q_NULLPTR);~CustomRectItem();// Returns the shape of this item as a QPainterPath in local coordinates.QPainterPath shape() const override;// Returns the bounding rect of the shape (including the resize handles).QRectF boundingRect() const override;void updateHandlesPos();bool isHover();// point is scene coordinateQCursor getRotateCursor(const QPointF& point);// set point for start rorate// @note point is scene coordinatevoid setRotateStart(const QPointF& point);// set point for end rorate// @note point is scene coordinatevoid setRotateEnd(const QPointF& point);protected:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE;void hoverEnterEvent(QGraphicsSceneHoverEvent *event);//  Executed when the mouse leaves the shape (NOT PRESSED).void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);// Executed when the mouse moves over the shape (NOT PRESSED).void hoverMoveEvent(QGraphicsSceneHoverEvent *event);//  Executed when the mouse is being moved over the item while being pressed.void mouseMoveEvent(QGraphicsSceneMouseEvent *event);// Executed when the mouse is pressed on the item.void mousePressEvent(QGraphicsSceneMouseEvent *event);// Executed when the mouse is released from the item.void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);// Executed when the key is pressed on the item.void keyPressEvent(QKeyEvent *event);private://  Returns the resize handle below the given point.MOUSEHANDLE handleAt(const QPointF& point);//  Perform shape interactive resize.void interactiveResize(const QPointF& mousePos);// the length2 with point1 and point2float getLength2(const QPointF& point1, const QPointF& point2);private:std::map<MOUSEROTATEHANDLE, QPointF> m_points;std::map<MOUSEROTATEHANDLE, QCursor> m_cursorRotate;std::map<MOUSEHANDLE, QRectF> m_handles;MOUSEHANDLE m_handle;QCursor m_cursor;QPointF m_mousePressPos;QRectF m_mousePressRect;QPointF m_mouseRotateStart;float m_fLastAngle;MOUSEHANDLE m_bhandleSelected;bool m_isHover;
};

源文件代码参考

分步介绍我就不加头文件咯!另外,我是摘出来的这段代码,有小错误的话,自己纠正一下就行咯!

重载paint函数,绘制了选中时的,边角矩形和去掉了选中状态(那种难看的虚线框)。

void CustomRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{QStyleOptionGraphicsItem op;if (widget == nullptr)op = *option;elseop.initFrom(widget);if (option->state & QStyle::State_Selected)op.state = QStyle::State_None;QGraphicsRectItem::paint(painter, &op, widget);if (isSelected() == true){painter->setRenderHint(QPainter::Antialiasing);painter->setBrush(QBrush(QColor(255, 255, 255, 255)));painter->setPen(QPen(QColor(0x293a56ff), 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));for (auto it : m_handles){if (m_bhandleSelected == MOUSEHANDLE::handleNone || it.first == m_bhandleSelected)painter->drawRect(it.second);}}
}

初始化部分,不做介绍。

CustomRectItem::CustomRectItem(QGraphicsItem * parent): QGraphicsRectItem(parent), m_points(), m_cursorRotate(), m_handles(), m_handle(MOUSEHANDLE::handleNone), m_cursor(Qt::ArrowCursor), m_mousePressPos(), m_mousePressRect(), m_mouseRotateStart(), m_fLastAngle(0.0), m_bhandleSelected(MOUSEHANDLE::handleNone), m_isHover(false)
{setAcceptHoverEvents(true);setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges);m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopLeft, QRectF()));m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopMiddle, QRectF()));m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopRight, QRectF()));m_handles.insert(std::make_pair(MOUSEHANDLE::handleMiddleLeft, QRectF()));m_handles.insert(std::make_pair(MOUSEHANDLE::handleMiddleRight, QRectF()));m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomLeft, QRectF()));m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomMiddle, QRectF()));m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomRight, QRectF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopLeft, QPointF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopMiddle, QPointF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopRight, QPointF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleRight, QPointF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomRight, QPointF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomMiddle, QPointF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomLeft, QPointF()));m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleLeft, QPointF()));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopLeft, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateTopLeft]).scaled(c_rotate_cursor_size))));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopMiddle, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateTopMiddle]).scaled(c_rotate_cursor_size))));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopRight, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateTopRight]).scaled(c_rotate_cursor_size))));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleRight, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateMiddleRight]).scaled(c_rotate_cursor_size))));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomRight, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateBottomRight]).scaled(c_rotate_cursor_size))));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomMiddle, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateBottomMiddle]).scaled(c_rotate_cursor_size))));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomLeft, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateBottomLeft]).scaled(c_rotate_cursor_size))));m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleLeft, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateMiddleLeft]).scaled(c_rotate_cursor_size))));updateHandlesPos();
}
CustomRectItem::~CustomRectItem()
{}

这部分我也不清楚什么意思。

QPainterPath CustomRectItem::shape() const
{QPainterPath path = QPainterPath();path.addRect(this->rect());if (this->isSelected()){for (auto shape : m_handles)path.addEllipse(shape.second);}return path;
}

调整了下有效边界,这影响着hoverEnterEvent,hoverLeaveEvent生效的范围。c_handle_size 是调整大小的方框的大小,c_handle_space表示方框嵌入item的宽度,是个负数,正常为c_handle_size 的一半。

QRectF CustomRectItem::boundingRect() const
{auto o = c_handle_size + c_handle_space;return this->rect().adjusted(-o, -o, o, o);
}

m_isHover 表示鼠标是否在item上。当进行放缩时,鼠标可能会出界,导致view捕捉到,并且修改指针形状,通过判断该参数可纠正。

void CustomRectItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
{QGraphicsRectItem::hoverEnterEvent(event);m_isHover = true;
}
void CustomRectItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
{setCursor(Qt::ArrowCursor);QGraphicsRectItem::hoverLeaveEvent(event);m_isHover = false;
}

这里基于python的原文,进行了适当修改。当item进行了旋转后,鼠标指针的方向也应该跟着改变。而且这里有个22.5度的逆向偏移。如果不理解可以运行demo,去掉试试。比如,旋转角度为44度,46度时,会有一个看着别扭。

void CustomRectItem::hoverMoveEvent(QGraphicsSceneHoverEvent * event)
{if (isSelected()){m_handle = handleAt(event->pos());if (MOUSEHANDLE::handleNone == m_handle)m_cursor = Qt::SizeAllCursor;else{float angle = this->rotation() + 22.5;while (angle >= 360.0)angle -= 360;// choose the right cursorm_cursor = handleCursors[((int)m_handle + (int)(angle / 45) - 1) % c_handle_cursors_size];}setCursor(m_cursor);}   QGraphicsRectItem::hoverMoveEvent(event);
}

判断鼠标指针的状态,进行调整大小。

void CustomRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{if (MOUSEHANDLE::handleNone != m_bhandleSelected)interactiveResize(event->pos());elseQGraphicsRectItem::mouseMoveEvent(event);
}void CustomRectItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
{m_bhandleSelected = handleAt(event->pos());if (MOUSEHANDLE::handleNone != m_bhandleSelected){m_mousePressPos = event->pos();m_mousePressRect = boundingRect();}QGraphicsRectItem::mousePressEvent(event);
}

<这里前半部分是个重点>
目的是解决有旋转角度的矩形,拉伸之后,再次旋转,旋转中心该仍然为之前坐标,手动设置为中心,会产生漂移的问题。如果不需要解决该问题,可注掉该部分代码。原理参见子章节:https://blog.csdn.net/xiaonuo911teamo/article/details/106129696

void CustomRectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{auto rr = this->rect();auto angle = qDegreesToRadians(this->rotation());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()));setTransformOriginPoint(this->rect().center());updateHandlesPos();m_bhandleSelected = MOUSEHANDLE::handleNone;m_mousePressPos = QPointF();m_mousePressRect = QRectF();this->update();QGraphicsRectItem::mouseReleaseEvent(event);
}

键盘控制平移的简单实现。

void CustomRectItem::keyPressEvent(QKeyEvent * event)
{switch (event->key()){case Qt::Key_Up:this->moveBy(0, -1);event->setAccepted(true);break;case Qt::Key_Down:this->moveBy(0, 1);event->setAccepted(true);break;case Qt::Key_Left:this->moveBy(-1, 0);event->setAccepted(true);break;case Qt::Key_Right:this->moveBy(1, 0);event->setAccepted(true);break;default:event->setAccepted(false);break;}//QGraphicsRectItem::keyPressEvent(event);
}

调整四周小矩形的位置和大小。

void CustomRectItem::updateHandlesPos()
{auto s = c_handle_size;auto b = boundingRect();m_handles[MOUSEHANDLE::handleTopLeft] = QRectF(b.left(), b.top(), s, s);m_handles[MOUSEHANDLE::handleTopMiddle] = QRectF(b.center().x() - s / 2, b.top(), s, s);m_handles[MOUSEHANDLE::handleTopRight] = QRectF(b.right() - s, b.top(), s, s);m_handles[MOUSEHANDLE::handleMiddleLeft] = QRectF(b.left(), b.center().y() - s / 2, s, s);m_handles[MOUSEHANDLE::handleMiddleRight] = QRectF(b.right() - s, b.center().y() - s / 2, s, s);m_handles[MOUSEHANDLE::handleBottomLeft] = QRectF(b.left(), b.bottom() - s, s, s);m_handles[MOUSEHANDLE::handleBottomMiddle] = QRectF(b.center().x() - s / 2, b.bottom() - s, s, s);m_handles[MOUSEHANDLE::handleBottomRight] = QRectF(b.right() - s, b.bottom() - s, s, s);
}bool CustomRectItem::isHover()
{return m_isHover;
}

判断是否在可旋转范围内,是则返回对应的QCursor。计算应当返回什么QCursor的思路是,先在item坐标下,计算出距离最近的是哪个小方块,然后再加上旋转角度的偏移量,就得到了应该在视觉上看到的正确的鼠标形状。或许有更方便的实现方法。

QCursor CustomRectItem::getRotateCursor(const QPointF & point)
{if (m_isHover == true || !isSelected())return QCursor();if (boundingRect().contains(mapFromScene(point)))return QCursor();auto srcRect = rect();auto frameRect = srcRect.adjusted(-c_rotate_tolerance, -c_rotate_tolerance, c_rotate_tolerance, c_rotate_tolerance);QPointF innerPoint = mapFromScene(point);if (!frameRect.contains(innerPoint))return QCursor();m_points[MOUSEROTATEHANDLE::handleRotateTopLeft] = srcRect.topLeft();m_points[MOUSEROTATEHANDLE::handleRotateTopMiddle] = QPointF(srcRect.center().x(), srcRect.top());m_points[MOUSEROTATEHANDLE::handleRotateTopRight] = srcRect.topRight();m_points[MOUSEROTATEHANDLE::handleRotateMiddleRight] = QPointF(srcRect.right(), srcRect.center().y());m_points[MOUSEROTATEHANDLE::handleRotateBottomRight] = srcRect.bottomRight();m_points[MOUSEROTATEHANDLE::handleRotateBottomMiddle] = QPointF(srcRect.center().x(), srcRect.bottom());m_points[MOUSEROTATEHANDLE::handleRotateBottomLeft] = srcRect.bottomLeft();m_points[MOUSEROTATEHANDLE::handleRotateMiddleLeft] = QPointF(srcRect.left(), srcRect.center().y());auto ret = MOUSEROTATEHANDLE::handleRotateNone;float l = 3.4028235E38;for (auto& iter : m_points){auto length = getLength2(iter.second, innerPoint);if (length < l){l = length;ret = iter.first;}}if (ret == MOUSEROTATEHANDLE::handleRotateNone)return QCursor();float angle = this->rotation() + 22.5;while (angle >= 360.0)angle -= 360;ret = MOUSEROTATEHANDLE(((int)ret + (int)( angle/ 45)) % c_rotate_cursors_size);if (ret == MOUSEROTATEHANDLE::handleRotateNone)ret = MOUSEROTATEHANDLE::handleRotateTopLeft;return m_cursorRotate[ret];
}

设置setRotateStart,表示开始旋转,记录此时的鼠标落点和角度。
设置setRotateEnd,基于上次设置的Start,进行旋转。并且始终保持rotation在[0,360)之间。
注:point是场景坐标。

void CustomRectItem::setRotateStart(const QPointF & point)
{m_mouseRotateStart = point;m_fLastAngle = rotation();
}
void CustomRectItem::setRotateEnd(const QPointF & point)
{QPointF ori = mapToScene(transformOriginPoint());QPointF v1 = m_mouseRotateStart - ori;QPointF v2 = point - ori;float angle = std::atan2f(v2.y(), v2.x()) - std::atan2f(v1.y(), v1.x());angle = m_fLastAngle + angle * 180 / 3.1415926;// angle = [0,360)while (angle < 0.0)angle += 360;while (angle >= 360.0)angle -= 360;setRotation(angle);
}

判断鼠标位置,应为的鼠标状态。

CustomRectItem::MOUSEHANDLE CustomRectItem::handleAt(const QPointF& point)
{for (auto it : m_handles){if (it.second.contains(point))return it.first;}return MOUSEHANDLE::handleNone;
}

调整大小

void CustomRectItem::interactiveResize(const QPointF & mousePos)
{auto offset = c_handle_size + c_handle_space;auto bRect = boundingRect();auto rr = this->rect();auto diff = QPointF(0, 0);prepareGeometryChange();if (m_bhandleSelected == MOUSEHANDLE::handleTopLeft){auto fromX = m_mousePressRect.left();auto fromY = m_mousePressRect.top();auto toX = fromX + mousePos.x() - m_mousePressRect.x();auto toY = fromY + mousePos.y() - m_mousePressRect.y();if (!(toX - fromX >= rr.width() || toY - fromY >= rr.height())){diff.setX(toX - fromX);diff.setY(toY - fromY);bRect.setLeft(toX);bRect.setTop(toY);rr.setLeft(bRect.left() + offset);rr.setTop(bRect.top() + offset);this->setRect(rr);}        }else if (m_bhandleSelected == MOUSEHANDLE::handleTopMiddle){auto fromY = m_mousePressRect.top();auto toY = fromY + mousePos.y() - m_mousePressPos.y();if (!(toY - fromY >= rr.height())){diff.setY(toY - fromY);bRect.setTop(toY);rr.setTop(bRect.top() + offset);this->setRect(rr);} }else if (m_bhandleSelected == MOUSEHANDLE::handleTopRight){auto fromX = m_mousePressRect.right();auto fromY = m_mousePressRect.top();auto toX = fromX + mousePos.x() - m_mousePressPos.x();auto toY = fromY + mousePos.y() - m_mousePressPos.y();if (!(fromX - toX >= rr.width() || toY - fromY >= rr.height())){diff.setX(toX - fromX);diff.setY(toY - fromY);bRect.setRight(toX);bRect.setTop(toY);rr.setRight(bRect.right() - offset);rr.setTop(bRect.top() + offset);this->setRect(rr);}}else if (m_bhandleSelected == MOUSEHANDLE::handleMiddleLeft){auto fromX = m_mousePressRect.left();auto toX = fromX + mousePos.x() - m_mousePressPos.x();if (!(toX - fromX >= rr.width())){diff.setX(toX - fromX);bRect.setLeft(toX);rr.setLeft(bRect.left() + offset);this->setRect(rr);}        }else if (m_bhandleSelected == MOUSEHANDLE::handleMiddleRight){auto fromX = m_mousePressRect.right();auto toX = fromX + mousePos.x() - m_mousePressPos.x();if (!(fromX - toX >= rr.width())){diff.setX(toX - fromX);bRect.setRight(toX);rr.setRight(bRect.right() - offset);this->setRect(rr);}}else if (m_bhandleSelected == MOUSEHANDLE::handleBottomLeft){auto fromX = m_mousePressRect.left();auto fromY = m_mousePressRect.bottom();auto toX = fromX + mousePos.x() - m_mousePressPos.x();auto toY = fromY + mousePos.y() - m_mousePressPos.y();if (!(toX - fromX >= rr.width() || fromY - toY >= rr.height())){diff.setX(toX - fromX);diff.setY(toY - fromY);bRect.setLeft(toX);bRect.setBottom(toY);rr.setLeft(bRect.left() + offset);rr.setBottom(bRect.bottom() - offset);this->setRect(rr);}  }else if (m_bhandleSelected == MOUSEHANDLE::handleBottomMiddle){auto fromY = m_mousePressRect.bottom();auto toY = fromY + mousePos.y() - m_mousePressPos.y();if (!(fromY - toY >= rr.height())){diff.setY(toY - fromY);bRect.setBottom(toY);rr.setBottom(bRect.bottom() - offset);this->setRect(rr);}}else if (m_bhandleSelected == MOUSEHANDLE::handleBottomRight){auto fromX = m_mousePressRect.right();auto fromY = m_mousePressRect.bottom();auto toX = fromX + mousePos.x() - m_mousePressPos.x();auto toY = fromY + mousePos.y() - m_mousePressPos.y();if (!(fromX - toX >= rr.width() || fromY - toY >= rr.height())){diff.setX(toX - fromX);diff.setY(toY - fromY);bRect.setRight(toX);bRect.setBottom(toY);rr.setRight(bRect.right() - offset);rr.setBottom(bRect.bottom() - offset);this->setRect(rr);}}updateHandlesPos();
}

简单的求两点距离平方的函数。因为这不属于这个类的附属功能,所以没有开放。当然,声明为static private会更好。

float CustomRectItem::getLength2(const QPointF & point1, const QPointF & point2)
{return (point1.x() - point2.x()) * (point1.x() - point2.x()) + (point1.y() - point2.y()) * (point1.y() - point2.y());
}

使用实例

#pragma once#include <QtWidgets/QWidget>
#include <QGraphicsView>
#include "CustomRectItem.h"
#include "ui_QtGuiApplication4.h"class QtGuiApplication4 : public QGraphicsView
{Q_OBJECTpublic:QtGuiApplication4(QWidget *parent = Q_NULLPTR);void mouseMoveEvent(QMouseEvent* event) override;void mousePressEvent(QMouseEvent* event) override;void mouseReleaseEvent(QMouseEvent* event) override;private:// the length2 with point1 and point2float getLength2(const QPointF& point1, const QPointF& point2);private:Ui::QtGuiApplication4Class ui;QGraphicsScene* m_scene;CustomRectItem* m_rect;volatile bool m_bTurn;
};
#include "QtGuiApplication4.h"
#include <QDebug>
#include <QMouseEvent>
#include <QTimer>
#include <QBitmap>QtGuiApplication4::QtGuiApplication4(QWidget *parent): QGraphicsView(parent), m_rect(nullptr), m_scene(nullptr), m_bTurn(false)
{ui.setupUi(this);m_scene = new QGraphicsScene();setScene(m_scene);resize(400, 400);QTimer::singleShot(1000, [this]() {m_rect = new CustomRectItem();m_rect->setPos(50, 50);m_scene->addItem(m_rect);m_rect->setRect(0, 0, 50, 50);m_rect->setTransformOriginPoint(25, 25);m_rect->setRotation(45);});
}void QtGuiApplication4::mouseMoveEvent(QMouseEvent * event)
{if (m_bTurn != true){QCursor cursor = m_rect->getRotateCursor(mapToScene(event->pos()));if (!cursor.pixmap().isNull()){viewport()->setCursor(cursor);}else if (!m_rect->isHover()){viewport()->setCursor(Qt::ArrowCursor);}}else{m_rect->setRotateEnd(mapToScene(event->pos()));}QGraphicsView::mouseMoveEvent(event);
}void QtGuiApplication4::mousePressEvent(QMouseEvent * event)
{if (!m_rect->getRotateCursor(mapToScene(event->pos())).pixmap().isNull()){m_rect->setRotateStart(mapToScene(event->pos()));m_bTurn = true;}QGraphicsView::mousePressEvent(event);
}void QtGuiApplication4::mouseReleaseEvent(QMouseEvent * event)
{if (true == m_bTurn){m_bTurn = false;}QGraphicsView::mouseReleaseEvent(event);
}float QtGuiApplication4::getLength2(const QPointF & point1, const QPointF & point2)
{return (point1.x() - point2.x()) * (point1.x() - point2.x()) + (point1.y() - point2.y()) * (point1.y() - point2.y());
}

QGraphicsRectItem美观实现缩放,旋转,平移相关推荐

  1. 【J2me3D系列学习文章之三】(立即模式)对立方体进行变换操作-旋转、缩放、平移...

     本文源地址:http://blog.csdn.net/xiaominghimi/archive/2010/12/09/6064367.aspx  Himi  原创, 转载请注明! 谢谢. 上一篇文章 ...

  2. qgraphicsview鼠标移动图片_交互式QGraphicsView(平移/缩放/旋转)-阿里云开发者社区...

    简述 Graphics View提供了一个平台用于大量自定义 2D 图元的管理与交互框架包括一个事件传播架构支持场景 Scene 中的图元 Item 进行精确的双精度交互功能.Item 可以处理键盘事 ...

  3. java线段的平移和旋转,几何变换(旋转、缩放、平移)

    几何变换(旋转.缩放.平移) 创建场景中的三维模型往往需要设置显示大小.位置.角度,three.js提供了一系列网格模型对象的几何变换方法,从WebGL的角度看,旋转.缩放.平移对应的都是模型变换矩阵 ...

  4. 【工作需要】CAD+VBA 实现图块的旋转平移缩放和拼接

    CAD+VBA 实现图块的旋转平移缩放和拼接 前言 一.需求 二.实现步骤 1.识别文件中的正确的坐标信息 2.选择图块上的角点,计算正确坐标信息与正确角点坐标之间的平移旋转参数,并进行平移旋转,加入 ...

  5. 数据增广:旋转,缩放,平移以及错切

    在深度学习(图像领域)中,为了提升训练样本数量数据增广是非常常见的手段.比如: 随机水平翻转 随机色调(H).饱和度(S).明度(V)调整 随机旋转,缩放,平移以及错切 还有近几年常用的mixup,m ...

  6. PAOGD个人作业3——OpenGL,实现模型自身的旋转,平移,缩放

    中山大学数据科学与计算机学院本科生实验报告 (2019年春季学期) 课程名称 PAOGD 任课老师 郑贵锋 年级 16 专业(方向) 软件工程(计算机应用方向) 学号 16340132 姓名 梁颖霖 ...

  7. openGL-读取off、stl、obj文件并旋转平移缩放操作

    说明 很多朋友反馈,加载完毕后是一片空白-不用担心.我认为你很大程度上已经配置成功.这时候你可以试一试点击数字1.2.3进行查看. 此外我建议你使用点面数目规模较小的模型例如bunny等而不是使用ki ...

  8. [Python从零到壹] 三十八.图像处理基础篇之图像几何变换(平移缩放旋转)

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  9. 【Unity3D】3D 视图操作 ( 视图基本元素 | 导航器 | 栅格 | 天空盒 | 3D 视图操作 | 视图旋转 | 视图缩放 | 视图平移 | 导航器操作 | 恢复方向 | 顶、右、前视图 )

    文章目录 一.3D 视图基本元素 1.导航器 Gizmo 2.栅格 Grid 3.天空盒 Skybox 二.3D 视图操作 1.视图旋转 2.视图缩放 3.视图平移 三.导航器操作 1.恢复方向 2. ...

最新文章

  1. LeetCode——Rotate Image(二维数组顺时针旋转90度)
  2. 解决SQL Server管理器无法连接远程数据库Error: 1326错误
  3. input上传文件夹第二次时删除第一次_Web端非常有用的一个文件上传插件——FilePond...
  4. 面试mysql中怎么创建索引_阿里面试:MySQL如何设计索引更高效?
  5. Oracle查询锁表以及杀会话或系统进程来解除锁表操作
  6. 【Qt】QModbusDeviceIdentification类
  7. 配置解决中文乱码的过滤器
  8. 【ES11(2020)】Promise 扩展 allSettled()
  9. MySQL(三) —— 约束以及修改数据表
  10. 百度又要开放哪些无人车新能力?“老司机”Apollo3.5要来了,市中心开车无压力...
  11. 08.为什么要使用lombok,它解决了什么问题?
  12. Android集成百度语音识别API
  13. excel VB代码
  14. MySQL服务 - 客户端工具mysql及mysqladmin使用介绍
  15. html重置css样式,css样式重置 移动端适配
  16. 电商一定是一元化结构
  17. web前端响应式设计总结
  18. XMUTOJ-默罕默德的炸弹
  19. 网页服务器修复,网页被劫持,跳转发布网修复方法 看完就明白
  20. Python分布式通用爬虫(4)

热门文章

  1. Blake算法的流程
  2. nibabel库 - 初步
  3. 重磅!腾讯优图17篇论文入选ICCV 2021
  4. 解决ssh: no common algorithm for key exchange; client offered: [curve25519-sha256@libssh.org ecdh
  5. 求职-如何选择offer
  6. 勇士屠熊,绿军射鹿,夕阳西下,人群散尽,唯有烈火燎原势不可挡
  7. React-Native with LeanCloud 构建实时聊天软件
  8. 树莓派4b之初学者入门人脸识别(手把手完整版)
  9. 【Web安全笔记】之【7.0 防御技术】
  10. 关于智能家居开源平台(如Home Assistant)——智汀家庭云,你需要知道的是