百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

Qt实现炫酷启动图-动态进度条 无法初始化qt平台插件该程序无法启动

liebian365 2024-10-17 14:00 9 浏览 0 评论

一、简述

在软件启动的时候会消耗比较长的时间,原生的进度条已经不能满足我们的需求,这里我们就需要一个会动的进度条,效果如下图所示。

光效进度条主要是做了一个进度动画,在已完成的部分上进行快速的迭代渲染,给用户一种直观感受,我们的软件一直努力加载,它还活着。

有了这个进度条之后,当我们的进度从40%到50%这个持续的过程中,界面再也不会出现假死的情况,是不是很完美呢。。。

下面我就来分析下这个动效进度条是怎么做的

二、动效进度条

如效果图所示,光效进度条不同于一般的进度条,他在基础的任务进度之上还添加了一层光效,主要是想告诉用户我们的软件一直在努力运行,请在耐心的等待一下下。

我自己在做功能的时候,往往喜欢先做一个测试demo,然后在把做好的功能集成在正式环境,这个功能也不列外,如第一节中展示的效果图,就是测试demo的样子,虽然很丑,但是基础功能是有的。

现在的很多软件,在进度展示上都有了比较绚丽的效果,比如压缩软件,解压文件的时候都会有动效进度条,用过的同学应该都知道长啥样,而我们的光效进度条跟这个效果差不多,除此之外我们还提供了另一种动效,延迟动效,他们两个在一定程度上都展示了更友好的进度效果。

在开始分析功能前,首先我们先来考虑下我们的需求:动效进度条,也就是说在原来的进度条基础上需要添加实时动画,让进度条看起来更炫酷一些,除了光效进度条以外,还有一种延迟到达进度条,也属于动态进度条。

延迟动效、说直白一点儿就是延迟到达,当我们设置了进度从10%到20%时,程序模拟了一个渐进的过程,使用一个时间段走完了这10%的进度。

下面我们分别来介绍这两种进度条的实现

实现炫酷的进度条我们可以从QWidget自定义开始写,也就是说从头开始写,但通常我们不这样干,因为这样可能会写出无穷无尽的bug,而且现有的轮子已经很稳定了,为什么还要造呢。

1、光效进度条

光效进度条我们使用了一个小技巧,采用一个简单的办法实现,我们的光效进度条控件继承自Qt原生进度条类QProgressBar,在新类中我们只需要在Qt绘制完原生进度条之后,补画动效即可。

a、paintEvent函数

paintEvent函数是Qt的绘制函数,当界面刷新的时候,这个接口函数就会被调用,因此我们需要重写这个接口,首先调用父窗口的绘制方法,然后我们在绘制我们自己的动效,代码如下所示

QProgressBar::paintEvent(event);
drawCache绘制动效

b、drawCache绘制动效

绘制动效的时候,我们需要知道动效的绘制区域,这个地方我们需要主动去解析qss的一些参数,Qt的style()->subElementRect这个接口刚好可以拿到我们需要的信息

下面简单描述下我们的实现流程

  • 首先我们获取进度条的几何大小和中间进度的几何大小,这样的话我们就可以计算出来各border的数值
  • 然后根据我们当前的value值就可以计算出进度条已经走过(就是值小于我们设定的区域)的几何大小
  • 我们的光效将是跑在第二步计算出来的区域上,一直循环迭代
  • 内存里我们维护一个cacheValue,这个值在每次界面刷新的时候递增,但是不能大于第二步的value值,cacheValue将是我们动效绘制的一个关键参数,他表示了动效绘制的长度
  • 构造一个渐变刷子,设置给QPainter
  • 绘制动效

上下大致描述了下绘制动效的一个流程,下面送上具体代码,由于篇幅原因,代码我进行了部分伪代码处理。

