Qt無邊框窗體-模擬模態窗體抖動效果
目錄
- 一、概述
- 二、效果展示
- 三、功能實現
- 四、相關文章
原文連結:Qt無邊框窗體-模擬模態窗體抖動效果
一、概述
用Qt開發windows客戶端介面確實是一大利器,兼顧效能的同時,速度相對來說也不錯。再加上qss的輔助,那麼一個漂亮的介面就不在話下了。
想要做出漂亮的介面,重寫一個標題欄是必不可少的,那麼我們肯定是需要使用Qt給我們提供的一個無邊框Qt::FramelessWindowHint窗體屬性。但是設定了這個屬性以後,隨之而來的就是一系列的問題,比如說標題欄拖拽需要我們自己搞;視窗放大縮小需要自己實現;最要命的是一些模態窗體原生的抖動效果沒有了。
既然出現問題,那麼我們就得想辦法解決。
視窗放大縮小和拖拽在Qt的早期版本是提供了一個類檔案支援的,作者本人也對這個檔案進行了二次開發,可以提供更為豐富的功能。由於拖拽和縮放跟本篇文章關係不大,因此這裡不做說明,感興趣的同學可以到Qt無邊框窗體-最大化時支援拖拽還原這裡檢視
本篇文章我們就來說一說當模態窗體彈出來時,如果點選了非模態窗體以外的應用程式介面,怎麼實現一個閃動的效果。
閃動只是一個對外的資訊互動,如果大家想要一些其他互動效果,可以自行實現。
二、效果展示
如效果圖所示,做了一個簡單的效果
- 點選主應用程式時,彈出的模態窗體邊框顏色發生了變動,實現了一個抖動的效果。
- 點選桌面時,模態窗體也有一個失去焦點時的狀態變化。
三、功能實現
實現視窗抖動效果,首先需要了解windows的訊息ID,知道我們要接受哪個windows訊息來完成閃動效果,其次就是Qt怎麼接收這樣的原生windows訊息。
windowws訊息
瞭解windows訊息ID,隨手開啟一個搜尋引擎,輸入關鍵字Windows訊息ID
,然後就能找到大量的文章專門講述windwos訊息,博主這裡找了一篇整理windows訊息列表的文章Windows訊息ID說明,文章中的訊息基本上都有中文註釋,因此閱讀起來比較容易。
然後我們就會發現有這樣一個訊息,可能是我們需要的,如下圖所示。
第130條內容,ID為86的WM_NCACTIVATE訊息。訊息觸發的實際是當某個視窗它的非客戶區需要被改變來顯示是啟用還是非啟用狀態時。 聽著有點兒意思,好像是我們需要的,然後就試唄。
Qt接收原生訊息
既然鎖定了訊息ID,那麼接下來就是接收這個訊息,然後實現響應的UI互動效果即可。
那麼問題來了,Qt視窗怎麼接收windows原生訊息呢!
這個問題當然難不倒我們了。Qt為啥這麼火,可不僅僅是因為庫封裝的好,而是它幫助文件更全。下一步大家應該知道該幹什麼了吧,開啟幫助文件,然後搜尋關鍵字nativeEv
,如果不知道函式的具體名字或者功能名字,最好進行模糊搜尋。
不搜不知道,一搜嚇一跳,原來還有不少接收原生訊息的函式,如下不所示。
上圖中總共有如下幾個函式
- filterNativeEvent:安裝事件過濾器的回撥函式
- installNativeEventFilter:安裝事件過濾器,回撥函式是第4個函式
- nativeEvent:視窗原生事件回撥
- nativeEventFilter:事件過濾器回撥函式,使用方法2安裝
看到這裡大家卡能會有些迷茫,好像都差不多呀!其實不然,還是有卻別的,感興趣的同學可以看看我之前寫的幾篇相關文章,都使用了接收全域性windows訊息來實現先關功能,具體一點來說就是使用上述的方法2+方法4來完成。
- Qt之自定義QLineEdit右鍵選單
- qt捕獲全域性windows訊息
- Qt之股票元件-股票檢索--支援搜尋結果預覽、滑鼠、鍵盤操作
除過方法2和方法4搭配起來使用外,方法1和方法2也可以一起搭配使用,言外之意就是方法2是按照事件過濾器的,方法1和方法4只是事件過濾器的回撥處理介面而已。
為什麼這麼說呢,大家可以來驗證一下,還是開啟幫助文件,我們輸入關鍵字installNativeEventFilter
,回車就會發現,事件過濾器可以被安裝到兩個物件上,一個是我們熟知的QCoreApplication,另外一個看著好像也會牛逼的樣子,好像還是一個全域性的抽象事件派發器。恭喜你,答對了,這兩個物件都很牛逼,都能優先處理到Qt的全域性事件。
本篇文章我們只是要實現一個模態窗體的抖動而已,因此就不需要大材小用了,我們使用QWidget的nativeEvent函式即可,同樣能達到我們的目的。
大方向都定了,那麼還等什麼
開啟vs,新建了一個demo。哐哐哐,就是一頓幹。。。。
發現還真好使,竊喜中。。。
下面是實現的核心程式碼,由於是demo,所以寫的比較粗糙,大家在寫到專案裡時最好能規範下程式碼。
bool XXX::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
if ("windows_generic_MSG" == eventType)
{
MSG * pMsg = reinterpret_cast<MSG *>(message);
if (pMsg->message == WM_NCACTIVATE)
{
bool active = (bool)(pMsg->wParam);
if (active)
{
setStyleSheet("border:2 solid blue;background:gray;");
}
else
{
setStyleSheet("border:2 solid red;background:gray;");
}
style()->unpolish(this);
style()->polish(this);
}
}
return QDialog::nativeEvent(eventType, message, result);
}
重點強調
這裡還需要說一點,有些同學按照文件操作了,除錯時程式碼也走到相關位置了,但是發現沒有效果,然後就開始懷疑人生了。
這裡博主重點說幾個可能出現錯誤的地方
- 我們的模態窗體一定要指定模態的父窗體是誰
- 窗體一定要設定上Qt::Dialog屬性
第二點是非常關鍵的,很多同學都是沒有設定這個屬性,導致失去了效果。
四、相關文章
- Qt自定義的無邊框Dialog 在點選其他視窗時處理閃爍效果
- Qt無邊框窗體-最大化時支援拖拽還原
- Qt之自定義QLineEdit右鍵選單
- qt捕獲全域性windows訊息
- Qt之股票元件-股票檢索--支援搜尋結果預覽、滑鼠、鍵盤操作
值得一看的優秀文章:
- 財聯社-產品展示
- 廣聯達-產品展示
- Qt定製控制元件列表
- 牛逼哄哄的Qt庫
如果您覺得文章不錯,不妨給個打賞,寫作不易,感謝各位的支援。您的支援是我最大的動力,謝謝!!!
很重要--轉載宣告
本站文章無特別說明,皆為原創,版權所有,轉載時請用連結的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords
如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。