Qt無邊框窗體-模擬模態窗體抖動效果

原文鏈接:Qt無邊框窗體-模擬模態窗體抖動效果

一、概述

用Qt開發windows客戶端界面確實是一大利器,兼顧性能的同時,速度相對來說也不錯。再加上qss的輔助,那麼一個漂亮的界面就不在話下了。

想要做出漂亮的界面,重寫一個標題欄是必不可少的,那麼我們肯定是需要使用Qt給我們提供的一個無邊框Qt::FramelessWindowHint窗體屬性。但是設置了這個屬性以後,隨之而來的就是一系列的問題,比如說標題欄拖拽需要我們自己搞;窗口放大縮小需要自己實現;最要命的是一些模態窗體原生的抖動效果沒有了。

既然出現問題,那麼我們就得想辦法解決。

窗口放大縮小和拖拽在Qt的早期版本是提供了一個類文件支持的,作者本人也對這個文件進行了二次開發,可以提供更爲豐富的功能。由於拖拽和縮放跟本篇文章關係不大,因此這裏不做說明,感興趣的同學可以到Qt無邊框窗體-最大化時支持拖拽還原這裏查看

本篇文章我們就來說一說當模態窗體彈出來時,如果點擊了非模態窗體以外的應用程序界面,怎麼實現一個閃動的效果。

閃動只是一個對外的信息交互,如果大家想要一些其他交互效果,可以自行實現。

二、效果展示

如效果圖所示,做了一個簡單的效果

  1. 點擊主應用程序時,彈出的模態窗體邊框顏色發生了變動,實現了一個抖動的效果。
  2. 點擊桌面時,模態窗體也有一個失去焦點時的狀態變化。

三、功能實現

實現窗口抖動效果,首先需要了解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,如果不知道函數的具體名字或者功能名字,最好進行模糊搜索。

不搜不知道,一搜嚇一跳,原來還有不少接收原生消息的函數,如下不所示。

上圖中總共有如下幾個函數

  1. filterNativeEvent:安裝事件過濾器的回調函數
  2. installNativeEventFilter:安裝事件過濾器,回調函數是第4個函數
  3. nativeEvent:窗口原生事件回調
  4. nativeEventFilter:事件過濾器回調函數,使用方法2安裝

看到這裏大家卡能會有些迷茫,好像都差不多呀!其實不然,還是有卻別的,感興趣的同學可以看看我之前寫的幾篇相關文章,都使用了接收全局windows消息來實現先關功能,具體一點來說就是使用上述的方法2+方法4來完成。

  1. Qt之自定義QLineEdit右鍵菜單
  2. qt捕獲全局windows消息
  3. 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);
}

重點強調

這裏還需要說一點,有些同學按照文檔操作了,調試時代碼也走到相關位置了,但是發現沒有效果,然後就開始懷疑人生了。

這裏博主重點說幾個可能出現錯誤的地方

  1. 我們的模態窗體一定要指定模態的父窗體是誰
  2. 窗體一定要設置上Qt::Dialog屬性

第二點是非常關鍵的,很多同學都是沒有設置這個屬性,導致失去了效果。

四、相關文章

  1. Qt自定義的無邊框Dialog 在點擊其他窗口時處理閃爍效果
  2. Qt無邊框窗體-最大化時支持拖拽還原
  3. Qt之自定義QLineEdit右鍵菜單
  4. qt捕獲全局windows消息
  5. Qt之股票組件-股票檢索--支持搜索結果預覽、鼠標、鍵盤操作

值得一看的優秀文章:

  1. 財聯社-產品展示
  2. 廣聯達-產品展示
  3. Qt定製控件列表
  4. 牛逼哄哄的Qt庫





如果您覺得文章不錯,不妨給個打賞,寫作不易,感謝各位的支持。您的支持是我最大的動力,謝謝!!!














很重要--轉載聲明

  1. 本站文章無特別說明,皆爲原創,版權所有,轉載時請用鏈接的方式,給出原文出處。同時寫上原作者:朝十晚八 or Twowords

  2. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章