void GMPProgressBar::drawCache()
{
    QStyleOptionProgressBarV2 opt;
    QRect outerRect = style()->subElementRect(QStyle::SE_ProgressBarGroove, &opt, this);
    QRect innerRect = style()->subElementRect(QStyle::SE_ProgressBarContents, &opt, this);
    QMargins borders(构造一个QMargins);

	QRectF rect(动效绘制区域);

	if (m_iCacheValue != 0)
	{
		QPainter painter(this);
		QLinearGradient gradient(构造绘图刷子);
		painter.setBrush(gradient);
		painter.drawRoundedRect(rect, 2, 2);
	}
}

c、定时刷新

由于我们的动效是需要主动去刷新的,因此我们需要声明一个定时器,然后定时去刷新,实现代码可能像下面这样

connect(m_pCacheTimer, &QTimer::timeout, this, [this]{
		if (TM_CACHE == m_mode)
		{
			++m_iCacheValue;
			repaint();
		}else
        {
            m_pCacheTimer->stop();
        }
	});

定时器只需要在我们第一次设置进度条值的时候启动,或者当我们设置一个新的值,而定时器没有启动,我们就需要去激活定时器。

TM_CACHE模式即是我们的动效模式,TM_SMOOTH模式则是我们的延迟到达模式

connect(this, &QProgressBar::valueChanged, [this](int value){//TM_CACHE模式下 启动动画时机
		if (!m_pCacheTimer->isActive() && value != 0 && TM_CACHE == m_mode)
		{
			m_pCacheTimer->start(m_iRefreshleveling);
		}
	});

动效进度条效果如下图所示

2、延迟到达进度条

动效进度条可能更适用于启动界面,但是也有一些时候,我们可能需要更平缓的一个加载曲线,例如安装软件、卸载软件的时候。

【领QT开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】「链接」

a、setValue

延迟到达进度条和动效进度条的实现方式就有所差别了,对于实现延迟到达进度条,我们这里重写了setValue函数,当外部调用该接口设置value值时,我们并没有立即去设置当前值,而是使用了一个时间段去完成这个值得刷新。

  • 外部调用setValue时,我们首先计算出我们应该绘制的最大宽度PixelMax、当前已经绘制到的最大宽度cacheValue和我们的步长
  • 设置定时器刷新频率,并重启定时器
  • 定时器刷新时,cacheValue自增我们的步长
  • 调用父类的QProgressBar::setValue接口设置值

b、定时器

延迟达到功能的的定时器和之前我们什么的动效定时器可以混用一个,我们定时器刷新的时候,针对不同的动画模式,我们执行不同的的代码即可,实现代码可能像下面这样

connect(m_pCacheTimer, &QTimer::timeout, this, [this]{
	if (TM_CACHE == m_mode)
	{
		++m_iCacheValue;
		repaint();
	}
	else if (TM_SMOOTH == m_mode)
	{
		changeSmooth();
	}
    else
    {
        m_pCacheTimer->stop();
    }
});

延迟到达进度条效果如下图所示

3、接口说明

光效进度条类对外只暴露了3个接口,分别是设置动画模式、动画时长和刷新频率

特别需要注意的是,我们这里重写了父类的setValue接口,这意味着我们不能使用多态来操作这个接口

void setTransitionMode(TransitionMode mode);//设置动画模式
void setSmoothDuration(int duration);//设置刷新总时长 模式为TM_SMOOTH时有效
void setRefreshleveling(int rate);//设置刷新频率 每次更改TransitionMode之后会变为默认值

a、修改动画模式

修改动画模式的时候,我们需要清空内存中的所有数据,并把value值设为0。

void GMPProgressBar::setTransitionMode(TransitionMode mode)
{
	if (m_mode == mode)
	{
		return;
	}

	m_mode = mode;
	clearData();

	QProgressBar::setValue(0);
}

b、其他接口

设置刷新时长和频率接口都比较简单,不做特别说明

特别注意:这个3个接口最好是在动画启动前设置,动画开始后尽量不要去调用

三、启动图

第二节我们主要是讲述了怎么做一个动效进度条,这一节我们来做一个启动图页面,把这个动效使用进去。

启动图不是我们主要分析的内容,这个我就简单说下这个类的实现方式和一些借口说明

