这篇文章主要介绍了Qt怎么使用QDialog实现界面遮罩的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Qt怎么使用QDialog实现界面遮罩文章都会有所收获,下面我们一起来看看吧。
先来看下效果:
根据需求功能,我们需要提供设置主窗口的接口,同样的,并不是说所有的窗口都需要进行遮罩,那么我们也同样需要知道哪些窗口是需要遮罩的,因此,还需要提供一个判断的标准,在一个工程里面,每个UI文件的objectName是独一份的,因此我们可以通过这些objectName来判断哪些dialog需要遮罩。
该类是在需要被遮罩的dialog显示出来的时候自动调用显示,而不需要手动调用,因此需要检测全局的事件循环。
以上,我们来看下该组件的头文件定义:
#ifndef MASK_WIDGET_H#define MASK_WIDGET_H#include <QDialog>namespace Ui { class MaskWidget;}class MaskWidget : public QDialog{ Q_OBJECT Q_PROPERTY(QStringList names READ names WRITE setNames DESIGNABLE true)public: static MaskWidget *instance(); void setMainWidget(QWidget* pWidget); QStringList names() const; void setNames(const QStringList& names);protected: bool eventFilter(QObject *obj, QEvent *event);private: explicit MaskWidget(QWidget *parent = Q_NULLPTR); ~MaskWidget();private: Ui::MaskWidget* ui; QStringList m_listName{ QStringList() }; QWidget* m_pMainWidget{ Q_NULLPTR }; static MaskWidget* m_pSelf;};#endif // MASK_WIDGET_H
由上面的类定义也能够看出来,这个组件还是比较简单的,简单到只有两个接口和一个事件过滤函数,所以下面,我们来具体看下其中的实现。
首先是千篇一律的单例实现,该组件在整个工程中独一份就好,多了可能就会出现你想不到的情况(多层覆盖或者冲突了):
MaskWidget * MaskWidget::m_pSelf = Q_NULLPTR;MaskWidget * MaskWidget::instance(){if (m_pSelf == Q_NULLPTR){m_pSelf = new MaskWidget;}return m_pSelf;}
在其构造中,我们需要设置一些window相关的属性,并且将该窗口先隐藏起来,要不然程序一打开就会看到整个上面有一层灰蒙蒙的遮罩。其实最主要的是需要在其构造函数里面注册事件过滤。
MaskWidget::MaskWidget(QWidget *parent) : QDialog(parent), ui(new Ui::MaskWidget){ ui->setupUi(this); hide(); setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowDoesNotAcceptFocus); qApp->installEventFilter(this);}
在主程序启动之后,我们还要做两件事,也就是我们前面说的两个接口需要调用实现,一个是设置需要遮罩的主窗口,一个是需要设置弹出需要遮罩的窗口的名称,先看下设置主窗口。
void MaskWidget::setMainWidget(QWidget *pWidget){ this->setFixedSize(QSize(pWidget->width(), pWidget->height())); this->setParent(pWidget); this->move(pWidget->x(), pWidget->y());}
由上面可以看出,设置主窗口之后,我们将该组件的父类也设置为了主窗口,这样就能保证该组件显示出来的时候一定是以设置的主窗口为父节点进行显示,并且能够铺满整个主窗口。
显示窗口的设置也是比较简单的属性的操作方式,如下:
void MaskWidget::setNames(const QStringList& names){ if(m_listName == names) { return; } m_listName = names; } QStringList MaskWidget::names() const { return names; }
在整个过程中,其实最主要的是事件过滤函数的实现,该函数基本包含了该组件的基本功能,下面我们看下该函数的实现。
bool MaskWidget::eventFilter(QObject *obj, QEvent *event){ if(event->type() == QEvent::Hide) { if(m_listName.contains(obj->objectName())) { hide(); } return QObject::eventFilter(obj, event); } if (event->type() == QEvent::Show) { if (!m_listName.contains(obj->objectName())) { return QObject::eventFilter(obj, event); } show(); auto pWidget = dynamic_cast<QWidget*>(obj); //将object转换为普通QWidget if (Q_NULLPTR == pWidget) { return QObject::eventFilter(obj, event); } pWidget->activateWindow(); pWidget->setFocus(Qt::ActiveWindowFocusReason); stackUnder(pWidget); //将该窗口设置放到弹窗的下面 if(Q_NULLPTR == m_pMainWidget) { return QObject::eventFilter(obj, event); } m_pMainWidget->stackUnder(this); //将主窗口设置放到该组件界面下方,就能够有一个比较清晰的层次关系 //下面是实现将弹窗的位置移动到主程序的正中间,在这边实现的目的是为了减少代码量,毕竟写代码能偷的懒还是一定要偷的 QRect screenGeometry = m_pMainWidget->geometry(); int x = screenGeometry.x() + (screenGeometry.width() - pWidget->width()) / 2; int y = screenGeometry.y() + (screenGeometry.height() - pWidget->height()) / 2; pWidget->move(x, y); } return QObject::eventFilter(obj, event);}
以上,该组件的全部功能介绍完了。
使用的过程中了,直接包含文件就能够使用,需要注意的是,弹出的dialog窗口的基类必须QDialog,并且在调用时使用QDialog::exec()函数实现模态。如果不实现模态的话,会出现一些意外,当然这些意外并不影响使用,只是交互上面会比较不友好。假设你的主程序不能移动,那么就会很不友好。
TestDialog dlg;if(QDialog::Accept == dlg.exec()){}
关于“Qt怎么使用QDialog实现界面遮罩”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Qt怎么使用QDialog实现界面遮罩”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。