用VB6.0在Vista下實現全磨砂玻璃窗口

使用過Windows Vista 的用戶都會對Vista窗口的磨砂玻璃效果印象深刻,而如果你在Windows Vista 下使用過 Windows Media Player 11 更會發現微軟把這種效果擴展至WMP11的底部區域,使得WMP的底部按鈕區域成爲一條“玻璃帶”,如圖:


  事實上,Vista窗口的磨砂玻璃效果不僅限於窗體的邊框(非客戶區域),他可以任意的延伸,甚至鋪滿整個窗口,下面我們就來看看怎麼用的vb6來實現這種擴展。

  Vista實現磨砂玻璃效果主要依靠一組叫做 Desktop Window Manager (DWM) 的API來實現,該組API均以dwm打頭,存在於dwmapi.dll中(該文件爲Vista特有),顧名思義,這些API是專門用來實現Vista窗口的特效的。由於篇幅所限,這裏僅介紹和本文關係最密切的兩個函數:DwmIsCompositionEnabled 和 DwmExtendFrameIntoClientArea。

  第一個函數DwmIsCompositionEnabled是用於判斷系統的磨砂玻璃合成效果是否已經開啓,因爲該效果可以由用戶關閉,儘管你可以在用戶關閉合成效果的情況下在程序中單獨使用合成效果。


  DwmIsCompositionEnabled的原型爲:

HRESULT DwmIsCompositionEnabled( BOOL *pfEnabled )

  其中pfEnabled爲一個輸出參數,告訴後面的程序合成效果是否被打開。

  該函數的VB聲明爲:

   Public Declare Function DwmIsCompositionEnabled Lib "dwmapi.dll" (ByRef enabledptr As Long) As Long

  這裏要注意C++裏的BOOL類型必須譯成vb中的Long而不是Boolean,否則你將得到錯誤的結果。

  DwmExtendFrameIntoClientArea函數則用於將磨砂邊框擴展至窗體客戶區,使得整個窗體看上就像一張卡片(sheet)。

  該函數原型爲:

   HRESULT DwmExtendFrameIntoClientArea(HWND hWnd,const MARGINS *margins)

  其中hWnd 爲目標窗口句柄,margins爲一個MARGINS結構體指針

  MARGINS結構體定義爲:

typedef struct _MARGINS
{
 int cxLeftWidth;
 int cxRightWidth;
 int cyTopHeight;
 int cyBottomHeight;
} MARGINS, *PMARGINS;


  該函數的vb引用爲:

Public Declare Function DwmExtendFrameIntoClientArea Lib "dwmapi.dll" (ByVal hwnd As Long, margin As MARGINS) As Long
  
  MARGINS的vb形式定義:

Public Type MARGINS
 m_Left As Long
 m_Right As Long
 m_Top As Long
 m_Button As Long
End Type

  其中MARGINS中的各個成員爲需要擴展的邊框大小(單位:像素),如果要把磨砂玻璃效果鋪滿整個邊框(本文以此爲例),全部成員可設置爲-1

  知道了這些,我們現在就可以動手了。

  我們在窗體的Form_Load事件裏寫上:

Dim mg As MARGINS, en As Long
mg.m_Left = -1
mg.m_Button = -1
mg.m_Right = -1
mg.m_Top = -1
DwmIsCompositionEnabled en
If en Then
 DwmExtendFrameIntoClientArea Me.hwnd, mg
End If

 然後運行(先確保系統使用Aero界面且合成效果被打開),結果發現窗體依然如故。原來,DwmExtendFrameIntoClientArea擴展後的邊框並不會在客戶區的前景顯示(它其實是一個背景,你會發現,此時邊框其實已經被擴展了,因爲原來的客戶區的凹陷邊界已經消失),磨砂玻璃的效果被窗體默認畫上去的前景覆蓋了,所以我們得自己給窗體畫個“透明”的前景。幸運的是,在RGB調色版中,黑色black (0x00000000)剛好就是ARGB(short for Alpha, Red, Green and Blue)的100%透明(這剛好可以解釋爲什麼用Windows 畫圖板打開一個png圖片時透明背景會變成純黑)。所以,第一個方法,我們可以在窗口的Form_Paint事件(是的,Form_Paint就足夠了,不用去子類化窗體。當然,如果要實現更高級功能,還是子類化吧…)中給窗口的前景用純黑(RGB(0,0,0))填充,用的是經典的GDI,主要就是CreateSolidBrush和FillRect兩個API工作,代碼:

