当主窗体需要弹出一个窗体用于给用户输入时,如果只是单存的显示出来,就会显得很单调;
如果加上背景黑色半透明的话,效果就会很不错!如下图效果: 
使用
新建项目,并新建窗体用于显示弹窗;

主窗体是widget,手动新建的窗体是dialogform。
然后在项目中添加如下两个代码文件
maskwidget.h
cpp
#ifndef MASKWIDGET_H
#define MASKWIDGET_H
/**
* 1. 可设置需要遮罩的主窗体,自动跟随主窗体位置显示遮罩面积
* 2. 只需要将弹窗窗体的名称一开始传入队列即可,足够简单
* 3. 可设置透明度
* 4. 可设置遮罩层颜色
* 5. 不阻塞消息循坏
*/
#include <QWidget>
#ifdef quc
class Q_DECL_EXPORT MaskWidget : public QWidget
#else
class MaskWidget : public QWidget
#endif
{
Q_OBJECT
public:
static MaskWidget *Instance();
explicit MaskWidget(QWidget *parent = 0);
protected:
void showEvent(QShowEvent *);
bool eventFilter(QObject *obj, QEvent *event);
private:
static QScopedPointer<MaskWidget> self;
QWidget *mainWidget; //需要遮罩的主窗体
QStringList dialogNames; //可能弹窗的窗体对象名称集合链表
public Q_SLOTS:
void setMainWidget(QWidget *mainWidget);
void setDialogNames(const QStringList &dialogNames);
void setBgColor(const QColor &bgColor);
void setOpacity(double opacity);
private:
QColor m_bgColor; // 添加颜色成员变量
};
#endif // MASKWIDGET_H
maskwidget.cpp
cpp
#pragma execution_character_set("utf-8")
#include "maskwidget.h"
#include "qmutex.h"
#include "qdesktopwidget.h"
#include "qapplication.h"
#include "qdebug.h"
QScopedPointer<MaskWidget> MaskWidget::self;
MaskWidget *MaskWidget::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new MaskWidget);
}
}
return self.data();
}
MaskWidget::MaskWidget(QWidget *parent) : QWidget(parent)
{
mainWidget = nullptr;
m_bgColor = QColor(0, 0, 0);
// 设置初始透明度
setOpacity(0.7);
// 不设置主窗体则遮罩层大小为默认桌面大小
this->setGeometry(qApp->desktop()->geometry());
// 修改窗口标志,增强兼容性
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
// 设置属性,允许透明区域点击穿透(部分Linux桌面环境支持)
this->setAttribute(Qt::WA_TransparentForMouseEvents, false);
// 绑定全局事件,过滤弹窗窗体进行处理
qApp->installEventFilter(this);
}
void MaskWidget::setMainWidget(QWidget *mainWidget)
{
if (this->mainWidget != mainWidget) {
this->mainWidget = mainWidget;
}
}
void MaskWidget::setDialogNames(const QStringList &dialogNames)
{
if (this->dialogNames != dialogNames) {
this->dialogNames = dialogNames;
}
}
void MaskWidget::setOpacity(double opacity)
{
this->setWindowOpacity(opacity);
// Linux兼容性:同时使用样式表设置透明度
int alpha = static_cast<int>(opacity * 255);
QString style = QString("background-color: rgba(%1, %2, %3, %4);")
.arg(m_bgColor.red())
.arg(m_bgColor.green())
.arg(m_bgColor.blue())
.arg(alpha);
this->setStyleSheet(style);
}
void MaskWidget::setBgColor(const QColor &bgColor)
{
m_bgColor = bgColor;
QPalette palette = this->palette();
palette.setBrush(QPalette::Window, bgColor);
this->setPalette(palette);
// 更新样式表
setOpacity(this->windowOpacity());
}
void MaskWidget::showEvent(QShowEvent *)
{
if (mainWidget != 0) {
this->setGeometry(mainWidget->geometry());
}
}
bool MaskWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Show) {
if (dialogNames.contains(obj->objectName())) {
this->show();
this->activateWindow();
QWidget *w = (QWidget *)obj;
w->activateWindow();
}
} else if (event->type() == QEvent::Hide) {
if (dialogNames.contains(obj->objectName())) {
this->hide();
}
} else if (event->type() == QEvent::WindowActivate) {
//当主窗体激活时,同时激活遮罩层
if (mainWidget != 0) {
if (obj->objectName() == mainWidget->objectName()) {
if (this->isVisible()) {
this->activateWindow();
}
}
}
}
return QObject::eventFilter(obj, event);
}
之后,就可以在主窗体(widget.cpp)中添加如下代码进行测试:
widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDialog>
#include <QDebug>
#include "maskwidget/maskwidget.h"
#include "dialogform.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
initMaskWidget();
QPushButton *btn = new QPushButton("dialog弹窗", this);
btn->move(width() / 2, height() / 2);
connect(btn, &QPushButton::clicked, this, &Widget::onBtnClicked);
}
Widget::~Widget()
{
delete ui;
}
void Widget::initMaskWidget()
{
qDebug() << "Initializing MaskWidget...";
MaskWidget *mask = MaskWidget::Instance();
mask->setMainWidget(this); // 设置主窗口
// 设置需要遮罩的对话框名称
QStringList dialogNames;
dialogNames << "DialogForm"; // 必须与窗口设置的objectName一致
mask->setDialogNames(dialogNames);
mask->setBgColor(QColor(0, 0, 0)); // 使用黑色背景
mask->setOpacity(0.6); // 增加不透明度
qDebug() << "MaskWidget initialized with dialogNames:" << dialogNames;
}
void Widget::onBtnClicked()
{
DialogForm d;
d.exec();
// d.show();
}
重点关注void Widget::initMaskWidget()是如何处理的。
