一、演示效果
二、关键程序
#include "winrestorebutton.h"
WinRestoreButton::WinRestoreButton(QWidget* parent)
: InteractiveButtonBase(parent)
{
setUnifyGeomerey(true);
}
void WinRestoreButton::paintEvent(QPaintEvent* event)
{
InteractiveButtonBase::paintEvent(event);
if (!show_foreground) return ; // 不显示前景
// 画出现一角的矩形
int w = _w, h = _h;
int dx = offset_pos.x(), dy = offset_pos.y();
QRect br;
if (click_ani_appearing || click_ani_disappearing)
{
double pro = click_ani_progress / 800.0;
br = QRect(
_l+(w/3+dx) - (w/3+dx)*pro,
_t+(h/3+dy) - (h/3+dy)*pro,
w/3 + (w*2/3)*pro,
h/3 + (h*2/3)*pro
);
}
else
{
br = QRect(_l+w/3+dx, _t+h/3+dy, w/3, h/3);
}
// 画原来的矩形
QPainter painter(this);
painter.setPen(QPen(icon_color));
painter.drawRect(br);
dx /= 2; dy /= 2;
int l = _l+w*4/9+dx, t = _t+h*2/9+dy, r = _l+w*7/9+dx, b = _t+h*5/9+dy;
if (click_ani_appearing || click_ani_disappearing)
{
double pro = click_ani_progress / 800.0;
l -= l*pro;
t -= t*pro;
r += (w-r)*pro;
b += (h-b)*pro;
}
QPoint topLeft(l, t), topRight(r, t), bottomLeft(l, b), bottomRight(r, b);
QList<QPoint>points;
/* 两个矩形一样大的,所以运行的时候,需要有三大类:
* 1、完全重合(可以视为下一点任意之一)
* 2、有一个点落在矩形内(4种情况)
* 3、完全不重合
* 根据3大类共6种进行判断
*/
if (br.topLeft() == topLeft)
{
points << topLeft << topRight << bottomRight << bottomLeft << topLeft;
}
else if (br.contains(topLeft)) // 左上角在矩形内
{
points << QPoint(br.right()+1, t) << topRight << bottomRight << bottomLeft << QPoint(l, br.bottom()+1);
}
else if (br.contains(topRight)) // 右上角在矩形内
{
points << QPoint(r, br.bottom()+1) << bottomRight << bottomLeft << topLeft << QPoint(br.left(), t);
}
else if (br.contains(bottomLeft)) // 左下角在矩形内(默认)
{
points << QPoint(l, br.top()) << topLeft << topRight << bottomRight << QPoint(br.right()+1, b);
}
else if (br.contains(bottomRight)) // 右下角在矩形内
{
points << QPoint(br.left(), b) << bottomLeft << topLeft << topRight << QPoint(r, br.top());
}
else // 没有重合
{
points << topLeft << topRight << bottomRight << bottomLeft << topLeft;
}
if (points.size() > 1)
{
QPainterPath path;
path.moveTo(points.at(0));
for (int i = 1; i < points.size(); ++i)
path.lineTo(points.at(i));
QColor color(icon_color);
color.setAlpha(color.alpha()*0.8);
painter.setPen(QPen(color));
painter.drawPath(path);
}
}
#include "threedimenbutton.h"
ThreeDimenButton::ThreeDimenButton(QWidget* parent) : InteractiveButtonBase (parent)
{
setMouseTracking(true);
aop_w = width() / AOPER;
aop_h = height() / AOPER;
shadow_effect = new QGraphicsDropShadowEffect(this);
shadow_effect->setOffset(0, 0);
shadow_effect->setColor(QColor(0x88, 0x88, 0x88, 0x64));
shadow_effect->setBlurRadius(10);
setGraphicsEffect(shadow_effect);
setJitterAni(false);
}
void ThreeDimenButton::enterEvent(QEvent *event)
{
}
void ThreeDimenButton::leaveEvent(QEvent *event)
{
if (in_rect && !pressing && !inArea(mapFromGlobal(QCursor::pos())))
{
in_rect = false;
InteractiveButtonBase::leaveEvent(nullptr);
}
// 不return,因为区域不一样
}
void ThreeDimenButton::mousePressEvent(QMouseEvent *event)
{
// 因为上面可能有控件,所以可能无法监听到 enter 事件
if (!in_rect && inArea(event->pos())) // 鼠标移入
{
in_rect = true;
InteractiveButtonBase::enterEvent(nullptr);
}
if (in_rect)
return InteractiveButtonBase::mousePressEvent(event);
}
void ThreeDimenButton::mouseReleaseEvent(QMouseEvent *event)
{
if (pressing)
{
InteractiveButtonBase::mouseReleaseEvent(event);
if (leave_after_clicked || (!inArea(event->pos()) && !pressing)) // 鼠标移出
{
in_rect = false;
InteractiveButtonBase::leaveEvent(nullptr);
}
}
}
void ThreeDimenButton::mouseMoveEvent(QMouseEvent *event)
{
bool is_in = inArea(event->pos());
if (is_in && !in_rect)// 鼠标移入
{
in_rect = true;
InteractiveButtonBase::enterEvent(nullptr);
}
else if (!is_in && in_rect && !pressing) // 鼠标移出
{
in_rect = false;
InteractiveButtonBase::leaveEvent(nullptr);
}
if (in_rect)
InteractiveButtonBase::mouseMoveEvent(event);
}
void ThreeDimenButton::resizeEvent(QResizeEvent *event)
{
aop_w = width() / AOPER;
aop_h = height() / AOPER;
return InteractiveButtonBase::resizeEvent(event);
}
void ThreeDimenButton::anchorTimeOut()
{
// 因为上面有控件挡住了,所以需要定时监控move情况
mouse_pos = mapFromGlobal(QCursor::pos());
if (!pressing && !inArea(mouse_pos)) // 鼠标移出
{
InteractiveButtonBase::leaveEvent(nullptr);
}
InteractiveButtonBase::anchorTimeOut();
// 修改阴影的位置
if (offset_pos == QPoint(0,0))
shadow_effect->setOffset(0, 0);
else
{
if (offset_pos.manhattanLength() > SHADE)
{
double sx = -SHADE * offset_pos.x() / offset_pos.manhattanLength();
double sy = -SHADE * offset_pos.y() / offset_pos.manhattanLength();
shadow_effect->setOffset(sx*hover_progress/100, sy*hover_progress/100);
}
else
{
shadow_effect->setOffset(-offset_pos.x()*hover_progress/100, -offset_pos.y()*hover_progress/100);
}
}
}
QPainterPath ThreeDimenButton::getBgPainterPath()
{
QPainterPath path;
if (hover_progress) // 鼠标悬浮效果
{
/**
* 位置比例 = 悬浮比例 × 距离比例
* 坐标位置 ≈ 鼠标方向偏移
*/
double hp = hover_progress / 100.0;
QPoint o(width()/2, height()/2); // 中心点
QPointF m = limitPointXY(mapFromGlobal(QCursor::pos())-o, width()/2, height()/2); // 当前鼠标的点
QPointF f = limitPointXY(offset_pos, aop_w, aop_h); // 偏移点(压力中心)
QPointF lt, lb, rb, rt;
// 左上角
{
QPointF p = QPoint(aop_w, aop_h) - o;
double prob = dian_cheng(m, p) / dian_cheng(p, p);
lt = o + (p) * (1-prob*hp/AOPER);
}
// 右上角
{
QPointF p = QPoint(width() - aop_w, aop_h) - o;
double prob = dian_cheng(m, p) / dian_cheng(p, p);
rt = o + (p) * (1-prob*hp/AOPER);
}
// 左下角
{
QPointF p = QPoint(aop_w, height() - aop_h) - o;
double prob = dian_cheng(m, p) / dian_cheng(p, p);
lb = o + (p) * (1-prob*hp/AOPER);
}
// 右下角
{
QPointF p = QPoint(width() - aop_w, height() - aop_h) - o;
double prob = dian_cheng(m, p) / dian_cheng(p, p);
rb = o + (p) * (1-prob*hp/AOPER);
}
path.moveTo(lt);
path.lineTo(lb);
path.lineTo(rb);
path.lineTo(rt);
path.lineTo(lt);
}
else
{
// 简单的path,提升性能用
path.addRect(aop_w, aop_h, width()-aop_w*2, height()-aop_h*2);
}
return path;
}
QPainterPath ThreeDimenButton::getWaterPainterPath(InteractiveButtonBase::Water water)
{
QRect circle(water.point.x() - water_radius*water.progress/100,
water.point.y() - water_radius*water.progress/100,
water_radius*water.progress/50,
water_radius*water.progress/50);
QPainterPath path;
path.addEllipse(circle);
return path & getBgPainterPath();
}
void ThreeDimenButton::simulateStatePress(bool s, bool a)
{
in_rect = true;
InteractiveButtonBase::simulateStatePress(s, a);
in_rect = false;
}
bool ThreeDimenButton::inArea(QPointF point)
{
return !(point.x() < aop_w
|| point.x() > width()-aop_w
|| point.y() < aop_h
|| point.y() > height()-aop_h);
}
/**
* 计算两个向量的叉积
* 获取压力值
*/
double ThreeDimenButton::cha_cheng(QPointF a, QPointF b)
{
return a.x() * b.y() - b.x()* a.y();
}
double ThreeDimenButton::dian_cheng(QPointF a, QPointF b)
{
return a.x() * b.x() + a.y() * b.y();
}
QPointF ThreeDimenButton::limitPointXY(QPointF v, int w, int h)
{
// 注意:成立时,v.x != 0,否则除零错误
if (v.x() < -w)
{
v.setY(v.y()*-w/v.x());
v.setX(-w);
}
if (v.x() > w)
{
v.setY(v.y()*w/v.x());
v.setX(w);
}
if (v.y() < -h)
{
v.setX(v.x()*-h/v.y());
v.setY(-h);
}
if (v.y() > h)
{
v.setX(v.x()*h/v.y());
v.setY(h);
}
return v;
}
三、程序下载
程序链接
https://download.csdn.net/download/u013083044/85802960