Dim hBrush As Long, m_Rect As RECT, hBrushOld As Long
hBrush = CreateSolidBrush(RGB(0, 0, 0))
hBrushOld = SelectObject(Me.hdc, hBrush)
GetClientRect Me.hwnd, m_Rect
FillRect Me.hdc, m_Rect, hBrush
SelectObject Me.hdc, hBrushOld
DeleteObject hBrush ‘別忘了刪除對象

  現在再按一次F5,恩….很好!效果如下:


  但是接着問題就來了,當你在窗體上放上幾個控件之後會發現,控件的黑色部分(一般就是文字)也帶上了磨砂玻璃的“特效”,如圖:


  注意到上面的Text1文字了嗎?這種效果可不是我們想要的。怎麼辦呢?

  上帝說:要有更好的辦法

  於是,就有了第二種實現方法。

  其實這個問題的關鍵是畫出透明的客戶區,那麼,別忘了,還有一個API可以做成此事,記得.NET裏面那些控件和窗口有的有個TransparentKey屬性麼?沒錯了,就是用它—— SetLayeredWindowAttributes

  SetLayeredWindowAttributes可以提供這樣的一個功能:給一個窗口設定一個透明色,然後窗口顯示的時候指定顏色的區域將變成透明。這樣,只要我們給窗口指定一種沒有用到的顏色(反正不是黑色就行,這裏我用RGB(255,255,1)),就可以“畫”出“透明”的區域了。

  我們在使用之前要先對SetLayeredWindowAttributes做做手腳,將其聲明爲:

  Public Declare Function SetLayeredWindowAttributesByColor Lib "user32" Alias "SetLayeredWindowAttributes" (ByVal hwnd As Long, ByVal crey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long

  爲什麼要這麼幹呢?留意函數第二個參數,本來有人將其聲明爲Byte類型(用於窗體半透明時沒有問題),但是這裏要傳一個RGB值,所以要改成Long

  代碼如下,相關的API和常量不再敷述,聲明和值請讀者自行補齊

  Form_Load事件:(先聲明m_transparencyKey全局變量,Long類型)

m_transparencyKey = RGB(255, 255, 1) ‘多少沒所謂
SetWindowLong Me.hwnd, GWL_EXSTYLE, GetWindowLong(Me.hwnd, GWL_EXSTYLE) Or WS_EX_LAYERED
SetLayeredWindowAttributesByColor Me.hwnd, m_transparencyKey, 0, LWA_COLORKEY
Dim mg As MARGINS, en As Long
mg.m_Left = -1
mg.m_Button = -1
mg.m_Right = -1
mg.m_Top = -1
MsgBox "1"
DwmIsCompositionEnabled en
If en Then
 DwmExtendFrameIntoClientArea Me.hwnd, mg
End If

  再在Form_Paint事件中畫圖:

  Form_Paint代碼:

Dim hBrush As Long, m_Rect As RECT, hBrushOld As Long
hBrush = CreateSolidBrush(m_transparencyKey)
hBrushOld = SelectObject(Me.hdc, hBrush)
GetClientRect Me.hwnd, m_Rect
FillRect Me.hdc, m_Rect, hBrush
SelectObject Me.hdc, hBrushOld
DeleteObject hBrush

  再按F5,效果嘛……


  順便提一下,此代碼在Windows Vista以下版本,2000及以上Windows版本運行時會產生一個很有趣的效果(除控件外窗體客戶區背景完全透明!),如圖:


 
發佈了1 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章