Russian Qt Forum
Ноябрь 01, 2024, 04:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Glass (эффект "затемнения" виджета при длительной операции)  (Прочитано 9011 раз)
yaroslav429
Гость
« : Декабрь 29, 2010, 03:22 »

Возникла необходимость отображать пользователю статус работы приложения при длительных расчетах, да так, что бы виджет, в котором обновляется информация был недоступен.

Написал небольшой класс (пример использования во вложении), который с горем-пополам выполняет данную задачу: указанный виджет затемняется с возможностью отображения текста и прогрессбара (по надобности).
Сильно не пинайте, а лучше, по возможности, укажите грубые ошибки, подскажите как улучшить.
Надеюсь, что кому-то пригодится Подмигивающий

Небольшое описание публичных методов :
    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();
}
« Последнее редактирование: Декабрь 29, 2010, 03:25 от yaroslav429 » Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #1 : Январь 07, 2011, 15:57 »

Идея хорошая, мне нравится Улыбающийся

Код немного кривоват, надо бы рихтануть, но у меня к сожалению сейчас нет времени Грустный
Может кто другой поможет?

ЗЫЖ Я вот тут подумал, а не сорганизовать ла нам свою либу по дополнениям к Qt по аналогии с libqxt?

Основное требование к ней, чтобы она была легковесной и с возможностью выдирать определенные классы для своего проекта (то бишь минимум внутренних зависимостей)...

Разместить ее на каком-нить гуглокоде или житхабе...
Записан

Гугль в помощь
_govorilka
Гость
« Ответ #2 : Январь 14, 2011, 09:59 »

ЗЫЖ Я вот тут подумал, а не сорганизовать ла нам свою либу по дополнениям к Qt по аналогии с libqxt?

Основное требование к ней, чтобы она была легковесной и с возможностью выдирать определенные классы для своего проекта (то бишь минимум внутренних зависимостей)...

Разместить ее на каком-нить гуглокоде или житхабе...

Начал делать небольшую либу:
http://code.google.com/p/fireworks/

Буду выкладывать сюда общие куски из проекта, которые делаю на работе.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #3 : Январь 14, 2011, 10:31 »

2 yaroslav429
Не мешало бы все аргументы "QString" поменять на "const QString&" и делать так всю оставшуюся жизнь)
Записан

Qt 5.11/4.8.7 (X11/Win)
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #4 : Январь 17, 2011, 20:26 »

Начал делать небольшую либу:
http://code.google.com/p/fireworks/

Буду выкладывать сюда общие куски из проекта, которые делаю на работе.

Ну это замечательно, но либа немного не в тему:
>> Framework for creating GUI for embedded system based on Qt library
>> This framework based on QtCore library, but not used QtGui

Embedded это не общее направление.
И название Fireworks ни о чем не говорящее..

Кстати зачем делать свой Embedded когда есть Qt Embedded?
Записан

Гугль в помощь
_govorilka
Гость
« Ответ #5 : Январь 19, 2011, 12:07 »

Кстати зачем делать свой Embedded когда есть Qt Embedded?

 В Qt Embedded не хватает гибкости. Проект Lighthouse еще пока живет только в лаборатории и  не является частью "официального" Qt. Но это тема для отдельной ветки на форуме. Тему сейчас подниму, возможно кому-то будет интересно...
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.049 секунд. Запросов: 23.