baizy77 发表于 2019-7-5 09:57:12

KS09-06 为应用程序添加启动画面(QSplashScreen)

本帖最后由 baizy77 于 2019-8-7 09:21 编辑

版权声明---------------------------------------------------------------------------------------------------------------------该文章原创于Qter开源社区(www.qter.org)作者: 女儿叫老白转载请注明出处!---------------------------------------------------------------------------------------------------------------------课程目录: 【独家连载】《Qt入门与提高-GUI产品开发》目录
网页版课程源码 提取码:1uy7
引言------------------------------------------------------------------------------------大型的应用程序启动一般都比较耗时,为了不降低用户体验,大型应用一般都有启动画面。而且,启动画面上一般会显示进度:比如用文本或进度条指示进度。本节将介绍带进度条的启动画面的开发方法。
正文------------------------------------------------------------------------------------
如果单纯展示一个启动画面,可以直接使用QSplashScreen;但是如果还要提供进度条,那么QSplashScreen就不满足需求了,需要我们自行实现。图09-06-01是程序运行效果图。
我们以src.baseline中的代码为基础,为其添加启动界面。
首先,我们要编写自己的CSplashScreen类    CSpahsScreen派生自QSplashScreen。代码如下:
代码清单09-06-01splashscreen.h#pragma once

#include <QSplashScreen>

QT_BEGIN_NAMESPACE
class QProgressBar;
QT_END_NAMESPACE

class CSplashScreen : public QSplashScreen
{
      Q_OBJECT
public:
    CSplashScreen(const QPixmap &pixmap = QPixmap());
      ~CSplashScreen(){;}

public Q_SLOTS:
    void setProgress(quint32);

private:
    //进度条
    QProgressBar * m_pProgressBar;
};
    在代码清单09-06-01中,我们提供了CSplashScreen类定义。该类派生自QSplashScreen。我们提供了一个构造函数,该构造函数接受一个const QPixmap&参数。    在第21行,我们为该类提供了一个QProgressBar*进度条对象用来展示进度。    在第17行,我们为该类提供一个槽函数setProgress(quint32)。大家可以看到,它接受一个quint32类型的数据。我们用这个数据来更新m_pProgressBar的进度值。    下面看一下CSplashScreen的实现。代码清单09-06-02
splashscreen.cpp#include "splashscreen.h"
#include <QProgressBar>
CSplashScreen::CSplashScreen(const QPixmap &pixmap) :
    QSplashScreen(pixmap)
{
    m_pProgressBar = new QProgressBar(this);
   
    //设置进度条的位置
    m_pProgressBar->setGeometry(0,
                              pixmap.height() - 50,
                              pixmap.width(),
                              30);
    //设置进度条的样式
    m_pProgressBar->setStyleSheet(
      "QProgressBar {color:black;font:30px;text-align:center; } \
         QProgressBar::chunk {background-color: rgb(200, 160, 16);}");
   
    //设置进度条的范围
    m_pProgressBar->setRange(0, 100);
   
    //设置进度条的当前进度
    m_pProgressBar->setValue(0);
}

void CSplashScreen::setProgress(quint32 value)
{
    m_pProgressBar->setValue(value%101);
}
    在代码清单09-06-02中,我们提供了CSplashScreen的实现。    在构造函数中,在第6行,我们构建了进度条对象m_pProgressBar。    在第9~12行,我们设置了进度条的位置、尺寸。这里我们借用了启动图片的宽度和高度数据。    为了让进度条更加美观,在第14~16行为进度条对象设置样式。读者可以根据需要自行调整、修改样式数据。    第19~22行设置了进度条的范围、默认值。    第25~28行提供了进度条的槽函数实现。该槽函数用来接收主窗口发出的进度信号中带的进度数据,以便更新进度条位置。
然后,修改主窗口,为它添加进度信号以及connect信号槽的代码    先为主窗口增加位置信号和槽函数。代码清单09-06-03
mainwindow.hclass CMainWindow : public QMainWindow
{
      Q_OBJECT
public:
      CMainWindow(QWidget* parent, CSplashScreen* pSplashScreen);
      ~CMainWindow(){;}

    void readData(); // 模拟构造过程中的耗时操作

Q_SIGNALS:
void progress(quint32);
// ......
};
    在代码清单09-06-03中,只列出了修改的内容。    第5行,为构造函数增加了一个参数,用来传入CSplashScreen对象。可能有人有疑问:为何不提供接口来设置该对象呢?原因很简单,我们的目的是在CMainWindow构造(比较耗时)的过程中,展示启动进度,如果在CMainWindow构造完成后再去调用接口传入CSplashScreen对象来更新进度条就已经晚了。如果您的应用程序的启动过程的时间主要花费在其他地方,那么就可以在耗费时间的地方去发送信号更新进度条状态。本节只是以CMainWindow构造比较耗时为例进行演示。    第8行的readData()接口用来模拟构造过程中的耗时操作。以便在该接口中发出信号更新进度条。    第11行的progress(quint32)信号就是我们为主窗口新增的信号。该信号用来通知CSplashScreen更新进度条。具体在CMainWindow的构造函数的实现代码中解释。
    下面看一下CMainWindow的实现代码。代码清单09-06-04
