QT-动画控件演示

一、演示效果

请添加图片描述

二、关键程序

#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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的大海贼

联系博主,为您提供有价值的资源

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值