应用背景
对话框中执行一段比较耗时的程序时,界面会出现假死现象,如果用户没有耐心就会乱点软件,导致软件崩溃。
解决思路
执行耗时任务前打开一个子窗口(显示动图),将耗时任务扔到一个线程里执行,这里新开线程必须是异步的,如果是同步的话没有作用!任务执行结束后将子窗口关闭
实现步骤
1. 新建Qt的GUI类,在界面中添加label:
2. 找一个gif资源,放到软件相对路径下,可通过以下网站自行下载:
https://www.lanrentuku.com/gif/a/loading.html
3. 主对话框中点击运行后,在相应槽函数中调用上面的dlg,然后创建异步线程,在线程中执行耗时任务:
首先对转圈对话框进行一些设置,主要把窗口边框去掉,然后背景设置为透明而label中资源不透明:
LoginDlg::LoginDlg(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);//去掉边框的对话框风格
//设置背景透明而内容不透明:
this->setWindowOpacity(1);
this->setAttribute(Qt::WA_TranslucentBackground);
//设置为非模态
setWindowModality(Qt::NonModal);
//label中添加资源
m_Move = new QMovie("../res/转圈圈.gif");
ui.label_gif->setMovie(m_Move);
ui.label_gif->setScaledContents(false);
ui.label_gif->setAlignment(Qt::AlignCenter);
ui.label_gif->setStyleSheet("QLabel {background-color:transparent;}");//设置lable背景透明
m_Move->start();
}
LoginDlg::~LoginDlg()
{
m_Move->stop();
}
点击运行的槽函数中:
//转圈
m_logindlg = new LoginDlg(this);
//调用等待窗口转圈
m_logindlg->show();
//使用线程执行耗时操作
QString path = ui.lineEdit->text();
QFuture<void> ff = QtConcurrent::run(this,&MyDlg::doThread,path);
- 这里转圈对话框设置成了当前主对话框的成员变量,方便在其他槽函数中关闭它;
- 另外,这里转圈对话框要设置为非模态的,就是不阻塞,否则无法执行下面的异步线程;
- 最后需要注意的是这里的线程必须是异步的,如果是同步的(比如通过继承QTread类,重写run方法就是同步的,这样的话会等线程执行完成后才会弹出转圈对话框,结果就不是我们想要的),所以这里使用QFuture实现异步线程(QFuture使用可参考https://blog.csdn.net/hu12306/article/details/79760605,其他异步执行方法可参考https://blog.csdn.net/qq_37529913/article/details/110521759
这里假装给一个耗时函数:
void MyDlg::doThread(QString funcpath)
{
//执行耗时任务
while(1)
{
sleep(5);
}
emit loginTerminate(QString());//自定义的消息
}
这里接收消息,并关闭转圈窗口:
void ConvolutionCenterDlg::slotTerminate(QString infos)
{
//关闭转圈窗口
m_logindlg->close();
//执行后续操作
}
最后效果显示:这里只截图了,没有录制动图,可以看到整个图层在主窗口上方且没有背景色,达到预期效果: