2010-10-19 52 views
39

我創造什麼應該是一個非常簡單的Win32 C++應用程序誰是它唯一的目的,只顯示一個半透明PNG透明窗口。該窗口不應該有任何鉻,所有的不透明度應該在PNG本身進行控制。創建在C++中的Win32

我的問題是,當窗口下的內容改變,所以PNG的透明區域是「卡住」與窗下是什麼應用程序時最初啓動的窗口不會重新繪製。

這裏就是我建立新的窗口行:

hWnd = CreateWindowEx(WS_EX_TOPMOST, szWindowClass, szTitle, WS_POPUP, 0, height/2 - 20, 40, 102, NULL, NULL, hInstance, 0); 

對於調用RegisterClassEx,我有這樣的設置背景:

wcex.hbrBackground = (HBRUSH)0; 

這裏是我的WM_PAINT消息處理程序:

case WM_PAINT: 
{ 
    hdc = BeginPaint(hWnd, &ps); 
    Gdiplus::Graphics graphics(hdc); 
    graphics.DrawImage(*m_pBitmap, 0, 0); 
    EndPaint(hWnd, &ps); 
    break; 
} 

有一點要注意的是,應用程序總是停靠在t他屏幕並不動。但是,當用戶打開,關閉或移動它時,應用程序下面的內容可能會發生變化。

當應用程序首次啓動時,它看起來很完美。透明(和simi透明)的PNG部分顯示完美。但是,當應用程序下方的背景發生變化時,背景不會更新,它只是在應用程序首次啓動時保持不變。實際上,WM_PAINT(或WM_ERASEBKGND在後臺更改時不會被調用)。

我一直在玩這個相當長一段時間,並已接近了獲得100%正確的,但也不能令人信服。例如,我試着將背景設置爲(HBRUSH)NULL_BRUSH,我試過處理WM_ERASEBKGND。

可以做些什麼來獲取窗口時的內容下,它改變重繪?

+0

SetBKMode和SetBKColor是我已經用於製造透明父控制的API。 – 2010-10-19 15:43:23

回答

32

我能夠做的正是我想通過使用代碼本系列的第1部分和第2部分:http://code.logos.com/blog/2008/09/displaying_a_splash_screen_with_c_introduction.html

那些博客文章正在討論在Win32 C++中顯示啓動畫面,但它與我需要做的幾乎完全相同。我相信我遺漏的部分是,我不需要使用GDI +將PNG繪製到窗口,而是需要使用具有適當BLENDFUNCTION參數的UpdateLayeredWindow函數。我將粘貼下面的SetSplashImage方法,其能夠在第2部分在上述鏈接中找到:

void SetSplashImage(HWND hwndSplash, HBITMAP hbmpSplash) 
{ 
    // get the size of the bitmap 
    BITMAP bm; 
    GetObject(hbmpSplash, sizeof(bm), &bm); 
    SIZE sizeSplash = { bm.bmWidth, bm.bmHeight }; 

    // get the primary monitor's info 
    POINT ptZero = { 0 }; 
    HMONITOR hmonPrimary = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); 
    MONITORINFO monitorinfo = { 0 }; 
    monitorinfo.cbSize = sizeof(monitorinfo); 
    GetMonitorInfo(hmonPrimary, &monitorinfo); 

    // center the splash screen in the middle of the primary work area 
    const RECT & rcWork = monitorinfo.rcWork; 
    POINT ptOrigin; 
    ptOrigin.x = 0; 
    ptOrigin.y = rcWork.top + (rcWork.bottom - rcWork.top - sizeSplash.cy)/2; 

    // create a memory DC holding the splash bitmap 
    HDC hdcScreen = GetDC(NULL); 
    HDC hdcMem = CreateCompatibleDC(hdcScreen); 
    HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpSplash); 

    // use the source image's alpha channel for blending 
    BLENDFUNCTION blend = { 0 }; 
    blend.BlendOp = AC_SRC_OVER; 
    blend.SourceConstantAlpha = 255; 
    blend.AlphaFormat = AC_SRC_ALPHA; 

    // paint the window (in the right location) with the alpha-blended bitmap 
    UpdateLayeredWindow(hwndSplash, hdcScreen, &ptOrigin, &sizeSplash, 
     hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA); 

    // delete temporary objects 
    SelectObject(hdcMem, hbmpOld); 
    DeleteDC(hdcMem); 
    ReleaseDC(NULL, hdcScreen); 
} 
+0

最佳答案,當通過COM接口與WIC(Windows圖像處理組件)一起使用時,還支持自動PNG alpha混合。 – dns 2015-07-05 01:51:52

+0

結束了與AlphaBlend浪費了大量時間。此解決方案可能是實現每像素Alpha混合的最簡單方法之一,特別是在您更新窗口時。 – TheBlueNotebook 2016-01-11 12:30:17

16

使用SetLayeredWindowAttributes,這允許您設置將變爲透明的遮罩顏色,從而允許背景透過。

http://msdn.microsoft.com/en-us/library/ms633540(VS.85).aspx

您還需要與分層標誌,例如配置窗口

SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); 

之後,它是相當簡單:

// Make red pixels transparent: 
SetLayeredWindowAttributes(hwnd, RGB(255,0,0), 0, LWA_COLORKEY); 

當你的PNG包含要與背景融爲一體半透明像素,這變得更加複雜。你可以試試這個CodeProject上的文章中望方法:

Cool, Semi-transparent and Shaped Dialogs with Standard Controls for Windows 2000 and Above

+1

我試過這個它幾乎可以工作。問題是PNG的某些區域是類似透明的,並且顏色鍵方法僅使顏色鍵顏色值的100%不透明度的像素透明。如果一切都失敗了,我的後備將是去除所有半透明區域,但我真的寧願避免這樣做。 – adoss 2010-10-19 16:24:41

+0

你可以嘗試更復雜的黑客,比如我鏈接的文章中的黑客,但基本上,只要你想將預先存在的圖像與桌面內容混合,事情就會變得複雜起來。 – 2010-10-19 16:45:59

+0

查看我發佈的答案。我喜歡這個代碼比我在CodeProject這篇文章中看到的要好很多。不僅如此,但我相信我發現的是適當的解決方案,而不是黑客。謝謝您的幫助! – adoss 2010-10-19 19:05:17

相關問題