在使用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[] 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函数,绘制了选中时的,边角矩形和去掉了选中状态(那种难看的虚线框)。
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);
}
}
}
初始化部分,不做介绍。
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 cursor
m_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());
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);
}
<这里前半部分是个重点>
目的是解决有旋转角度的矩形,拉伸之后,再次旋转,旋转中心该仍然为之前坐标,手动设置为中心,会产生漂移的问题。如果不需要解决该问题,可注掉该部分代码。原理参见子章节: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_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;
};
#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());
}