1、实现思路

Qt已经给我们提供了一个QSplashScreen,但是使用起来还是特别有限,因此这里我把Qt的源码直接进行了二次开发

  • 首先Qt的原生实现方式基本都被移植了出来
  • 启动图使用了简单的上下布局,上面是一张我自绘制的图片,放在了一个QLabel上,下面是动效进度条
  • 自绘制的图片上包括了,产品名称、logo、背景图等等

【领QT开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】「链接」

2、背景图切换

当我们调用setPixmap设置背景图时,如果我们指定了多张图,我将会启动一个定时器,在指定时长后重新构造一张大的背景图,并添加到启动窗口上

这里主要说明下背景图是怎么构造出来的,代码如下所示

a、根据背景图构造启动图大小,并移动到屏幕中间

m_currentPixmap = m_lstPixmaps.at(m_iCurrentIndex);

QRect size(QPoint(), m_currentPixmap.size()  / m_currentPixmap.devicePixelRatio());
size.setHeight(size.height() + StatusBarHeight);
setFixedSize(size.size());
m_pProgressBar->setFixedWidth(size.width() / 8 * 3);
move(QApplication::desktop()->screenGeometry().center() - size.center());

b、绘制程序logo

QPainter painter(&m_currentPixmap);
painter.drawPixmap(m_startPos, m_logo);

c、绘制标题栏

painter.save();
painter.setFont(m_titleFont);

QFontMetrics fontMetrics(m_titleFont);
int textWidth = fontMetrics.width(m_strWindowTitle);
int textHegith = m_logo.height();
QRect textTect = QRect(m_startPos + QPoint(13 + m_logo.width(), 0), QSize(textWidth, textHegith));
painter.drawText(textTect, m_strWindowTitle, QTextOption(Qt::AlignCenter));
painter.restore();

d、设置给QLabel背景图

m_pWindowBackground->setPixmap(m_currentPixmap);

启动图的效果这里就不在贴图了,第三节上的两个gif图都是最终的启动图效果

四、测试

最后就是测试代码了,主要是模拟了程序的一个加载过程

1、构造启动图

首先我们构造一个启动图对象,并设置程序logo和动画模式

GMPSplashScreen * screen = new GMPSplashScreen(QPixmap(":/splashScreen/start.png"));
screen->show();
screen->setLogo(QIcon("logo.ico").pixmap(48, 48));
screen->setTransitionMode(GMPProgressBar::TM_CACHE);

2、背景图

设置背景图,并设置背景图更换时间间隔

QList<QPixmap> lstPixmap;
lstPixmap.append(QPixmap(":/splashScreen/start.png"));
lstPixmap.append(QPixmap(":/splashScreen/start.jpg"));
screen->setPixmap(lstPixmap, 2000);

3、其他信息

设置程序的提示信息和标题栏

screen->showMessage("Established connections", 0);
screen->setTitle(QStringLiteral("广联达BIM土建计量GTJ2018"));

4、事件循环

这里写了一个死循环,主要是为了模拟程序的一个加载过程,每隔10ms处理下界面刷新事件

a.processEvents();

while (1)
{
    QTest::qSleep(10);
    a.processEvents();
}
splashScreen w;
w.show();

screen->finish(&w);

相关推荐

快递查询教程,批量查询物流,一键管理快递

作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...

一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递

对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...

快递查询单号查询,怎么查物流到哪了

输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...

3分钟查询物流,教你一键批量查询全部物流信息

很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...

快递单号查询,一次性查询全部物流信息

现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...

快递查询工具,批量查询多个快递快递单号的物流状态、签收时间

最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...

快递查询软件,自动识别查询快递单号查询方法

当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...

教你怎样查询快递查询单号并保存物流信息

商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...

简单几步骤查询所有快递物流信息

在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...

物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号

最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...

连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息

快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...

快递查询教程,快递单号查询,筛选更新量为1的单号

最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...

掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析

在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...

从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息

在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...

物流单号查询,在哪里查询快递

如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...

取消回复欢迎 发表评论: