在使用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内部坐标完成的放缩,所以旋转并不会影响其效果。所以,你大可以重新实现更好的旋转效果,如果可以的话,也可以分享给我你的想法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | #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[] size const int c_rotate_cursors_size = 9; // MOUSEROTATEHANDLE size const 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 coordinate QCursor getRotateCursor(const QPointF& point); // set point for start rorate // @note point is scene coordinate void setRotateStart(const QPointF& point); // set point for end rorate // @note point is scene coordinate void 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 point2 float 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函数,绘制了选中时的,边角矩形和去掉了选中状态(那种难看的虚线框)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | void CustomRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QStyleOptionGraphicsItem op; if (widget == nullptr) op = *option; else op.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); } } } |
初始化部分,不做介绍。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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() { } |
这部分我也不清楚什么意思。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 的一半。
1 2 3 4 5 | QRectF CustomRectItem::boundingRect() const { auto o = c_handle_size + c_handle_space; return this->rect().adjusted(-o, -o, o, o); } |
m_isHover 表示鼠标是否在item上。当进行放缩时,鼠标可能会出界,导致view捕捉到,并且修改指针形状,通过判断该参数可纠正。
1 2 3 4 5 6 7 8 9 10 11 | 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度时,会有一个看着别扭。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 cursor m_cursor = handleCursors[((int)m_handle + (int)(angle / 45) - 1) % c_handle_cursors_size]; } setCursor(m_cursor); } QGraphicsRectItem::hoverMoveEvent(event); } |
判断鼠标指针的状态,进行调整大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | void CustomRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event) { if (MOUSEHANDLE::handleNone != m_bhandleSelected) interactiveResize(event->pos()); else QGraphicsRectItem::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); } void CustomRectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) { m_bhandleSelected = MOUSEHANDLE::handleNone; m_mousePressPos = QPointF(); m_mousePressRect = QRectF(); this->update(); QGraphicsRectItem::mouseReleaseEvent(event); } |
键盘控制平移的简单实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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); } |
调整四周小矩形的位置和大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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坐标下,计算出距离最近的是哪个小方块,然后再加上旋转角度的偏移量,就得到了应该在视觉上看到的正确的鼠标形状。或许有更方便的实现方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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是场景坐标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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); } |
判断鼠标位置,应为的鼠标状态。
1 2 3 4 5 6 7 8 9 | CustomRectItem::MOUSEHANDLE CustomRectItem::handleAt(const QPointF& point) { for (auto it : m_handles) { if (it.second.contains(point)) return it.first; } return MOUSEHANDLE::handleNone; } |
调整大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | 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会更好。
1 2 3 4 | 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()); } |
使用实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #pragma once #include <QtWidgets/QWidget> #include <QGraphicsView> #include "CustomRectItem.h" #include "ui_QtGuiApplication4.h" class QtGuiApplication4 : public QGraphicsView { Q_OBJECT public: 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 point2 float getLength2(const QPointF& point1, const QPointF& point2); private: Ui::QtGuiApplication4Class ui; QGraphicsScene* m_scene; CustomRectItem* m_rect; volatile bool m_bTurn; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #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()); } |