首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GDI DC的透明度

GDI DC的透明度
EN

Stack Overflow用户
提问于 2015-03-04 03:32:08
回答 1查看 259关注 0票数 2

我有一个“简单”的目标,就是在屏幕上画一个带有一些透明度的位图。这一点没那么难:

代码语言:javascript
复制
#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);
}

使用任何带有黑色边框的通用bmp都行,我使用了以下内容:

现在的问题是,当我移动窗口(单击/拖动)背景更新时,如何才能做到这一点?我本来希望把位图放进透明的窗口,这样它就可以覆盖在事物的上面,但它似乎只是抓住了它背后的像素。

如果可能的话,我尝试在没有GDI+或其他库的情况下这样做。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-04 04:02:48

CreateWindow()不接受扩展的窗口样式,例如WS_EX_TRANSPARENT (这就是为什么它的名称中有EX )。您必须使用CreateWindowEx()来代替:

代码语言:javascript
复制
hwnd = CreateWindowExW(WS_EX_TRANSPARENT,
    wc.lpszClassName, L"",
    WS_VISIBLE | WS_POPUP,
    100, 100, wW, wH, NULL, NULL, hInst, NULL);

更好的选择是使用分层窗口扩展样式创建WS_EX_LAYERED (请参见)。然后可以使用UpdateLayeredWindow()函数为窗口提供位图和透明颜色(也可以指定alpha )。让窗口管理为您透明绘制位图的所有艰苦工作。

您的WndProc()还可以响应WM_NCHITTEST消息,告诉操作系统,对窗口的所有单击都应被视为用户正在单击窗口的标题栏。让窗口为您处理鼠标跟踪和自动定位.

尝试更像这样的东西:

代码语言:javascript
复制
#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);
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28846219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档