一、效果展示
二、源码分享
PatternPasswordWidget .hpp
cpp
#ifndef PATTERNCODELOCKWIDGET_H
#define PATTERNCODELOCKWIDGET_H
#include <QWidget>
#include <QWidget>
#include <QTimer>
class PatternPasswordWidget : public QWidget
{
Q_OBJECT
public:
PatternPasswordWidget(QWidget *parent = nullptr);
~PatternPasswordWidget()override;
void reset();
int getNumberOfEachRowAndCol() const;
void setNumberOfEachRowAndCol(int newNumberOfEachRowAndCol);
signals:
void inputPasswordOverSignal(QString);
protected:
void paintEvent(QPaintEvent *event)override;
void resizeEvent(QResizeEvent *event) override;
void mouseMoveEvent(QMouseEvent *event)override;
void mousePressEvent(QMouseEvent *event)override;
void mouseReleaseEvent(QMouseEvent *event)override;
void mouseDoubleClickEvent(QMouseEvent *event)override;
private:
void onHoverTimer();
QString getPassWord();
enum class CircularState
{
normal,//正常
hoverOnInnerSamrtCircular//鼠标悬浮在中间的小圆上面
};
enum class PatternCodeLockState
{
notSet,
setting,
setted_valid,//有效
setted_invalid//无效
};
int numberOfEachRowAndCol;
PatternCodeLockState patternCodeLockSetUpState{PatternCodeLockState::notSet};
QList<CircularState> circularStateList;
QList<QRect> smartCircularRectList;
bool isUpdateSmartCircularRect{true};
QTimer hoverTimer;
int radiu;
int lastHoverIndex{-1};
int currentchangeLength;
bool mouseInSomeSmartCircular{false};
QList<int> setList;
QPoint settingMousPos;
};
#endif // PATTERNCODELOCKWIDGET_H
PatternPasswordWidget .cpp
cpp
#include "patternPasswordWidget.h"
#include <QPainter>
#include <QPainterPath>
#include <QPaintEvent>
PatternPasswordWidget::PatternPasswordWidget(QWidget *parent)
: QWidget(parent)
{
setMouseTracking(true);
setMinimumSize(400,400);
numberOfEachRowAndCol = 3;
for (int i = 0;i < numberOfEachRowAndCol;++i)
{
for (int j = 0;j < numberOfEachRowAndCol;++j)
{
circularStateList << CircularState::normal;
smartCircularRectList << QRect();
}
}
connect(&hoverTimer,&QTimer::timeout,this,&PatternPasswordWidget::onHoverTimer);
hoverTimer.setInterval(40);
}
PatternPasswordWidget::~PatternPasswordWidget()
{
}
void PatternPasswordWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
const auto rect = event->rect();
painter.fillRect(rect,QColor("#1D1D1D"));
auto width = rect.width();
auto height = rect.height();
auto sideLength = std::min(width,height) - 20;
auto halfSideLength = sideLength/2;
QRect drawZoneRect = QRect(-halfSideLength,-halfSideLength,sideLength,sideLength);
drawZoneRect.translate(rect.center());
painter.save();
painter.setPen(QPen(QBrush("#141414"),5));
painter.drawRoundedRect(drawZoneRect,12,12);
painter.restore();
radiu = sideLength / (1 + 1 + numberOfEachRowAndCol * 2 + (numberOfEachRowAndCol - 1) * 3);
bool mustUpdateCircularRect = isUpdateSmartCircularRect;
for (int i = 0,listIndex = 0;i < numberOfEachRowAndCol;++i)
{
for (int j = 0;j < numberOfEachRowAndCol;++j,++listIndex)
{
QPoint circularCenter = drawZoneRect.topLeft() + QPoint(2*radiu + i*5*radiu,2*radiu + j*5*radiu);
if(setList.contains(listIndex))
{
if(patternCodeLockSetUpState == PatternCodeLockState::setting ||
patternCodeLockSetUpState == PatternCodeLockState::setted_valid)
{
painter.setPen(QPen(QBrush(QColor("#00FF80")),3));
}
else
{
painter.setPen(QPen(QBrush(QColor("#FE4C40")),3));
}
}
else
{
painter.setPen(QPen(QBrush(Qt::white),3));
}
if(listIndex == lastHoverIndex &&
hoverTimer.isActive() &&
patternCodeLockSetUpState == PatternCodeLockState::setting)
{
painter.drawEllipse(circularCenter,radiu + currentchangeLength,radiu + currentchangeLength);
}
else
{
painter.drawEllipse(circularCenter,radiu,radiu);
}
if(mustUpdateCircularRect)
{
QRect newCircularRect = QRect(-radiu/2,-radiu/2,radiu,radiu);
newCircularRect.translate(circularCenter);
smartCircularRectList[listIndex] = newCircularRect;
}
painter.save();
switch (circularStateList.at(listIndex))
{
case CircularState::normal:
{
if(listIndex == lastHoverIndex &&
hoverTimer.isActive() &&
patternCodeLockSetUpState == PatternCodeLockState::notSet)
{
painter.setBrush(Qt::white);
painter.setPen(Qt::transparent);
painter.drawEllipse(circularCenter,
static_cast<int>(radiu * 0.5 + currentchangeLength),
static_cast<int>(radiu * 0.5 + currentchangeLength));
}
else
{
painter.setBrush(QColor("#888888"));
painter.setPen(Qt::transparent);
painter.drawEllipse(circularCenter,radiu/2,radiu/2);
}
}break;
case CircularState::hoverOnInnerSamrtCircular:
{
painter.setPen(Qt::transparent);
if(patternCodeLockSetUpState == PatternCodeLockState::notSet)
{
painter.setBrush(Qt::white);
if(hoverTimer.isActive())
{
painter.drawEllipse(circularCenter,
static_cast<int>(radiu * 0.5 + currentchangeLength),
static_cast<int>(radiu * 0.5 + currentchangeLength));
}
else
{
painter.drawEllipse(circularCenter,
static_cast<int>(radiu * 0.7),
static_cast<int>(radiu * 0.7));
}
}
else
{
if(patternCodeLockSetUpState == PatternCodeLockState::setting ||
patternCodeLockSetUpState == PatternCodeLockState::setted_valid)
{
painter.setBrush(QColor("#00FF80"));
}
else
{
painter.setBrush(QColor("#FE4C40"));
}
painter.drawEllipse(circularCenter,
static_cast<int>(radiu * 0.7),
static_cast<int>(radiu * 0.7));
}
}break;
}
painter.restore();
}
}
if(patternCodeLockSetUpState != PatternCodeLockState::notSet)
{
painter.setBrush(Qt::transparent);
if(patternCodeLockSetUpState == PatternCodeLockState::setted_invalid)
{
painter.setPen(QPen(QBrush(QColor("#FE4C40")),7,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
}
else
{
painter.setPen(QPen(QBrush(QColor("#00FF80")),7,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
}
int setListSize = setList.size();
for(int i = 0;i < setListSize;++i)
{
if(i < (setListSize - 1))
{
painter.drawLine(smartCircularRectList.at(setList.at(i)).center(),
smartCircularRectList.at(setList.at(i + 1)).center());
}
}
if(patternCodeLockSetUpState == PatternCodeLockState::setting)
{
painter.drawLine(smartCircularRectList.at(setList.last()).center(),
settingMousPos);
}
}
if(mustUpdateCircularRect)
isUpdateSmartCircularRect = false;
}
void PatternPasswordWidget::resizeEvent(QResizeEvent *event)
{
isUpdateSmartCircularRect = true;
QWidget::resizeEvent(event);
}
void PatternPasswordWidget::mouseMoveEvent(QMouseEvent *event)
{
auto pos = event->pos();
int currentHoverIndex = -1;
if(patternCodeLockSetUpState == PatternCodeLockState::notSet)
{
bool mouseInSomeSmartCircular{false};
for(int i = 0;i < smartCircularRectList.size();++i)
{
if(smartCircularRectList.at(i).contains(pos))
{
circularStateList[i] = CircularState::hoverOnInnerSamrtCircular;
currentHoverIndex = i;
mouseInSomeSmartCircular = true;
}
else
{
circularStateList[i] = CircularState::normal;
}
}
if(mouseInSomeSmartCircular)
{
lastHoverIndex = currentHoverIndex;
setCursor(Qt::PointingHandCursor);
}
else
{
setCursor(Qt::ArrowCursor);
}
if(!hoverTimer.isActive())
{
if(this->mouseInSomeSmartCircular != mouseInSomeSmartCircular)//鼠标进入了某个小圆或从小圆出来
{
this->mouseInSomeSmartCircular = mouseInSomeSmartCircular;
if(this->mouseInSomeSmartCircular)
{
currentchangeLength = 0;
}
else
{
currentchangeLength = radiu * 0.2;
}
hoverTimer.start();
}
}
}
else if(patternCodeLockSetUpState == PatternCodeLockState::setting)
{
bool mouseInSomeSmartCircular{false};
for(int i = 0;i < smartCircularRectList.size();++i)
{
if(smartCircularRectList.at(i).contains(pos))
{
if(!setList.contains(i))
{
setList << i;
circularStateList[i] = CircularState::hoverOnInnerSamrtCircular;
currentHoverIndex = i;
}
mouseInSomeSmartCircular = true;
}
}
if(this->mouseInSomeSmartCircular != mouseInSomeSmartCircular)
{
this->mouseInSomeSmartCircular = mouseInSomeSmartCircular;
if(mouseInSomeSmartCircular)
{
lastHoverIndex = currentHoverIndex;
setCursor(Qt::PointingHandCursor);
if(!hoverTimer.isActive())
{
currentchangeLength = 0;
hoverTimer.start();
}
}
else
{
setCursor(Qt::ArrowCursor);
}
}
settingMousPos = pos;
}
update();
QWidget::mouseMoveEvent(event);
}
void PatternPasswordWidget::onHoverTimer()
{
if(patternCodeLockSetUpState == PatternCodeLockState::notSet)
{
if(mouseInSomeSmartCircular)
{
if(currentchangeLength >= (radiu * 0.2))
{
hoverTimer.stop();
}
currentchangeLength += 2;
}
else
{
if(currentchangeLength <= -(radiu * 0.1))
{
hoverTimer.stop();
}
currentchangeLength -= 2;
}
}
else if(patternCodeLockSetUpState == PatternCodeLockState::setting)
{
if(currentchangeLength >= (radiu * 0.1))
{
hoverTimer.stop();
}
currentchangeLength += 2;
}
update();
}
void PatternPasswordWidget::mousePressEvent(QMouseEvent *event)
{
if(lastHoverIndex != -1)
{
if(patternCodeLockSetUpState == PatternCodeLockState::notSet)//开始设置
{
patternCodeLockSetUpState = PatternCodeLockState::setting;
setList << lastHoverIndex;
circularStateList[lastHoverIndex] = CircularState::hoverOnInnerSamrtCircular;
settingMousPos = event->pos();
currentchangeLength = 0;
hoverTimer.start();
update();
}
}
QWidget::mousePressEvent(event);
}
void PatternPasswordWidget::mouseReleaseEvent(QMouseEvent *event)
{
if(patternCodeLockSetUpState == PatternCodeLockState::setting)
{
patternCodeLockSetUpState = PatternCodeLockState::setted_valid;
emit inputPasswordOverSignal(getPassWord());
update();
}
QWidget::mouseReleaseEvent(event);
}
void PatternPasswordWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
if(patternCodeLockSetUpState == PatternCodeLockState::setting && !mouseInSomeSmartCircular)
{
patternCodeLockSetUpState = PatternCodeLockState::setted_valid;
emit inputPasswordOverSignal(getPassWord());
update();
}
QWidget::mouseDoubleClickEvent(event);
}
QString PatternPasswordWidget::getPassWord()
{
QString psw;
for(const int & value : setList)
{
psw.append(QString::number(value+1,16));
}
return psw;
}
int PatternPasswordWidget::getNumberOfEachRowAndCol() const
{
return numberOfEachRowAndCol;
}
void PatternPasswordWidget::setNumberOfEachRowAndCol(int newNumberOfEachRowAndCol)
{
if(newNumberOfEachRowAndCol > 1 && newNumberOfEachRowAndCol < 10)
{
reset();
circularStateList.clear();
smartCircularRectList.clear();
numberOfEachRowAndCol = newNumberOfEachRowAndCol;
for (int i = 0;i < numberOfEachRowAndCol;++i)
{
for (int j = 0;j < numberOfEachRowAndCol;++j)
{
circularStateList << CircularState::normal;
smartCircularRectList << QRect();
}
}
update();
}
}
void PatternPasswordWidget::reset()
{
patternCodeLockSetUpState = PatternCodeLockState::notSet;
std::fill(circularStateList.begin(),circularStateList.end(),CircularState::normal);
lastHoverIndex = -1;
hoverTimer.stop();
currentchangeLength = 0;
isUpdateSmartCircularRect = true;
mouseInSomeSmartCircular = false;
setList.clear();
settingMousPos = QPoint(0,0);
update();
}
三、使用方法
新建一个Dialog界面
开始布局
将widgetPassword右键->提升为->然后选择PatternPasswordWidget
类就OK!
觉得不错给作者点个赞呗!