Допустим, в приложении необходимо обеспечить временную блокировку Ui-формы до наступления определенного события (действия со стороны пользователя или завершения фонового потока выполнения задачи).
В этом случае можно заблокировать все виджеты формы (поля ввода, ползунки, и т.д.) явно с помощью вызова setDisabled()
. В Qt для этих целей предусмотрено вполне универсальное и эффективное решение через цикл. Однако большую свободу можно получить, если организовать блокировку более радикальными методами.
Существует несколько подходов. Первый из них заключается в отображении одного виджета над другим. Еще один вариант сводится к использованию QStackedWidget
. На последнем мы и сосредоточимся.
Готовое решение будет выглядеть следующим образом (слева - активный виджет, а справа - заблокированный):
Для создания эффекта блокировки мы:
QStackedWidget
), который собираемся заблокировать, с помощью QProxy::grabWidget()
;QLabel
, который находится на соседней странице QStackedWidget
;QLabel
.В примере переход между режимами осуществляется с помощью гиперссылок Active
и Passive
.
Реализация не намного сложнее идеи. Файл proxywidgetdemo.h
:
Завод спорта это силовые тренажеры для спортзала и дома.
#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
:
#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
установлен режим выравнивания по левому верхнему краю для предотвращения "скачков" картинки при изменении размеров окна.В реальном приложении вы можете пойти как по пути усложнения рассмотренной идеи (например, добавив крутые графические эффекты с градиентами, значками и прочими украшательствами), так и по пути упрощения (например, вовсе отбросить идею создания скриншота виджета, и просто выводить статичный текст или анимированный индикатор занятости).
Скачать пример использования QStackedWidget для создания эффекта блокировки Ui-форм
Anonymous:
А нельзя ли установить пустой виджет с прозрачным фоном, чтобы не делать скрин ?
Можно пойти и таким путем. Представленное в статье решение является лишь одним из возможных вариантов.
Anonymous
А нельзя ли установить пустой виджет с прозрачным фоном, чтобы не делать скрин ?