Допустим, в приложении необходимо обеспечить временную блокировку Ui-формы до наступления определенного события (действия со стороны пользователя или завершения фонового потока выполнения задачи).
В этом случае можно заблокировать все виджеты формы (поля ввода, ползунки, и т.д.) явно с помощью вызова setDisabled(). В Qt для этих целей предусмотрено вполне универсальное и эффективное решение через цикл. Однако большую свободу можно получить, если организовать блокировку более радикальными методами.
Существует несколько подходов. Первый из них заключается в отображении одного виджета над другим. Еще один вариант сводится к использованию QStackedWidget. На последнем мы и сосредоточимся.
Для создания эффекта блокировки мы:
- Делаем скриншот виджета (он расположен на первой странице QStackedWidget), который собираемся заблокировать, с помощью QProxy::grabWidget();
- Закрашиваем получившееся изображение полупрозрачным серым цветом;
- Устанавливаем изображение в QLabel, который находится на соседней странице QStackedWidget;
- Переключаемся на страницу с подготовленным на предыдущем шаге QLabel.
В примере переход между режимами осуществляется с помощью гиперссылок Active и Passive.
Реализация не намного сложнее идеи. Файл proxywidgetdemo.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#ifndef PROXYWIDGETDEMO_H #define PROXYWIDGETDEMO_H #include <QWidget> namespace Ui { class ProxyWidgetDemo; } class ProxyWidgetDemo : public QWidget { Q_OBJECT public: explicit ProxyWidgetDemo( QWidget* parent = 0 ); ~ProxyWidgetDemo(); protected: void resizeEvent( QResizeEvent* e ); private slots: void onHyper( const QString& href ); private: Ui::ProxyWidgetDemo* ui; }; #endif // PROXYWIDGETDEMO_H |
Файл proxywidgetdemo.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include "proxywidgetdemo.h" #include "ui_proxywidgetdemo.h" #include <QPainter> ProxyWidgetDemo::ProxyWidgetDemo( QWidget* parent ) : QWidget( parent ), ui( new Ui::ProxyWidgetDemo ) { ui->setupUi( this ); connect( ui->lbProxyMode, SIGNAL( linkActivated( QString ) ), SLOT( onHyper( QString ) ) ); } ProxyWidgetDemo::~ProxyWidgetDemo() { delete ui; } void ProxyWidgetDemo::resizeEvent( QResizeEvent* ) { if( ui->stackedWidget->currentWidget() == ui->page_Passive ) { onHyper( "show-active" ); onHyper( "show-passive" ); } } void ProxyWidgetDemo::onHyper( const QString& href ) { if( href == "show-active" ) { ui->lbProxyView->clear(); ui->stackedWidget->setCurrentWidget( ui->page_Active ); } else if( href == "show-passive" ) { QPixmap pix = QPixmap::grabWidget( ui->page_Active ); QImage proxyImg( pix.size(), QImage::Format_ARGB32 ); QPainter p; p.begin( &proxyImg ); p.drawPixmap( 0, 0, pix ); p.fillRect( proxyImg.rect(), QColor( 0, 0, 0, 130 ) ); p.end(); ui->lbProxyView->setPixmap( QPixmap::fromImage( proxyImg ) ); ui->stackedWidget->setCurrentWidget( ui->page_Passive ); } } |
Алгоритм переключения практически дословно следует нашей задумке, поэтому не будем на нем останавливаться. Однако имеется несколько важных замечаний:
- Нам приходится явно обрабатывать событие resizeEvent(), когда мы находимся в режиме блокировки, поскольку само по себе изображение не обновится;
- QLabel, в который мы выводим «заблокированное» изображение, пришлось поместить в QScrollArea с отключенными полосами прокрутки, поскольку иначе уменьшение окна в режиме блокировки становилось невозможным. Кроме того, для QLabel установлен режим выравнивания по левому верхнему краю для предотвращения «скачков» картинки при изменении размеров окна.
В реальном приложении вы можете пойти как по пути усложнения рассмотренной идеи (например, добавив крутые графические эффекты с градиентами, значками и прочими украшательствами), так и по пути упрощения (например, вовсе отбросить идею создания скриншота виджета, и просто выводить статичный текст или анимированный индикатор занятости).