mainwindow.cpp#include "splashscreen.h"
CMainWindow::CMainWindow(QWidget* parent, CSplashScreen* pSplashScreen) : QMainWindow(parent)
{
    connect(this,
      &CMainWindow::progress,
      pSplashScreen,
      &CSplashScreen::setProgress);

    // 模拟耗时操作
    QThread::sleep(1);
    emit progress(10);
   
    createActions();
      createMenus();
      createToolBars();
      createStatusBar();

      initialize();

      setWindowTitle(tr("Demo"));
      setMinimumSize(160, 160);
      resize(480, 320);   
}
    在代码清单09-06-04中,我们对CMainWindow的构造函数进行了修改(见粗体斜体部分的代码)。    我们现在第5~8行将该类的progress信号绑定到传入的CSplashScreen对象的setProgress槽函数。请注意,设计的信号和槽函数的参数列表务必保持一致。    第11~12行模拟了一次耗时操作,方法是调用QThread::sleep(1),导致的结果是睡眠1秒。然后发出progress信号,信号中传输的值为10。这样就会更新进度条的进度值为10。具体可以查看CSplashScreen::setProgress()接口的实现。
    代码清单09-06-05
CMainWindow::initialize()void CMainWindow::initialize()
{
    // ......
    readData();

}
    在代码清单09-06-05中,我们把模拟耗时操作的接口readData()添加到initialize()中调用。    最后来看一下模拟耗时操作接口readData()的实现。    代码清单09-06-06
CMainWindow:: readData ()void CMainWindow::readData()
{

    QThread::sleep(1);
    emit progress(30);

    QThread::sleep(1);
    emit progress(50);

    QThread::sleep(1);
    emit progress(70);

    QThread::sleep(1);
    emit progress(100);

}
    从代码清单09-06-06可以看出,我们的模拟耗时操作接口readData()其实非常简单,就是通过QThread::sleep()接口进行睡眠然后发出更新进度条状态的信号progress()。
最后,在main()函数为应用程序中添加启动画面    代码清单09-06-07main.cpp#include <QApplication>
#include <QTranslator>
#include <QLibraryInfo>
#include <QFile>
#include <QPixmap>
#include <QTextEdit>
#include <QTextStream>
#include "mainwindow.h"
#include "splashscreen.h"

int main(int argc, char * argv[])
{
    QApplication app(argc, argv);
      // ......
    QPixmap pixmap(":images/logo.png");
    CSplashScreen splashScreen(pixmap);
    splashScreen.show();
app.processEvents();         // 保证显示启动画面的同时仍可以正
                           //   常响应鼠标、键盘等操作

      CMainWindow mainWindow(NULL, &splashScreen);   
    splashScreen.finish(&mainWindow);   // 等待主窗口初始化完毕,然后隐藏splashScreen
      mainWindow.showMaximized();

    return app.exec();
}
在代码清单09-06-07中:    第15~17行构造CSplashScreen对象并将其显示出来,请注意第15行中image文件的路径语法;    第18行的app.processEvents()目的是为了保证显示启动画面的同时仍可以正常响应鼠标、键盘等操作;    第21行,在构造CMainWindow对象时传入了splashScreen对象地址,以便在构造函数中绑定信号槽;    第22行的调用目的是在mianWindow构造函数执行完毕后隐藏splashScreen。
    为应用程序添加启动画面的方法介绍完毕。结语------------------------------------------------------------------------------------本文介绍了为应用程序添加启动界面的方法。其实,对不同的应用程序来说它的启动过程中的耗时操作可能不一定跟本节课demo的场景完全相同,但是处理思路是一致的:就是在耗时操作过程中不断的发出更新进度的信号以便自定义的CSplashScreen对象在接收到信号后更新进度条的进度。




页: [1]
查看完整版本: KS09-06 为应用程序添加启动画面(QSplashScreen)