問(wèn)題描述
我正在創(chuàng)建一個(gè)非常簡(jiǎn)單的 Win32 C++ 應(yīng)用程序,其唯一目的是僅顯示半透明的 PNG.窗口不應(yīng)有任何鍍鉻,并且所有不透明度都應(yīng)在 PNG 本身中控制.
I'm creating what should be a very simple Win32 C++ app whose sole purpose it to ONLY display a semi-transparent PNG. The window shouldn't have any chrome, and all the opacity should be controlled in the PNG itself.
我的問(wèn)題是當(dāng)窗口下的內(nèi)容發(fā)生變化時(shí)窗口不會(huì)重新繪制,因此 PNG 的透明區(qū)域卡住"了應(yīng)用程序最初啟動(dòng)時(shí)窗口下的內(nèi)容.
My problem is that the window doesn't repaint when the content under the window changes, so the transparent areas of the PNG are "stuck" with what was under the window when the application was initially started.
這是我設(shè)置新窗口的行:
Here's the line where I setup the new window:
hWnd = CreateWindowEx(WS_EX_TOPMOST, szWindowClass, szTitle, WS_POPUP, 0, height/2 - 20, 40, 102, NULL, NULL, hInstance, 0);
對(duì)于 RegisterClassEx 的調(diào)用,我為后臺(tái)設(shè)置了這個(gè):
For the call to RegisterClassEx, I have this set for the background:
wcex.hbrBackground = (HBRUSH)0;
這是我的 WM_PAINT 消息處理程序:
Here is my handler for WM_PAINT message:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics graphics(hdc);
graphics.DrawImage(*m_pBitmap, 0, 0);
EndPaint(hWnd, &ps);
break;
}
需要注意的一點(diǎn)是,應(yīng)用程序始終??吭谄聊蛔髠?cè)并且不會(huì)移動(dòng).但是,應(yīng)用程序下方的內(nèi)容可能會(huì)隨著用戶(hù)打開(kāi)、關(guān)閉或移動(dòng)其下方的窗口而發(fā)生變化.
One thing to note is that the application is always docked to the left of the screen and doesn't move. But, what's underneath the application may change as the user opens, closes or moves windows under it.
當(dāng)應(yīng)用程序第一次啟動(dòng)時(shí),它看起來(lái)很完美.PNG 的透明(和半透明)部分完美地顯示出來(lái).但是,當(dāng)應(yīng)用程序下面的背景發(fā)生變化時(shí),背景不會(huì)更新,它只是與應(yīng)用程序剛啟動(dòng)時(shí)保持不變.實(shí)際上,WM_PAINT(或 WM_ERASEBKGND 在背景變化時(shí)不會(huì)被調(diào)用).
When the application first starts, it looks perfect. The transparent (and simi-transparent) parts of the PNG show through perfectly. BUT, when the background underneath the application changes, the background DOESN'T update, it just stays the same from when the application first started. In fact, WM_PAINT (or WM_ERASEBKGND does not get called when the background changes).
我已經(jīng)玩了很長(zhǎng)一段時(shí)間,并且已經(jīng)接近 100% 正確,但還沒(méi)有完全正確.例如,我嘗試將背景設(shè)置為 (HBRUSH) NULL_BRUSH,并且嘗試處理 WM_ERASEBKGND.
I've been playing with this for quite a while and have gotten close to getting 100% right, but not quite there. For instance, I've tried setting the background to (HBRUSH) NULL_BRUSH and I've tried handling WM_ERASEBKGND.
當(dāng)窗口下的內(nèi)容發(fā)生變化時(shí),如何讓窗口重新繪制?
What can be done to get the window to repaint when the contents under it changes?
推薦答案
通過(guò)使用本系列第 1 部分和第 2 部分中的代碼,我能夠完全按照自己的意愿行事:
I was able to do exactly what I wanted by using the code from Part 1 and Part 2 of this series:
使用 C++ 顯示啟動(dòng)畫(huà)面
- 第 1 部分: 創(chuàng)建 HBITMAP 存檔
- 第 2 部分: 顯示窗口 存檔
那些博客文章談?wù)摰氖窃?Win32 C++ 中顯示啟動(dòng)畫(huà)面,但這與我需要做的幾乎相同.我相信我缺少的部分是,我需要使用 UpdateLayeredWindow
函數(shù)和正確的 BLENDFUNCTION
參數(shù).我將粘貼下面的 SetSplashImage 方法,該方法可以在上面鏈接的第 2 部分中找到:
Those blog posts are talking about displaying a splash screen in Win32 C++, but it was almost identical to what I needed to do. I believe the part that I was missing was that instead of just painting the PNG to the window using GDI+, I needed to use the UpdateLayeredWindow
function with the proper BLENDFUNCTION
parameter. I'll paste the SetSplashImage method below, which can be found in Part 2 in the link above:
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);
}
這篇關(guān)于在 C++ Win32 中創(chuàng)建透明窗口的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!