简体   繁体   中英

draw on transparent window using pen

I want to draw on a transparent window using a pen.

When drawing a line black area surround the line.

This image shows the problem:

在此处输入图片说明

How to solve this problem?

LRESULT __stdcall WindowProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc, backDC;
    PAINTSTRUCT ps;

    static Point prevPt;

    // Draw or Erase
    static bool isDraw = false;
    static bool isErase = false;

    // Select Pen Color
    static int selectColor = 1;

    // Color Pen(R, G, B) and Current Pen
    static HPEN redPen;
    static HPEN greenPen;
    static HPEN bluePen;
    static HPEN* currentPen = &redPen;

    switch (iMessage)
    {
    case WM_CREATE:
    {
        redPen = CreatePen(PS_SOLID, 4, RGB(255, 0, 0));
        greenPen = CreatePen(PS_SOLID, 4, RGB(0, 255, 0));
        bluePen = CreatePen(PS_SOLID, 4, RGB(0, 0, 255));
        return 0L;
    }
    case WM_DESTROY:
        cout << "\n" << "destroying window" << endl;
        PostQuitMessage(0);
        return 0L;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        return 0L;
    case WM_LBUTTONDOWN:
        prevPt.x = LOWORD(lParam);
        prevPt.y = HIWORD(lParam);
        isDraw = true;
        return 0L;
    case WM_LBUTTONUP:
        isDraw = false;
        return 0L;
    case WM_MOUSEMOVE:
    {
        int x = LOWORD(lParam);
        int y = HIWORD(lParam);
        if (isDraw)
        {
            hdc = GetDC(g_hWnd);

            HPEN OldPen = (HPEN)SelectObject(hdc, *currentPen);
            MoveToEx(hdc, prevPt.x, prevPt.y, NULL);
            LineTo(hdc, x, y);

            prevPt.x = x;
            prevPt.y = y;
            DeleteObject(OldPen);
            ReleaseDC(g_hWnd, hdc);
        }
    }
    return 0L;
    case WM_RBUTTONDOWN:
        isErase = true;
        return 0L;
    case WM_RBUTTONUP:
        isErase = false;
        return 0L;
    case WM_MOUSEWHEEL:
        if (selectColor > 3)
            selectColor = 1;

        if (selectColor == 1)   // Red
            currentPen = &redPen;
        else if (selectColor == 2)
            currentPen = &greenPen;
        else if (selectColor == 3)
            currentPen = &bluePen;

        selectColor++;
        return 0L;
    }

    return DefWindowProc(hWnd, iMessage, wParam, lParam);
}

void main()
{
    HWND window;
    LPCWSTR myclass = L"DrawTest";

    WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_VREDRAW | CS_HREDRAW, WindowProc,
    0, 0, NULL, LoadIcon(0,IDI_APPLICATION), LoadCursor(0,IDC_ARROW), (HBRUSH)WHITE_BRUSH, 0, myclass, LoadIcon(0,IDI_APPLICATION) };
    if (RegisterClassEx(&wndclass))
    {
        window = CreateWindowEx(WS_EX_TRANSPARENT, myclass, L"title", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN), 0, 0, NULL, 0);
    }

    VideoCapture* pCapture = nullptr;
    pCapture = new VideoCapture(0);

    if (pCapture)
    {
        if (!pCapture->isOpened())
        {
            cout << "Can not open video file." << endl;
            return;
        }

        int fps = (int)(pCapture->get(CAP_PROP_FPS));

        int delay = 0;
        if (fps == 0)
            fps = 24;

        delay = 1000 / fps;

        Mat colorMat;

        while (1)
        {
            *pCapture >> colorMat;
            if (colorMat.empty())
                break;

            Mat copyColor;
            colorMat.copyTo(copyColor);

            imshow("colorMat", copyColor);

            int ckey = waitKey(delay);
            if (ckey == 27)
                break;

            if (window)
            {
                ShowWindow(window, SW_SHOW);
                MSG msg;
                if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
                {
                    GetMessage(&msg, 0, 0, 0);
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
        }

        cv::destroyAllWindows();
    }
}

As I said in my comment, create a layered window:

window = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
                        GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
                        HWND_DESKTOP, NULL, NULL, NULL);

set color transparency the same as your background brush:

SetLayeredWindowAttributes(window, RGB(255, 255, 255), 0, LWA_COLORKEY);

In WM_PAINT

hdc = BeginPaint(hwnd, &ps);

HPEN OldPen = (HPEN)SelectObject(hdc, *currentPen);

//set random values
MoveToEx(hdc, 50, 50, NULL);
LineTo(hdc, 450, 450);

SelectObject(hdc, OldPen);

EndPaint(hwnd, &ps);

return 0;

This code works, BUT you cant get mouse messages cause the window is transparent. That is the main issue, not the drawing.

EDIT

The problem is how to get mouse messages. The solution is to create a second window on top of your main window with opacity nearly zero so it is not visible but get the mouse messages!

window = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
                        GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
                        HWND_DESKTOP, NULL, NULL, NULL);

windowClone = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
                        GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
                        window, NULL, NULL, NULL);

Make your main window complete transparent:

//background color MUST be the same with color Key!
SetLayeredWindowAttributes(window, RGB(255, 255, 255), 0, LWA_COLORKEY);

Make nearly transparent your clone window

//The transparency is set to 1
SetLayeredWindowAttributes(windowClone, 0, 1, LWA_ALPHA);

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    PAINTSTRUCT ps;
    HDC hdc;
    static int draw = FALSE, startX, startY, endX, endY, posX, posY;


    switch(message){ //handle the messages 
        case WM_PAINT:
            printf("WM_PAINT \n");

            if( hwnd == window && draw == TRUE ){
                HPEN OldPen, redPen;

                redPen = CreatePen(PS_SOLID, 4, RGB(255, 0, 0));

                hdc = BeginPaint(hwnd, &ps);

                OldPen = (HPEN)SelectObject(hdc, redPen);

                MoveToEx(hdc, startX, startY, NULL);
                LineTo(hdc, endX, endY);

                SelectObject(hdc, OldPen);

                EndPaint(hwnd, &ps);

                DeleteObject(redPen);

                return 0;
            }

            break;

        case WM_MOUSEMOVE:
            //printf("WM_MOUSEMOVE \n");

            if( hwnd == windowClone && draw == TRUE ){
                startX = posX;
                startY = posY;
                endX = GET_X_LPARAM(lParam);
                endY = GET_Y_LPARAM(lParam);

                posX = endX;
                posY = endY;

                InvalidateRect(window, NULL, FALSE);
            }

            break;

        case WM_LBUTTONDOWN:
            printf("WM_LBUTTONDOWN \n");

            if( hwnd == windowClone ){
                posX = GET_X_LPARAM(lParam);
                posY = GET_Y_LPARAM(lParam);
                draw = TRUE;
            }

            break;

       case WM_LBUTTONUP:
           printf("WM_LBUTTONUP \n");

           if( hwnd == windowClone && draw == TRUE ){
               draw = FALSE;
           }

           break;

       case WM_CAPTURECHANGED:
           printf("WM_CAPTURECHANGED \n");

           if( hwnd == windowClone && draw == TRUE ){
               draw = FALSE;
           }

           break;

        default:   //for messages that we don't deal with
            return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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