使用透明/視窗半透明效果/圖片時遇到的一些問題

來源:互聯網
上載者:User
  最近兩周使用透明、視窗半透明效果比較多,在此之前我寫代碼都藉助封裝好了的皮膚庫,而現在都是“手寫”的——石器時代大冒險,遇到了一些困難,在此做總結。
1、GDI函數對Alpha值的忽視。
    GDI函數只有AlphaBlend api可以提供alpha通道的繪製,使用AlphaBlend可以實現32位位元影像的繪製。因為只有這個api能識別alpha通道,如果在一個MemDC上用DrawText繪製文本,這些文字地區的alpha值都為0,之後再使用AlphaBlend api把MemDC的位元影像拷貝到實際DC,就會導致文字地區異常,要麼是透明了,要麼是變成純白色了。解決辦法是:1、在能達到目的的前提下,從MemDC拷貝到實際DC時,不用AlphaBlend混合拷貝,而是使用Bitblt簡單拷貝;2、1可能無法達到想要的半透明效果,那麼就只能在混合拷貝之前遍曆文字地區的每一個像素,把它的alpha值修改為255[可參考http://bbs.csdn.net/topics/360021944];3、最方便的做法是引入GDI+,使用CImage,GDI+的文本繪製帶有Alpha屬性值。

2、AlphaBlend API和透明度
     Alpha通道值。0表示完全透明,255表示完全不透明。
     AlphaBlend函數裡的BLENDFUNCTION結構體裡的SourceConstantAlpha成員,指示的是整個圖片的Alpha值。0,表示源圖片完全透明,255,表示使用源圖片的每個像素自己的Alpha值。
     AlphaBlend函數產生的圖片讓源、目標、SourceConstantAlpha混合。有一套複雜的計算:http://msdn.microsoft.com/en-us/library/windows/desktop/dd183393(v=vs.85).aspx
     計算涉及到這麼幾種情況:
1、沒有設定AC_SRC_ALPHA 屬性,只有SourceConstantAlpha做混合;
2、設定了AC_SRC_ALPHA 屬性,同時把SourceConstantAlpha設定為0xFF,這時候,只使用源圖片每個像素的Alpha值做混合;
3、設定了AC_SRC_ALPHA屬性,同時把SourceConstantAlpha設定為非0xFF,這時候既使用SourceConstantAlpha的值也使用源圖片每個像素的Alpha值做混合。
     按照MSDN公式的介紹,當SourceConstantAlpha的值為0的時候,則源DC的圖片在目標DC上完全不顯示了,源DC的RGB值都丟失了。當SourceConstantAlpha為255時,則使用源DC的圖片的Alpha值。
     當使用AlphaBlend的時候,只是把資料從一個DC拷貝到另一個DC。所以,如果是要把一個圖片貼到目標DC,必須是先把圖片選入到MemDC,然後再使用AlphaBlend函數把圖片從MemDC拷貝到實際DC。
  使用這個API,可以實現圖片切換時的平緩過渡效果,上一個圖片慢慢的消失,下一個圖片慢慢的呈現。3、AlphaBlend失敗的可能原因
    參數錯誤失敗原因1: 如果位元影像的bmBitsPixel為24,那麼是無法使用該函數的。
所以對於來源未知的圖片,安全的做法是
       BITMAP bitmapInfo;
      :: GetObject(hBitMap, sizeof( BITMAP), &bitmapInfo);
      if (bitmapInfo. bmBitsPixel == 24)  //24位的位元影像就直接使用Bitblt/StretchBlt
      {...........}

  參數錯誤失敗原因2:可能參數使用錯了,源dc的位元影像跟參數裡面指示源位元影像高度、寬度的值不相符。
    
  繪製效果很奇怪:之前以為使用了AlphaBlend之後就沒法使用Bitblt了,實際上是可以的,並不會導致alpha通道丟失。倒是這樣子會有問題:通過alphablend往memdc上繪製圖片,然後使用DrawText往memdc上繪製文字,最後使用alphablend把memdc的內容拷貝到實際DC,這就會導致文字變成白色的。所以,最後一步不能使用alphablend,必須使用bitblt這類函數。
 
4、GDI+繪製文本
     GDI+的DrawString可以繪製文本,如果用GDI+繪製文本再加上使用WS_EX_LAYER屬性,那麼GDI+繪製的文本必須使用UpdateLayeredWindow拷貝到目的地區域。不能直接在有WS_EX_LAYER屬性的視窗上使用GDI+繪製,必須先繪製然後使用UpdateLayeredWindow函數拷貝。

5、使用GDI+
     VS2008需要加上標頭檔:#include <objbase.h>  GDI+初始化:ULONG_PTR m_GdiToken; GdiplusStartupInput m_GdiInput;   GdiplusStartup(&m_GdiToken ,&m_GdiInput ,NULL );  GDI+銷毀GdiplusShutdown(m_GdiToken );

6、WS_EX_LAYERED視窗無法顯示
     只有WS_EX_LAYERED屬性,而沒有調用SetLayeredWindowAttribute或者UpdateLayeredWindow函數,那將導致視窗無法顯示。

7、如何繪製部分透明的視窗
1)切出部分透明的圖;
2)建立有WS_EX_LAYERED屬性的視窗;
3)把圖片選進MemDC,使用AlphaBlend函數把圖片混合拷貝到另一個MemDC;
4)由於GDI的DrawText函數會把該地區像素的alpha值清0,導致透明,所以建議使用GDI+的DrawString函數;
5)最後使用UpdateLayeredWindow把MemDC拷貝到實際DC。

8、SetLayeredWindowAttributes和UpdateLayeredWindow的區別
     兩者在win7以下的版本都要求必須是帶有WS_EX_LAYERED屬性的頂層視窗(非WS_CHILD屬性的視窗),windows 8之後的版本開始支援非頂層視窗。 
    SetLayeredWindowAttributes函數可以實現:1、對某一個RGB值實現透明;2、可以實現對整個視窗都使用同一個透明度。
    UpdateLayeredWindow函數可以實現局部半透明。而且這個函數是GDI+的函數,使用時需要初始化GDI+。
     
9、 UpdateLayeredWindow不支援局部更新  
      UpdateLayeredWindow函數包含了SetWindowPos設定視窗位置、大小的功能。這個函數不支援局部更新繪製地區。

10、不能把MAKEINTRESOURCE之後的值賦值給wstring
     因為這不是一個string,如果發生賦值,會導致觸發WM_PAINT訊息(很莫名其妙),導致錯誤。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.