Возникла необходимость отображать пользователю статус работы приложения при длительных расчетах, да так, что бы виджет, в котором обновляется информация был недоступен.
Написал небольшой класс (пример использования во вложении), который с горем-пополам выполняет данную задачу: указанный виджет затемняется с возможностью отображения текста и прогрессбара (по надобности).
Сильно не пинайте, а лучше, по возможности, укажите грубые ошибки, подскажите как улучшить.
Надеюсь, что кому-то пригодится
Небольшое описание публичных методов :
Glass(QString message = "", int stepCount = 0) - если message пустая, текста не будет; если stepCount пустая - прогрессбара.
void init(QWidget *parent) - установка затемнения на виджет parent
void hideAndDelete() - скрытие и удаление затемнения
void infinitely(QString text) - "бесконечное" прокручивание прогрессбара, если количество итераций зарание не известно.
void setAnimationDuration(int duration) - длительность анимации появления и скрытия (по умолчанию 300)
void setMessage(QString message) - установка текста
void setStepCount(int stepCount) - установка максимума в прогрессбаре
Ну и собственно :
Glass.h#ifndef GLASS_H
#define GLASS_H
#include <QObject>
#include <QEvent>
#include <QLabel>
#include <QProgressBar>
#include <QDebug>
#include <QColor>
#include <QPropertyAnimation>
class Glass : public QObject
{
Q_OBJECT
public:
Glass(QString message = "", int stepCount = 0);
~Glass();
void setMessage(QString message);
void setStepCount(int stepCount);
void setAnimationDuration(int duration);
void init(QWidget *parent);
void hideAndDelete();
void infinitely(QString text);
protected:
QLabel *glass;
QLabel *infoText;
QProgressBar *progressBar;
bool eventFilter(QObject *object, QEvent *event);
private:
bool
_haveMessage,
_haveProgress;
int
_stepCount,
_animationDuration;
void createControls();
void positioning();
QWidget *_parent;
signals:
void initailized(int);
private slots:
void afterInit();
public slots:
void nextStep(QString text);
};
#endif // GLASS_H
Glass.cpp#include "glass.h"
#include <QApplication>
Glass::Glass(QString message, int stepCount)
{
_haveMessage = ((!message.isEmpty()) ? true : false);
_haveProgress = ((stepCount > 0) ? true : false);
createControls();
if(_haveMessage) setMessage(message);
if(_haveProgress) setStepCount(stepCount);
}
void Glass::createControls()
{
glass = new QLabel();
glass->hide();
if(_haveMessage)
{
infoText = new QLabel(0);
infoText->hide();
infoText->setAlignment(Qt::AlignCenter);
infoText->setWordWrap(true);
infoText->setStyleSheet("color:#fff;");
}
if(_haveProgress)
{
progressBar = new QProgressBar(0);
progressBar->hide();
progressBar->setObjectName(QString::fromUtf8("progressBar"));
progressBar->setValue(0);
progressBar->setMaximum(0);
progressBar->setAlignment(Qt::AlignCenter);
progressBar->setTextVisible(true);
progressBar->setOrientation(Qt::Horizontal);
progressBar->setInvertedAppearance(false);
progressBar->setTextDirection(QProgressBar::TopToBottom);
progressBar->setFormat("%p% (%v/%m)");
}
_animationDuration = 300;
}
void Glass::setMessage(QString message)
{
if(_haveMessage) infoText->setText(message);
}
void Glass::setStepCount(int stepCount)
{
if(_haveProgress) progressBar->setMaximum(stepCount);
}
void Glass::setAnimationDuration(int duration)
{
_animationDuration = duration;
}
Glass::~Glass()
{
glass->setMaximumSize(0, 0);
glass->hide();
glass->deleteLater();
}
void Glass::hideAndDelete()
{
if(_haveMessage) infoText->hide();
if(_haveProgress) progressBar->hide();
if(_haveMessage) infoText->deleteLater();
if(_haveProgress) progressBar->deleteLater();
QPropertyAnimation *animation = new QPropertyAnimation(glass, "geometry");
animation->setDuration(_animationDuration);
animation->setEasingCurve(QEasingCurve::InCubic);
animation->setStartValue(glass->geometry());
animation->setEndValue(QRect((glass->geometry().x()+glass->geometry().width())/2, (glass->geometry().y()+glass->geometry().height())/2, 0, 0));
animation->start();
connect(animation, SIGNAL(finished()), this, SLOT(deleteLater()));
}
bool Glass::eventFilter(QObject *object, QEvent* event)
{
if(object != this && object != _parent) return false;
if(event->type() == QEvent::Resize)
{
glass->resize(glass->parentWidget()->size());
glass->move(0, 0);
positioning();
return true;
}
glass->setFocus();
return false;
}
void Glass::init(QWidget *parent)
{
_parent = parent;
qApp->installEventFilter(this);
glass->setStyleSheet("background-color: rgba(90, 90, 90, 127);");
glass->setParent(parent);
glass->show();
qApp->installEventFilter(this);
QPropertyAnimation *animation = new QPropertyAnimation(glass, "geometry");
animation->setDuration(_animationDuration);
animation->setEasingCurve(QEasingCurve::InCubic);
animation->setStartValue(QRect(parent->geometry().width()/2, parent->geometry().height()/2, 0, 0));
animation->setEndValue(QRect(0, 0, parent->geometry().width(), parent->geometry().height()));
animation->start();
connect(animation, SIGNAL(finished()), this, SLOT(afterInit()));
}
void Glass::afterInit()
{
_stepCount = 0;
if(_haveMessage)
{
infoText->setParent(_parent);
infoText->show();
}
if(_haveProgress)
{
_stepCount = progressBar->maximum();
progressBar->setParent(_parent);
progressBar->show();
}
positioning();
emit initailized(_stepCount);
}
void Glass::positioning()
{
int
pww = glass->parentWidget()->geometry().width(),
pwh = glass->parentWidget()->geometry().height();
if(_haveProgress) { progressBar->setGeometry(pww/4, pwh/2-10, pww/2, 21); qDebug() << progressBar->parentWidget() << progressBar->geometry(); }
if(_haveMessage) infoText->setGeometry(20, pwh/2-31, pww-40, 21);
qDebug() << "positioning" << _haveProgress << _haveMessage;
}
void Glass::nextStep(QString text)
{
if(_haveProgress) progressBar->setValue(progressBar->value()+1);
if(_haveMessage) setMessage(text);
qApp->processEvents();
}
void Glass::infinitely(QString text)
{
qDebug() << _haveProgress << _haveMessage;
if(!_haveProgress)
{
progressBar = new QProgressBar(0);
progressBar->hide();
progressBar->setObjectName(QString::fromUtf8("progressBar"));
progressBar->setValue(0);
progressBar->setMaximum(0);
progressBar->setAlignment(Qt::AlignCenter);
progressBar->setTextVisible(false);
progressBar->setOrientation(Qt::Horizontal);
progressBar->setInvertedAppearance(false);
progressBar->setParent(_parent);
}
progressBar->setMinimum(0);
progressBar->setMaximum(0);
progressBar->startTimer(0);
if(!_haveMessage)
{
infoText = new QLabel(0);
infoText->hide();
infoText->setAlignment(Qt::AlignCenter);
infoText->setWordWrap(true);
infoText->setStyleSheet("color:#fff;");
infoText->setParent(_parent);
}
infoText->setText(text);
infoText->show();
progressBar->show();
_haveProgress = true;
_haveMessage = true;
positioning();
}
Пример использования :
// например, в слоте для QPushButton::clicked()
...
Glass *glass = new Glass("Step #1", 152);
glass->setAnimationDuration(200);
connect(glass, SIGNAL(initailized(int)), this, SLOT(steps(int)));
glass->init(qobject_cast<QWidget *>(sender()->parent()));
...
void MainWindow::steps(int steps)
{
Glass *glass = qobject_cast<Glass *>(sender());
if(steps > 0)
{
QTime time;
time.start();
for(int i=0; i<steps; )
{
if(time.elapsed() > 20)
{
time.start();
++i;
glass->nextStep(QString("Step #%1").arg(i+1));
}
}
}
else
{
QTime time;
time.start();
glass->infinitely("loading...");
while(time.elapsed() < 5000)
{
qApp->processEvents();
}
}
glass->hideAndDelete();
}