简体   繁体   English

GDI DC的透明度

[英]Transparency in GDI DCs

I have the "simple" goal of drawing a bitmap with some transparency around it on the screen. 我有一个“简单”的目标,即在屏幕上绘制具有一定透明度的位图。 That bit wasn't so hard: 那一点并不难:

#include <windows.h>
#include "BBKG.h"

HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static int wH = 156;
static int wW = 166;

HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent)
{
    HDC mem0, mem1;
    HBITMAP hbmMask;
    BITMAP bm;
    GetObject(hbmColour, sizeof(BITMAP), &bm);
    hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);
    mem0 = CreateCompatibleDC(0);
    mem1 = CreateCompatibleDC(0);
    SelectObject(mem0, hbmColour);
    SelectObject(mem1, hbmMask);
    SetBkColor(mem0, crTransparent);
    BitBlt(mem1, 0, 0, bm.bmWidth, bm.bmHeight, mem0, 0, 0, SRCCOPY);
    BitBlt(mem0, 0, 0, bm.bmWidth, bm.bmHeight, mem1, 0, 0, SRCINVERT);
    DeleteDC(mem0);
    DeleteDC(mem1);

    return hbmMask;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    hInst = hInstance;
    MSG  msg;
    HWND hwnd;
    WNDCLASSW wc;

    wc.style = 0;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.lpszClassName = L"nope";
    wc.hInstance = hInst;
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NULL;
    wc.lpfnWndProc = WndProc;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassW(&wc);
    hwnd = CreateWindowW(wc.lpszClassName, L"",
        WS_VISIBLE | WS_POPUP|  WS_EX_TRANSPARENT,
        100, 100, wW, wH, NULL, NULL, hInst, NULL);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0)) {
        //Workaround for focusables stealing my Esc key
        if (msg.message == WM_KEYDOWN){
            if (msg.wParam == VK_ESCAPE) {
                SendMessage(hwnd, WM_CLOSE, 0, 0);
            }
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam)
{
    static int px;
    static int py;
    static HBITMAP bhbm;
    static RECT nRect = { 0, 0, wW, wH };

    switch (msg)
    {
    case WM_CREATE:
    {
        HWND bb = CreateWindowW(L"STATIC", L"",
            WS_VISIBLE | WS_CHILD ,
            0, 0, wW, wH,
            hwnd, (HMENU)11, hInst, NULL);
        //SetTimer(hwnd, 1, 80, NULL);

        return 0;
    }
    case WM_PAINT: {
        //Vars
        RECT wRect;
        if (GetUpdateRect(hwnd, &wRect, FALSE) == 0) {
            return 0; //Nothing to paint
        }
        PAINTSTRUCT gps;
        PAINTSTRUCT ps;
        BeginPaint(hwnd, &gps);
        HWND bb = GetDlgItem(hwnd, 11);
        HDC bbhdc = BeginPaint(bb, &ps);
        HDC mdc = CreateCompatibleDC(bbhdc);

        //Load Image
        BITMAP pBM;
        HBITMAP pHBM = (HBITMAP)LoadImage(NULL, L"twi00.bmp", 0, 0, 0, LR_LOADFROMFILE);
        HBITMAP pMBM = CreateBitmapMask((HBITMAP)pHBM, 0x00000000);
        GetObject(pHBM, sizeof(pBM), &pBM);

        //Paint
        HBITMAP oldBM = (HBITMAP)SelectObject(mdc, pMBM);
        BitBlt(bbhdc, 0, 0, pBM.bmWidth, pBM.bmHeight, mdc, 0, 0, SRCAND);
        SelectObject(mdc, pHBM);
        BitBlt(bbhdc, 0, 0, pBM.bmWidth, pBM.bmHeight, mdc, 0, 0, SRCPAINT);

        //Cleanup
        SelectObject(mdc, oldBM);
        DeleteObject(pHBM);
        DeleteObject(pMBM);
        DeleteDC(mdc);
        EndPaint(bb, &ps);
        EndPaint(hwnd, &gps);
        return 1;
    }
    case WM_ERASEBKGND: {
        return 0;
    }
    case WM_DESTROY:
    {
        DeleteObject(bhbm);
        PostQuitMessage(0);
        return 0;
    }
    case WM_LBUTTONDOWN:
        SetCapture(hwnd);
        px = LOWORD(lParam);
        py = HIWORD(lParam);
        return 1;
    case WM_LBUTTONUP:
    {
        ReleaseCapture();
        return 1;
    }
    case WM_MOUSEMOVE:
    {
        if (GetCapture() == hwnd)
        {
            RECT rcWindow;
            GetWindowRect(hwnd, &rcWindow);
            SetWindowPos(hwnd, NULL, rcWindow.left + LOWORD(lParam) - px, rcWindow.top + HIWORD(lParam) - py, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
        }
        break;
    }
    }
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

Use any generic bmp with a black border will do, I used this: 使用任何带有黑色边框的通用bmp都可以,我使用了以下方法:

小马

Now the question is, how can I make it so that when I move the window (click/drag) the background updates? 现在的问题是,如何移动窗口(单击/拖动)以更新背景? I was hoping for something like putting the bitmap into a transparent window so that it's overlayed on top of things but it seems to just grab the pixels of what ever is behind it. 我希望将位图放到透明窗口中,以使其覆盖在事物之上,但它似乎只是抓住了它背后的像素。

I'm attempting to do this without GDI+ or other libraries, if possible. 如果可能的话,我正在尝试不使用GDI +或其他库的情况。

CreateWindow() does not accept extended window styles, such as WS_EX_TRANSPARENT (which is why it has EX in its name). CreateWindow()不接受扩展的窗口样式,例如WS_EX_TRANSPARENT (这就是它的名称中带有EX原因)。 You have to use CreateWindowEx() instead: 您必须使用CreateWindowEx()代替:

hwnd = CreateWindowExW(WS_EX_TRANSPARENT,
    wc.lpszClassName, L"",
    WS_VISIBLE | WS_POPUP,
    100, 100, wW, wH, NULL, NULL, hInst, NULL);

A better option is to create a layered window (see also this ) by using the WS_EX_LAYERED extended style). 更好的选择是使用WS_EX_LAYERED扩展样式来创建分层窗口 (另请参见this )。 Then you can use the UpdateLayeredWindow() function to provide the window with the bitmap and the transparent color (you can also specify alpha as well). 然后,您可以使用UpdateLayeredWindow()函数为窗口提供位图和透明颜色(也可以指定alpha)。 Let the window manage all of the hard work of drawing the bitmap transparently for you. 让窗口管理为您透明地绘制位图的所有艰苦工作。

Your WndProc() can also respond to the WM_NCHITTEST message to tell the OS that all clicks on the window should be treated as if the user were clicking on the window's titlebar. 您的WndProc()也可以响应WM_NCHITTEST消息,以告知OS应该将对窗口的所有单击视为用户单击窗口的标题栏。 Let the window handle the mouse tracking and auto-positioning for you. 让窗口为您处理鼠标跟踪和自动定位。

Try something more like this: 尝试更多类似这样的方法:

#include <windows.h>

HINSTANCE hInst;
static int wH = 156;
static int wW = 166;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    hInst = hInstance;

    WNDCLASSW wc = {0};    
    wc.lpszClassName = L"nope";
    wc.hInstance = hInst;
    wc.lpfnWndProc = WndProc;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassW(&wc);
    HWND hwnd = CreateWindowEx(WS_EX_LAYERED,
        wc.lpszClassName, L"",
        WS_POPUP, 100, 100, wW, wH, NULL, NULL,
        hInst, NULL);

    HBITMAP hBmp = (HBITMAP) LoadImage(NULL, L"twi00.bmp", 0, 0, 0, LR_LOADFROMFILE);
    HDC hdcScreen = GetDC(0);
    HDC hdcBmp = CreateCompatibleDC(hdcScreen);
    HBITMAP oldBM = (HBITMAP) SelectObject(hdcBmp, hBmp);

    POINT pt = {0};
    UpdateLayeredWindow(hwnd,
        hdcScreen,
        NULL, NULL,
        hdcBmp, &pt,
        RGB(0, 0, 0), // black
        NULL, ULW_COLORKEY
    );

    SelectObject(hdcBmp, oldBM);
    DeleteDC(hdcBmp);
    ReleaseDC(0, hdcScreen);
    DeleteObject(hBmp);

    ShowWindow(hwnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0) > 0) {
        //Workaround for focusables stealing my Esc key
        if ((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE) {
            SendMessage(hwnd, WM_CLOSE, 0, 0);
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam)
{    
    switch (msg)
    {
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }

        case WM_NCHITTEST:
        {
            return HTCAPTION;
        }
    }

    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM