前言
Graphics View提供了一个surface,用于管理大量定制的2D图形项并与之交互,还提供了一个View小部件,用于可视化项目,并支持缩放和旋转.
该框架包含一个事件传播框架,该架构允许对场景中的项目提供精确的双精度交互功能.项目可以处理按键事件,鼠标按下,移动,释放和双击事件,还可以跟踪鼠标移动。
Graphics View使用BSP(二进制空间划分)树来提供非常快速的项目发现,因此,它可以实时地可视化大型场景,甚至是数百万个项目.
如何实现教具直尺
- 需要先设计所有教具的基类
- 继承基类设计直尺教具
(AbsTeachingTool.h)基类设计
#ifndef ABSTEAHINGTOOL_H
#define ABSTEAHINGTOOL_H
#include <QObject>
#include <QApplication>
#include <QColor>
#include <QRectF>
#include <functional>
class QGraphicsSvgItem;
class QGraphicsView;
class QGraphicsScene;
// 传入当前的场景返回视图
typedef std::function<QGraphicsView*(QGraphicsScene*)> CurrentViewFunc;
class AbsTeachingTool : public QObject
{
Q_OBJECT
Q_ENUMS(TEAHINGTOOLSTATE)
public:
enum TEAHINGTOOLSTATE {
TEAHINGTOOL_STATE_NONE, // 教具状态(无状态)
TEAHINGTOOL_STATE_MOVE, // 教具状态(移动)
TEAHINGTOOL_STATE_RESIZE_ONE, // 教具状态(改变大小-1)
TEAHINGTOOL_STATE_RESIZE_TWO, // 教具状态(改变大小-2)
TEAHINGTOOL_STATE_RESIZE_THREE, // 教具状态(改变大小-3)
TEANINGTOOL_STATE_RESIZE_FOUR, // 教具状态(改变大小-4)
TEAHINGTOOL_STATE_ROTATE, // 教具状态(旋转)
TEAHINGTOOL_STATE_CLOSE, // 教具状态(关闭)
TEAHINGTOOL_STATE_REST, // 教具状态(复位)
TEAHINGTOOL_STATE_PEN, // 教具状态(画图状态,画线)
TEAHINGTOOL_STATE_DORMANCY // 启动该状态为不响应任何鼠标事件
};
AbsTeachingTool() {
m_yState = TEAHINGTOOL_STATE_NONE;
SetRect(QRectF(0,0,0,0));
SetMinRect(QRectF(0,0,0,0));
SetMaxRect(QRectF(0,0,0,0));
PenWidthF = 1;
CurrentView = nullptr;
}
~AbsTeachingTool() {}
inline QString CurrentPath( void ) const {
return QCoreApplication::applicationDirPath();
}
inline void SetRect(QRectF rect) {
m_yRectF = rect;
}
inline QRectF Rect( void ) const {
return m_yRectF;
}
inline void SetMinRect(QRectF rect) {
m_yMinRectF = rect;
}
inline QRectF MinRect( void ) const {
return m_yMinRectF;
}
inline void SetMaxRect(QRectF rect) {
m_yMaxRectF = rect;
}
inline QRectF MaxRect( void ) const {
return m_yMaxRectF;
}
inline void SetPressPos(QPointF pos) {
m_yPressPos = pos;
}
inline QPointF PressPos( void ) const {
return m_yPressPos;
}
inline void SetOriginPos(QPointF pos) {
m_yOriginPos = pos;
}
inline QPointF OriginPos( void ) const {
return m_yOriginPos;
}
inline void SetPenState(qreal penwidth) {
PenWidthF = penwidth;
m_yState = TEAHINGTOOL_STATE_PEN;
}
inline void SetPenState(int penwidth) {
PenWidthF = static_cast<qreal>(penwidth);
m_yState = TEAHINGTOOL_STATE_PEN;
}
inline void SetState( TEAHINGTOOLSTATE state ) {
m_yState = state;
}
inline TEAHINGTOOLSTATE GetState( void ) const {
return m_yState;
}
inline void SetCurrentView( CurrentViewFunc func )
{
CurrentView = func;
}
inline void SetPenWidth(qreal penwidth) {
PenWidthF = penwidth;
}
inline qreal PenWidth( void ) const {
return PenWidthF;
}
protected:
virtual void InitProperty( void ) = 0;
virtual void UpdateResizeCursor( void ) = 0;
virtual void SetCursor(QCursor cursor) = 0;
CurrentViewFunc CurrentView;
signals:
// 控件关闭信号
void Closeed();
// 鼠标移入信号
void HoverEntered();
// 鼠标移出信号
void HoverLeaveed();
// 画线起始点
void LineStartPos(QPointF);
// 画线更新结束点
void LineUpdatePos(QPointF);
// 退出画线
void LineEnd();
// 画圆起始点
void ArcStartPos(QPointF);
// 画圆更新结束点
void ArcUpdatePos(QPointF);
// 退出画圆
void ArcEndPos();
/**
* @brief ArcStart 开始画弧
* @param QRectF
*
* QRectF(const QRect &rectangle)
* QRectF(qreal x, qreal y, qreal width, qreal height)
* QRectF(const QPointF &topLeft, const QPointF &bottomRight)
* QRectF(const QPointF &topLeft, const QSizeF &size)
*
* 本接口与drawArc一样
* @param startAngle
* 范围: 0 --- 360
*/
void ArcStart(QRectF, qreal startAngle);
/**
* @brief ArcUpdate 更新圆弧的角度
* @param updateAngle
* 范围: -720 --- 720
* startAngle+updateAngle 为最终旋转后的角度
*/
void ArcUpdate(qreal updateAngle);
/**
* @brief ArcEnd 退出画圆弧
*/
void ArcEnd();
private:
TEAHINGTOOLSTATE m_yState;
QRectF m_yRectF;
QRectF m_yMinRectF;
QRectF m_yMaxRectF;
QPointF m_yPressPos;
QPointF m_yOriginPos; // 原点坐标
qreal PenWidthF;
};
#endif // ABSTEAHINGTOOL_H
直尺类设计 (TeachingToolRuler.h)
#ifndef TEAHINGTOOLRULER_H
#define TEAHINGTOOLRULER_H
#include "AbsTeachingTool.h"
#include <QGraphicsItem>
class TeachingToolRuler : public AbsTeachingTool, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
TeachingToolRuler();
~TeachingToolRuler();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
QPainterPath shape() const;
void SetRulerBorderRadius(int radius);
void SetRulerBackgroundColor(QColor color);
void SetRulerBorderColor(QColor color);
void SetRulerScaleTextColor(QColor color);
void SetRulerScaleColor(QColor color);
void SetRulerRotateColor(QColor color);
void SetCloseButtonSvg(QString svg);
void SetResizeButtonSvg(QString svg);
void SetRotateButtonSvg(QString svg);
private:
// 传入画板的画线状态
enum DRAWLINE {
TOP,
BOTTOM
};
void InitProperty();
void UpdateResizeCursor();
void SetCursor(QCursor cursor);
QRectF CloseButtonRect() const;
QRectF ResizeButtonRect() const;
QRectF RotateButtonRect() const;
// 绘制本体
void PaintBody(QPainter *painter);
// 绘制按钮
void PaintButton( void );
// 刻度绘制
void PaintScale(QPainter *painter);
// 绘制旋转状态中的弧线
void PaintRotate(QPainter *painter);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
private:
// svg文件
QString CloseButtonSvg;
QString ResizeButtonSvg;
QString RotateButtonSvg;
QGraphicsSvgItem *m_pCloseButton = nullptr; // 关闭按钮
QGraphicsSvgItem *m_pResizeButton = nullptr; // 改变大小按钮
QGraphicsSvgItem *m_pRotateButton = nullptr; // 旋转按钮
// 颜色样式
int RulerBorderRadius;
QColor RulerBackgroundColor;
QColor RulerBorderColor;
QColor RulerScaleTextColor;
QColor RulerScaleColor;
QColor RulerRotateColor;
QCursor RotateCursor; // 旋转时鼠标显示的图标
QCursor DrawLineRulerCursor; // 与白板交互时绘制功能,鼠标显示图标
QCursor ResizeCursor; // 改变大小显示的图标
QCursor MoveCursor; // 移动时显示的图标
QCursor CloseCursor; // 关闭鼠标的图标
DRAWLINE DrawLineState;
};
#endif // TEAHINGTOOLRULER_H
直尺类实现 (TeachingToolRuler.cpp)
#include "TeachingToolRuler.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsSvgItem>
#include <QPainter>
#include <QGraphicsSceneHoverEvent>
#include <QCursor>
#include <QDebug>
#include "CatMath.h"
TeachingToolRuler::TeachingToolRuler()
{
InitProperty();
}
TeachingToolRuler::~TeachingToolRuler()
{
}
QRectF TeachingToolRuler::boundingRect() const
{
return Rect();
}
void TeachingToolRuler::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
// 打开抗锯齿
painter->setRenderHint(QPainter::Antialiasing, true);
// 平滑的像素图转换算法
painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
// 指示引擎应尽可能消除文本的别名
painter->setRenderHint(QPainter::TextAntialiasing, true);
painter->save();
// [0] 绘制直尺本体
PaintBody(painter);
// [1] 按钮绘制
PaintButton();
// [3] 刻度绘制
PaintScale(painter);
// [4] 旋转状态绘制
if(GetState() == TEAHINGTOOL_STATE_ROTATE)
{
PaintRotate(painter);
}
painter->restore();
}
// 以局部坐标的QPainterPath返回该项的形状。这个形状被用于很多方面,包括碰撞检测,碰撞测试,以及QGraphicsScene::items()函数。
QPainterPath TeachingToolRuler::shape() const
{
QPainterPath path;
path.addRoundedRect(Rect(), RulerBorderRadius, RulerBorderRadius);
return path;
}
void TeachingToolRuler::SetRulerBorderRadius(int radius)
{
RulerBorderRadius = radius;
}
void TeachingToolRuler::SetRulerBackgroundColor(QColor color)
{
RulerBackgroundColor = color;
}
void TeachingToolRuler::SetRulerBorderColor(QColor color)
{
RulerBorderColor = color;
}
void TeachingToolRuler::SetRulerScaleTextColor(QColor color)
{
RulerScaleTextColor = color;
}
void TeachingToolRuler::SetRulerScaleColor(QColor color)
{
RulerScaleColor = color;
}
void TeachingToolRuler::SetRulerRotateColor(QColor color)
{
RulerRotateColor = color;
}
void TeachingToolRuler::SetCloseButtonSvg(QString svg)
{
if(CloseButtonSvg != svg)
{
if(m_pCloseButton != nullptr)
{
m_pCloseButton->deleteLater();
m_pCloseButton = nullptr;
}
CloseButtonSvg = svg;
m_pCloseButton = new QGraphicsSvgItem(svg, this);
prepareGeometryChange();
}
}
void TeachingToolRuler::SetResizeButtonSvg(QString svg)
{
if(ResizeButtonSvg != svg)
{
if(m_pResizeButton != nullptr)
{
m_pResizeButton->deleteLater();
m_pResizeButton = nullptr;
}
ResizeButtonSvg = svg;
m_pResizeButton = new QGraphicsSvgItem(svg, this);
prepareGeometryChange();
}
}
void TeachingToolRuler::SetRotateButtonSvg(QString svg)
{
if(RotateButtonSvg != svg)
{
if(m_pRotateButton != nullptr)
{
m_pRotateButton->deleteLater();
m_pRotateButton = nullptr;
}
RotateButtonSvg = svg;
m_pRotateButton = new QGraphicsSvgItem(svg, this);
prepareGeometryChange();
}
}
void TeachingToolRuler::InitProperty()
{
// 初始化参数
RotateCursor = QCursor(QPixmap(":/TeachingTool/png/rotate.png"), 16, 16);
DrawLineRulerCursor = QCursor(QPixmap(":/TeachingTool/png/drawRulerLine.png"), 5, 16);
ResizeCursor = QCursor(QPixmap(":/TeachingTool/png/resize.png"), 16, 16);
MoveCursor = QCursor(Qt::SizeAllCursor);
CloseCursor = QCursor(Qt::ArrowCursor);
SetRect(QRectF(0, 0, CatMath::CmtoPx(21), 96));
SetMinRect(QRectF(0, 0, CatMath::CmtoPx(5), 96));
SetMaxRect(QRectF(0, 0, CatMath::CmtoPx(1010), 96));
SetRulerBorderRadius(6);
SetRulerBackgroundColor(QColor(255, 255, 255, 204));
SetRulerBorderColor(QColor(102, 102, 102));
SetRulerScaleTextColor(RulerBorderColor);
SetRulerScaleColor(RulerScaleTextColor);
SetRulerRotateColor(RulerScaleColor);
//qDebug() << CurrentPath();
setAcceptHoverEvents(true);
SetResizeButtonSvg(":/TeachingTool/svg/resizeRuler.svg");
m_pResizeButton->setVisible(false);
SetCloseButtonSvg(":/TeachingTool/svg/closeTool.svg");
m_pCloseButton->setVisible(false);
SetRotateButtonSvg(":/TeachingTool/svg/rotateTool.svg");
m_pRotateButton->setVisible(false);
// 设置直尺原点坐标,鼠标选择后旋转的坐标
SetOriginPos(QPointF(10,0));
setTransformOriginPoint(OriginPos());
UpdateResizeCursor();
}
void TeachingToolRuler::UpdateResizeCursor()
{
QPixmap pix(":/TeachingTool/png/resize.png");
QTransform tr;
// 设置改变直尺大小鼠标图标的旋转角度
tr.rotate(this->rotation());
ResizeCursor = QCursor(pix.transformed(tr, Qt::SmoothTransformation), pix.width() / 2, pix.height() / 2);
}
// 这里是一个关键, 鼠标样式可以影响范围,如果我们直接setCursor是改变了整个软件的鼠标样式,如果我们获取当前视图下的setCursor则鼠标样式改变的影响只在当前的view视图中。
void TeachingToolRuler::SetCursor(QCursor cursor)
{
if(CurrentView != nullptr)
{
QGraphicsView *view = CurrentView(this->scene());
view->setCursor(cursor);
} else {
setCursor(cursor);
}
}
QRectF TeachingToolRuler::CloseButtonRect() const
{
QPixmap pixmap(CloseButtonSvg);
QSizeF size(pixmap.rect().width(),
pixmap.rect().height());
QPointF topleft(size.width()/2,
(Rect().height() - size.height())/2);
return QRectF(topleft, size);
}
QRectF TeachingToolRuler::ResizeButtonRect() const
{
QPixmap pixmap(ResizeButtonSvg);
QSizeF size(pixmap.rect().width(),
pixmap.rect().height());
QPointF topleft(Rect().width() - size.width(),
0);
return QRectF(topleft, size);
}
QRectF TeachingToolRuler::RotateButtonRect() const
{
QPixmap pixmap(RotateButtonSvg);
QSizeF size(pixmap.rect().width(),
pixmap.rect().height());
QPointF topleft(ResizeButtonRect().x() - size.width() - size.width()/2,
(Rect().height() - size.height())/2);
return QRectF(topleft, size);
}
void TeachingToolRuler::PaintBody(QPainter *painter)
{
QPen pen = painter->pen();
pen.setColor(RulerBorderColor);
painter->setPen(pen);
painter->setBrush(QBrush(RulerBackgroundColor));
painter->drawRoundedRect(QRectF(QPointF(0,0), Rect().size()), RulerBorderRadius, RulerBorderRadius);
}
void TeachingToolRuler::PaintButton()
{
// [1] resize按钮
m_pResizeButton->setPos(ResizeButtonRect().x(), ResizeButtonRect().y());
// [2] close按钮
m_pCloseButton->setPos(CloseButtonRect().x(), CloseButtonRect().y());
// [3] rotate按钮
m_pRotateButton->setPos(RotateButtonRect().x(), RotateButtonRect().y());
}
void TeachingToolRuler::PaintScale(QPainter *painter)
{
QFont font = painter->font();
font.setPixelSize(14);
QPen pen = painter->pen();
pen.setColor(RulerScaleColor);
painter->setPen(pen);
painter->setFont(font);
int scalevalue = 0;
int value = 0;
qreal scalelocation = 10;
qreal longscaleheight = CatMath::CmtoPx(1)/2;
qreal scaleheight = longscaleheight*(2.0/3.0);
qreal shortscaleheight = scaleheight/2;
QFontMetrics fm(font);
while(scalelocation < Rect().width() - 10)
{
if(scalevalue == 0)
{
int pixelsWide = fm.horizontalAdvance(QString::number(value));
painter->drawLine(QLineF(scalelocation, 0, scalelocation, longscaleheight));
// 绘制刻度文字
painter->drawText(QPointF(scalelocation - pixelsWide/2 , longscaleheight + 14 + 1),
QString::number(value));
painter->drawLine(QLineF(scalelocation, Rect().height(),
scalelocation, Rect().height() - longscaleheight));
// 绘制刻度文字
painter->drawText(QPointF(scalelocation - pixelsWide/2 ,
Rect().height() - longscaleheight - 5),
QString::number(value));
} else if(scalevalue == 5)
{
painter->drawLine(QLineF(scalelocation, 0, scalelocation, scaleheight));
painter->drawLine(QLineF(scalelocation, Rect().height(), scalelocation,
Rect().height() - scaleheight));
} else {
painter->drawLine(QLineF(scalelocation, 0, scalelocation, shortscaleheight));
painter->drawLine(QLineF(scalelocation, Rect().height(), scalelocation,
Rect().height() - shortscaleheight));
}
scalevalue += 1;
if(scalevalue == 10)
{
value++;
scalevalue = 0;
}
scalelocation += CatMath::CmtoPx(0.1);
}
}
void TeachingToolRuler::PaintRotate(QPainter *painter)
{
QPen pen = painter->pen();
pen.setColor(RulerRotateColor);
painter->setPen(pen);
qreal longscaleheight = CatMath::CmtoPx(1);
painter->drawArc(QRectF(-(longscaleheight/2) + 10, -(longscaleheight/2), longscaleheight, longscaleheight), 0 * 16, -90 * 16);
}
void TeachingToolRuler::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// 如果鼠标是左键按下,并且教具处于活动状态下
if(event->button() == Qt::LeftButton && GetState() != TEAHINGTOOL_STATE_DORMANCY)
{
// 如果教具不处于画线状态下
if(GetState() != TEAHINGTOOL_STATE_PEN)
{
if(ResizeButtonRect().contains(event->pos()))
{
// 如果是改变大小按钮按下
SetState(TEAHINGTOOL_STATE_RESIZE_ONE);
m_pRotateButton->setVisible(false);
m_pCloseButton->setVisible(false);
SetPressPos(event->pos());
} else if(RotateButtonRect().contains(event->pos()))
{
// 如果旋转按钮被按下
SetState(TEAHINGTOOL_STATE_ROTATE);
m_pResizeButton->setVisible(false);
m_pCloseButton->setVisible(false);
SetPressPos(event->pos());
} else if(CloseButtonRect().contains(event->pos()))
{
// 如果关闭按钮被按下
SetState(TEAHINGTOOL_STATE_CLOSE);
m_pResizeButton->setVisible(false);
m_pRotateButton->setVisible(false);
} else if(boundingRect().contains(event->pos()))
{
// 如果本体被按下
SetState(TEAHINGTOOL_STATE_MOVE);
m_pCloseButton->setVisible(false);
m_pResizeButton->setVisible(false);
m_pRotateButton->setVisible(false);
SetPressPos(event->scenePos());
}
} else {
// 先获取scentPos,当前在画线状态下
QPointF pos = event->pos();
QPointF sceneTopPenPos = CatMath::PointCoordinatesOnACircle(this->scenePos(), PenWidth()/2, this->rotation() + 270);
QPointF sceneBottompos = CatMath::PointCoordinatesOnACircle(this->scenePos(), Rect().height() + PenWidth()/2, this->rotation() + 90);
QPointF scentTopMinPos = CatMath::PointCoordinatesOnACircle(sceneTopPenPos, OriginPos().x(), this->rotation());
QPointF scentTopMaxPos = CatMath::PointCoordinatesOnACircle(sceneTopPenPos, Rect().width() - 10, this->rotation());
QPointF scentBottomMinPos = CatMath::PointCoordinatesOnACircle(sceneBottompos, OriginPos().x(), this->rotation());
QPointF scentBottomMaxPos = CatMath::PointCoordinatesOnACircle(sceneBottompos, Rect().width() - 10, this->rotation());
QPointF StartPos;
if(pos.ry() > Rect().height()/2.0)
{
DrawLineState = BOTTOM;
} else {
DrawLineState = TOP;
}
switch (DrawLineState) {
case BOTTOM:{
//qDebug() << "BOTTOM";
if(pos.rx() < 10.0)
{
StartPos = scentBottomMinPos;
} else if(pos.rx() > Rect().width() - 10.0)
{
StartPos = scentBottomMaxPos;
} else {
QPointF scentMousePos = CatMath::PointCoordinatesOnACircle(sceneBottompos,
pos.x(), this->rotation());
StartPos = scentMousePos;
}
break;
}
case TOP:{
//qDebug() << "TOP";
if(pos.rx() < 10.0)
{
StartPos = scentTopMinPos;
} else if(pos.rx() > Rect().width() - 10.0)
{
StartPos = scentTopMaxPos;
} else {
QPointF scentMousePos = CatMath::PointCoordinatesOnACircle(sceneTopPenPos,
pos.x(), this->rotation());
StartPos = scentMousePos;
}
break;
}
}
emit LineStartPos(StartPos);
}
}
}
void TeachingToolRuler::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(GetState() != TEAHINGTOOL_STATE_DORMANCY)
{
switch(GetState())
{
case TEAHINGTOOL_STATE_MOVE:{
QPointF pos = event->scenePos();
QPointF move = pos - PressPos();
this->moveBy(move.rx(), move.ry());
SetPressPos(pos);
break;
}
case TEAHINGTOOL_STATE_RESIZE_ONE:{
QPointF pos = event->pos();
QPointF size = pos - PressPos();
qreal width = Rect().width() + size.rx();
if(width < MinRect().width())
{
SetRect(MinRect());
} else if(width >MaxRect().width())
{
SetRect(MaxRect());
} else {
SetRect(QRectF(Rect().x(), Rect().y(), width, Rect().height()));
}
SetPressPos(pos);
break;
}
case TEAHINGTOOL_STATE_ROTATE:{
QPointF pos = event->pos();
QVector2D Start = QVector2D(PressPos() - QPointF(10.0, 0.0));
QVector2D End = QVector2D(pos - QPointF(10.0, 0.0));
qreal angle = 0.0;
qreal angleEnd = CatMath::DegreeAngle(End);
qreal angleStart = CatMath::DegreeAngle(Start);
angle = angleEnd - angleStart + rotation();
angle = CatMath::AngleJudge(angle);
setRotation(angle);
UpdateResizeCursor();
break;
}
case TEAHINGTOOL_STATE_PEN:{
QPointF pos = event->pos();
QPointF sceneTopPenPos = CatMath::PointCoordinatesOnACircle(this->scenePos(), PenWidth()/2, this->rotation() + 270);
QPointF sceneBottompos = CatMath::PointCoordinatesOnACircle(this->scenePos(), Rect().height() + PenWidth()/2, this->rotation() + 90);
QPointF scentTopMinPos = CatMath::PointCoordinatesOnACircle(sceneTopPenPos, OriginPos().x(), this->rotation());
QPointF scentTopMaxPos = CatMath::PointCoordinatesOnACircle(sceneTopPenPos, Rect().width() - 10, this->rotation());
QPointF scentBottomMinPos = CatMath::PointCoordinatesOnACircle(sceneBottompos, OriginPos().x(), this->rotation());
QPointF scentBottomMaxPos = CatMath::PointCoordinatesOnACircle(sceneBottompos, Rect().width() - 10, this->rotation());
QPointF UpdatePos;
switch (DrawLineState) {
case BOTTOM:{
if(pos.rx() < 10.0)
{
UpdatePos = scentBottomMinPos;
} else if(pos.rx() > Rect().width() - 10.0)
{
UpdatePos = scentBottomMaxPos;
} else {
QPointF scentMousePos = CatMath::PointCoordinatesOnACircle(sceneBottompos,
pos.x(), this->rotation());
UpdatePos = scentMousePos;
}
break;
}
case TOP:{
if(pos.rx() < 10.0)
{
UpdatePos = scentTopMinPos;
} else if(pos.rx() > Rect().width() - 10.0)
{
UpdatePos = scentTopMaxPos;
} else {
QPointF scentMousePos = CatMath::PointCoordinatesOnACircle(sceneTopPenPos,
pos.x(), this->rotation());
UpdatePos = scentMousePos;
}
break;
}
}
emit LineUpdatePos(UpdatePos);
break;
}
default: {
break;
}
}
prepareGeometryChange();
}
}
void TeachingToolRuler::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event)
if(GetState() != TEAHINGTOOL_STATE_DORMANCY)
{
if(GetState() != TEAHINGTOOL_STATE_PEN)
{
if(GetState() == TEAHINGTOOL_STATE_CLOSE)
{
SetState(TEAHINGTOOL_STATE_NONE);
emit Closeed();
this->deleteLater();
} else {
SetState(TEAHINGTOOL_STATE_NONE);
m_pResizeButton->setVisible(true);
m_pCloseButton->setVisible(true);
m_pRotateButton->setVisible(true);
prepareGeometryChange();
}
} else {
emit LineEnd();
}
}
}
void TeachingToolRuler::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
if(GetState() != TEAHINGTOOL_STATE_DORMANCY)
{
if(GetState() != TEAHINGTOOL_STATE_PEN)
{
if(ResizeButtonRect().contains(event->pos()))
{
SetCursor(ResizeCursor);
} else if(RotateButtonRect().contains(event->pos()))
{
SetCursor(RotateCursor);
} else if(CloseButtonRect().contains(event->pos()))
{
SetCursor(CloseCursor);
} else {
SetCursor(MoveCursor);
}
} else {
SetCursor(DrawLineRulerCursor);
}
}
}
void TeachingToolRuler::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
if(GetState() != TEAHINGTOOL_STATE_DORMANCY)
{
emit HoverEntered();
if(GetState() != TEAHINGTOOL_STATE_PEN)
{
SetCursor(MoveCursor);
m_pResizeButton->setVisible(true);
m_pCloseButton->setVisible(true);
m_pRotateButton->setVisible(true);
} else {
SetCursor(DrawLineRulerCursor);
}
}
}
void TeachingToolRuler::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event)
if(GetState() != TEAHINGTOOL_STATE_DORMANCY)
{
emit HoverLeaveed();
if(GetState() != TEAHINGTOOL_STATE_PEN)
{
SetState(TEAHINGTOOL_STATE_NONE);
m_pResizeButton->setVisible(false);
m_pCloseButton->setVisible(false);
m_pRotateButton->setVisible(false);
}
SetCursor(Qt::ArrowCursor);
}
}
需要用到数学函数 (CatMath.h)
CatMath.h
#ifndef CATMATH_H
#define CATMATH_H
#include <QtGlobal>
#include <QVector2D>
namespace CatMath {
qreal CmtoPx(qreal cm);
qreal PxtoCm(qreal px);
qreal DegreeAngle(QVector2D vector2d);
// 已知圆心,半径,角度,求圆上的点坐标
QPointF PointCoordinatesOnACircle(QPointF centerpoint, qreal r, qreal angle);
// 旋转角度转换,将大于360,与小于0的角度进行极值判断
qreal AngleJudge(qreal angle);
// 勾股定理
qreal PythagoreanTheorem(qreal a, qreal b);
// 计算 靠近A点 角度方法
/*
B____C
| /
|_/
|/
A
*/
// 根据tan算出角度
qreal TanToAngle(qreal bc, qreal ab);
// 根据cos算出角度
qreal CosToAngle(qreal ab, qreal ac);
// 根据sin算出角度
qreal SinToAngle(qreal bc, qreal ac);
QPointF PosMove(QPointF last, QPointF pos);
}
#endif // CATMATH_H
CatMath.cpp
#include "CatMath.h"
#include <QApplication>
#include <QScreen>
#include <QtMath>
#include <math.h>
#include <QDebug>
// 求弧度 180度/π是1弧度对应多少度!
const qreal AnglePerPI = 180.0 / M_PI;
qreal GetDpi()
{
//QGuiApplication::highDpiScaleFactorRoundingPolicy();
return QApplication::primaryScreen()->logicalDotsPerInch();
}
qreal CatMath::CmtoPx(qreal cm)
{
//获取主屏幕分辨率
QScreen *screen = QApplication::primaryScreen();
// 1 英寸的像素
//qreal inchToPx = qreal(1)/GetDpi();
qreal inchToPx = qreal(1.0)/130.0;
// 屏幕宽度
qreal width = static_cast<qreal>(screen->geometry().width());
// 1 英寸=2.54 厘米 WidthToCm为当前屏幕宽度所对应的厘米尺寸
qreal WidthToCm = width * inchToPx * qreal(2.54);
// 换算cm 转 px
qreal px = (cm * width)/WidthToCm;
return px;
}
qreal CatMath::PxtoCm(qreal px)
{
//获取主屏幕分辨率
QScreen *screen = QApplication::primaryScreen();
// 1 英寸的像素
qreal inchToPx = qreal(1)/GetDpi();
// 屏幕宽度
qreal width = static_cast<qreal>(screen->geometry().width());
// 1 英寸=2.54 厘米 WidthToCm为当前屏幕宽度所对应的厘米尺寸
qreal WidthToCm = width * inchToPx * qreal(2.54);
// 换算px 转 cm
qreal cm = (px * WidthToCm)/width;
return cm;
}
qreal CatMath::DegreeAngle(QVector2D vector2d)
{
// qAtan2 返回的是弧度 - 官方文档有误
// qAtan2 * AnglePerPI + 360.0 用度表示反正切值
// fmod 求余
return fmod((qAtan2(static_cast<qreal>(vector2d.y()), static_cast<qreal>(vector2d.x())) * AnglePerPI + 360.0), 360.0);
}
QPointF CatMath::PointCoordinatesOnACircle(QPointF centerpoint, qreal r, qreal angle)
{
QPointF point;
qreal rotate = angle * M_PI / 180.0;
point.setX(centerpoint.rx() + r * qCos(rotate));
point.setY(centerpoint.ry() + r * qSin(rotate));
return point;
}
qreal CatMath::AngleJudge(qreal angle)
{
qreal temp = angle;
if (temp > 360.0)
{
while(1)
{
temp -= 360.0;
if (temp < 360.0) break;
}
}
else if (temp < 0.0)
{
while(1)
{
temp += 360.0;
if (temp > 0.0) break;
}
}
return temp;
}
qreal CatMath::PythagoreanTheorem(qreal a, qreal b)
{
qreal c = 0;
c = qSqrt(qPow(a, 2) + qPow(b, 2));
return c;
}
qreal CatMath::TanToAngle(qreal bc, qreal ab)
{
return qAtan(bc/ab) * 180 / M_PI;
}
qreal CatMath::CosToAngle(qreal ab, qreal ac)
{
return qAcos(ab/ac) * 180 / M_PI;
}
qreal CatMath::SinToAngle(qreal bc, qreal ac)
{
return qAsin(bc/ac) * 180 / M_PI;
}
QPointF CatMath::PosMove(QPointF last, QPointF pos)
{
return QPointF(last.rx() + pos.rx(), last.ry() + pos.ry());
}