2015-03-13 10 views
7

Für xtow möchte ich ein Top-Level-Fenster mit dem Standard-Nicht-Client-Bereich und dem Client-Bereich mit einer Bitmap, die einen Alpha-Kanal enthält, zeichnen.Zeichnen eines Fensters mit einem Standardrahmen und transparentem Inhalt

entdecke ich jetzt so, wie ich umgesetzt haben, das funktioniert auf Windows 7, aber nicht korrekt dargestellt auf Windows 8.1, hinter Bildern des Fensterinhaltes zu verlassen, wenn er bewegt wird oder maximiert.

Um zu untersuchen, habe ich ein einfaches Testprogramm alpha-test, das

  • DwmEnableBlurBehindWindow Verwendet() eine nicht schneidende Unschärfe Region zu setzen, so dass die Alpha-Werte im Fenster geehrt werden, ohne Unschärfe.
  • Verwendet BitBlt() eine Bitmap mit alpha hinein zu kopieren.
// 
// g++ alpha-test.cc -o alpha-test -mwindows -lgdiplus -ldwmapi 
// 

#define _WIN32_WINNT 0x0600 

#include <assert.h> 
#include <stdio.h> 
#include <windows.h> 
#include <gdiplus.h> 
#include <dwmapi.h> 

int width = 360; 
int height = 360; 
HBITMAP hBitmap; 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message) 
    { 
    case WM_PAINT: 
     { 
     PAINTSTRUCT ps; 
     HDC hdcUpdate = BeginPaint(hWnd, &ps); 

     RECT rc; 
     GetClientRect(hWnd, &rc); 
     HBRUSH hbrush = CreateSolidBrush(RGB(0,0,0)); 
     FillRect(hdcUpdate, &rc, hbrush); 
     DeleteObject(hbrush); 

     HDC hdcMem = CreateCompatibleDC(hdcUpdate); 
     HBITMAP hbmpold = (HBITMAP)SelectObject(hdcMem, hBitmap); 

     if (!BitBlt(hdcUpdate, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, hdcMem, 0, 0, SRCCOPY)) 
      { 
      printf("BitBlt failed: 0x%08x\n", (int)GetLastError()); 
      } 

     SelectObject(hdcMem, hbmpold); 
     DeleteDC(hdcMem); 

     EndPaint(hWnd, &ps); 
     } 
     return 0; 

    case WM_DESTROY: 
     PostQuitMessage(0); 
     return 0; 

    default: 
     return DefWindowProc(hWnd, message, wParam, lParam); 
    } 
} 

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) 
{ 
    ULONG_PTR gdiplusToken; 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput; 
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    LPCTSTR szWindowClass = "TransparentClass"; 

    // Register class 
    WNDCLASSEX wcex = {0}; 
    wcex.cbSize = sizeof(WNDCLASSEX); 
    wcex.style   = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC; 
    wcex.lpfnWndProc = WndProc; 
    wcex.cbClsExtra  = 0; 
    wcex.cbWndExtra  = 0; 
    wcex.hInstance  = hInstance; 
    wcex.hIcon   = NULL; 
    wcex.hCursor  = LoadCursor(NULL, IDC_ARROW); 
    wcex.lpszClassName = szWindowClass; 
    wcex.hIconSm  = NULL; 
    wcex.hbrBackground = (HBRUSH)CreateSolidBrush(0x00000000); 
    RegisterClassEx(&wcex); 

    // Create window 
    HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, 
          szWindowClass, 
          "Transparent Window", 
          WS_OVERLAPPED | WS_SYSMENU, 
          CW_USEDEFAULT, CW_USEDEFAULT, width, height, 
          NULL, NULL, hInstance, NULL); 

    Gdiplus::Bitmap *m_pImage = Gdiplus::Bitmap::FromFile(L"sample.png", FALSE); 
    Gdiplus::Color bg(0,0,0,0); 
    m_pImage->GetHBITMAP(bg, &hBitmap); 
    assert(hBitmap); 

    DWM_BLURBEHIND blurBehind = { 0 }; 
    blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; 
    blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1); 
    blurBehind.fEnable = TRUE; 
    blurBehind.fTransitionOnMaximized = FALSE; 
    DwmEnableBlurBehindWindow(hWnd, &blurBehind); 
    DeleteObject(blurBehind.hRgnBlur); 

    ShowWindow(hWnd, SW_SHOW); 

    // Main message loop 
    MSG msg; 
    while (GetMessage(&msg, NULL, 0, 0)) 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 

    return (int)msg.wParam; 
} 

Ist das wirklich kaputt? Wie kann ich meinen Code reparieren? Ist das ein Windows-Bug/Einschränkung?

Gibt es einen anderen Weg, um mein Ziel zu erreichen, der mit einer Grenze ein Bitmap mit Alpha in ein Fenster zu zeichnen?

Update: ich einige Tests haben Direct2D und Direct3D mit den Clientbereich mit den Bitmaps zu füllen, aber sie in der gleichen Art und Weise mis gemacht.

Antwort

1

Die DWM verwischt nicht mehr (diese Funktion wurde als zu energiehungrig angesehen und wurde in Windows 8 entfernt), also würde ich vermuten, dass der Hintergrundbereich Ihres Fensters nicht mehr richtig zusammengesetzt wird - und deshalb Sie erhalten nicht den "automatischen" Alpha-Effekt, den er Ihnen in Windows 7 gab.

Dies ist eine Art einer ungewöhnlichen Möglichkeit, transparente Fenster zu zeichnen, um ehrlich zu sein. Die Verwendung von UpdateLayeredWindow ist der "offizielle" Weg und hätte den Vorteil, sowohl unter Windows 8 als auch unter Windows 7 zu arbeiten.

+0

Vielleicht vermisse ich etwas, aber ich denke, dass Fenster, die mit UpdateLayeredWindow gezeichnet werden, keinen Rahmen bekommen, Das macht es für meine Zwecke ein bisschen ein Nichtstarter, es sei denn, es gibt einen Weg um das ... – jturney

+0

@jturney Beachten Sie, dass Sie in Windows 8 den 'WS_EX_LAYERED'-Stil in einem untergeordneten Fenster verwenden können, so dass Sie wahrscheinlich tun könnten dies mit zwei Codepfaden, unter Verwendung Ihrer vorhandenen Methode für Windows 7 und früher. Sind Sie sicher, dass Sie das in Windows 7 nicht können? (Ich habe nie versucht, einen der Rahmenstile im Fenster zu aktivieren, wenn ich das in der Vergangenheit getan habe) –

Verwandte Themen