Qt 使用QDialog實現(xiàn)界面遮罩的示例(蒙版)
寫應用程序的過程中,彈窗是個避免不了的功能,顯示中,假設彈窗背景色和主窗口背景色相差不多,甚至是一樣的時候,就會存在一個比較嚴重的人機交互和UI顯示的問題,找到彈窗的邊界是比較麻煩的一件事。但是如果我們能在彈窗顯示的時候被主窗口其他的部位增加一個背景色,這個背景色與彈窗的背景色形成比較大的色差,那么是不是就能夠很容易的找到彈窗的邊界。因此,我們實現(xiàn)一個自定義組件,可隨便設置需要遮罩的主窗口,并且能夠讓其跟隨主窗口的移動而移動。
先來看下效果:

- 根據(jù)需求功能,我們需要提供設置主窗口的接口,同樣的,并不是說所有的窗口都需要進行遮罩,那么我們也同樣需要知道哪些窗口是需要遮罩的,因此,還需要提供一個判斷的標準,在一個工程里面,每個UI文件的objectName是獨一份的,因此我們可以通過這些objectName來判斷哪些dialog需要遮罩。
- 該類是在需要被遮罩的dialog顯示出來的時候自動調(diào)用顯示,而不需要手動調(diào)用,因此需要檢測全局的事件循環(huán)。
以上,我們來看下該組件的頭文件定義:
#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由上面的類定義也能夠看出來,這個組件還是比較簡單的,簡單到只有兩個接口和一個事件過濾函數(shù),所以下面,我們來具體看下其中的實現(xiàn)。
首先是千篇一律的單例實現(xiàn),該組件在整個工程中獨一份就好,多了可能就會出現(xiàn)你想不到的情況(多層覆蓋或者沖突了):
MaskWidget * MaskWidget::m_pSelf = Q_NULLPTR;
MaskWidget * MaskWidget::instance()
{
if (m_pSelf == Q_NULLPTR)
{
m_pSelf = new MaskWidget;
}
return m_pSelf;
}在其構造中,我們需要設置一些window相關的屬性,并且將該窗口先隱藏起來,要不然程序一打開就會看到整個上面有一層灰蒙蒙的遮罩。其實最主要的是需要在其構造函數(shù)里面注冊事件過濾。
MaskWidget::MaskWidget(QWidget *parent) : QDialog(parent), ui(new Ui::MaskWidget)
{
ui->setupUi(this);
hide();
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowDoesNotAcceptFocus);
qApp->installEventFilter(this);
}在主程序啟動之后,我們還要做兩件事,也就是我們前面說的兩個接口需要調(diào)用實現(xiàn),一個是設置需要遮罩的主窗口,一個是需要設置彈出需要遮罩的窗口的名稱,先看下設置主窗口。
void MaskWidget::setMainWidget(QWidget *pWidget)
{
this->setFixedSize(QSize(pWidget->width(), pWidget->height()));
this->setParent(pWidget);
this->move(pWidget->x(), pWidget->y());
}由上面可以看出,設置主窗口之后,我們將該組件的父類也設置為了主窗口,這樣就能保證該組件顯示出來的時候一定是以設置的主窗口為父節(jié)點進行顯示,并且能夠鋪滿整個主窗口。
顯示窗口的設置也是比較簡單的屬性的操作方式,如下:
void MaskWidget::setNames(const QStringList& names)
{
if(m_listName == names)
{
return;
}
m_listName = names;
}
QStringList MaskWidget::names() const
{
return names;
}在整個過程中,其實最主要的是事件過濾函數(shù)的實現(xiàn),該函數(shù)基本包含了該組件的基本功能,下面我們看下該函數(shù)的實現(xiàn)。
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轉(zhuǎn)換為普通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); //將主窗口設置放到該組件界面下方,就能夠有一個比較清晰的層次關系
//下面是實現(xiàn)將彈窗的位置移動到主程序的正中間,在這邊實現(xiàn)的目的是為了減少代碼量,畢竟寫代碼能偷的懶還是一定要偷的
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,并且在調(diào)用時使用QDialog::exec()函數(shù)實現(xiàn)模態(tài)。如果不實現(xiàn)模態(tài)的話,會出現(xiàn)一些意外,當然這些意外并不影響使用,只是交互上面會比較不友好。假設你的主程序不能移動,那么就會很不友好。
TestDialog dlg;
if(QDialog::Accept == dlg.exec())
{
}測試代碼鏈接:https://gitee.com/Gqian_com/customcomponent/tree/master/maskwidget
到此這篇關于Qt 使用QDialog實現(xiàn)界面遮罩的示例(蒙版)的文章就介紹到這了,更多相關Qt QDialog界面遮罩內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++ LeetCode1775通過最少操作次數(shù)使數(shù)組和相等
這篇文章主要為大家介紹了C++ LeetCode1775通過最少操作次數(shù)使數(shù)組和相等,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
C++實現(xiàn)LeetCode(50.求x的n次方)
這篇文章主要介紹了C++實現(xiàn)LeetCode(50.求x的n次方),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07
一文詳解C語言中的switch語句和while循環(huán)
這篇文章主要給大家詳細介紹了C語言中的switch語句和while循環(huán),文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2023-12-12

