一.效果
二.原理
原理很简单,就是在主窗口上覆盖一层半透明窗口,然后把需要遮罩显示的窗口(嵌入窗口)布局到该半透明窗口中
网上很多实现方法是将主窗口截图绘制到遮罩窗口,然后再调用QPainter的fillRectr(rect(), QColor(0,0,0,100))来实现半透明效果,这种方法显然是不行的,因为这样的话就看不到主窗口中的动图了
因此需要直接把遮罩窗口设置为半透明效果,这样就能看到主窗口中的动图,如效果图所示,遮罩时依然能看到滚动条和动图的动画效果
设置遮罩窗口半透明的代码如下
QHMaskWidget::QHMaskWidget(QWidget *parent)
: QWidget(parent)
, m_embeddedWindow(nullptr)
{
parent->installEventFilter(this);
setVisible(false);
QPalette pal(palette());
pal.setColor(QPalette::Background, QColor(0, 0, 0, 100));
setAutoFillBackground(true);
setPalette(pal);
}
使用时,将主窗口的指针传到遮罩窗口QHMaskWidget的构造函数中,在该构造函数中会调用主窗口指针安装事件过滤器,这样在遮罩窗口中就可以处理主窗口的事件
这里要过滤主窗口的Resize事件,因为遮罩窗口需要在主窗口缩放时,依然能完整覆盖,代码如下
bool QHMaskWidget::eventFilter(QObject *object, QEvent *event)
{
if (isVisible() && object == parentWidget() && event->type() == QEvent::Resize)
{
resize(parentWidget()->size());
}
if (isVisible() && m_embeddedWindow && object == m_embeddedWindow && event->type() == QEvent::Close)
{
setVisible(false);
}
return QWidget::eventFilter(object, event);
}
m_embeddedWindow是嵌入窗口的指针,嵌入窗口也需要安装事件过滤器来监测器close事件,因为嵌入窗口关闭时,需要隐藏遮罩窗口
下面就是如何将嵌入窗口添加到遮罩窗口的布局中
void QHMaskWidget::addEmbeddedWindow(QWidget *window)
{
m_embeddedWindow = window;
window->setFixedSize(window->size());
window->installEventFilter(this);
QGridLayout *gLayout = new QGridLayout();
gLayout->addWidget(window);
gLayout->setMargin(0);
setLayout(gLayout);
}
要显示遮罩窗口的话,调用其show方法即可
void QHMaskWidget::show()
{
resize(parentWidget()->size());
if(m_embeddedWindow)
{
m_embeddedWindow->setVisible(true);
}
setVisible(true);
}
三.实现
QHMaskWidget完整代码如下
QHMaskWidget.h
#ifndef QHMASKWIDGET_H
#define QHMASKWIDGET_H
#include <QWidget>
class QHMaskWidget : public QWidget
{
Q_OBJECT
public:
explicit QHMaskWidget(QWidget *parent);
void show();
void addEmbeddedWindow(QWidget *widget);
protected:
bool eventFilter(QObject *object, QEvent *event);
private:
QWidget *m_embeddedWindow;
};
#endif // QHMASKWIDGET_H
QHMaskWidget.cpp
#include "QHMaskWidget.h"
#include <QEvent>
#include <QPaintEvent>
#include <QGridLayout>
#include <QDebug>
#include <QPalette>
QHMaskWidget::QHMaskWidget(QWidget *parent)
: QWidget(parent)
, m_embeddedWindow(nullptr)
{
parent->installEventFilter(this);
setVisible(false);
QPalette pal(palette());
pal.setColor(QPalette::Background, QColor(0, 0, 0, 100));
setAutoFillBackground(true);
setPalette(pal);
}
void QHMaskWidget::show()
{
resize(parentWidget()->size());
if(m_embeddedWindow)
{
m_embeddedWindow->setVisible(true);
}
setVisible(true);
}
void QHMaskWidget::addEmbeddedWindow(QWidget *window)
{
m_embeddedWindow = window;
window->setFixedSize(window->size());
window->installEventFilter(this);
QGridLayout *gLayout = new QGridLayout();
gLayout->addWidget(window);
gLayout->setMargin(0);
setLayout(gLayout);
}
bool QHMaskWidget::eventFilter(QObject *object, QEvent *event)
{
if (isVisible() && object == parentWidget() && event->type() == QEvent::Resize)
{
resize(parentWidget()->size());
}
if (isVisible() && m_embeddedWindow && object == m_embeddedWindow && event->type() == QEvent::Close)
{
setVisible(false);
}
return QWidget::eventFilter(object, event);
}
使用方法
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "testwindow.h"
#include <QMovie>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMovie *movie = new QMovie(":/icons/Luffy.gif");
movie->start();
ui->label->setMovie(movie);
// 遮罩窗口.
m_maskWidget = new QHMaskWidget(this);
// 嵌入窗口.
TestWindow *testWindow = new TestWindow(this);
m_maskWidget->addEmbeddedWindow(testWindow);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
m_maskWidget->show();
}