使用笔

时间:2016-11-11 07:49:45

标签: c++ c winapi

我想用钢笔在透明窗口上画画。

在线条周围绘制黑色区域时。

此图显示问题:

enter image description here

如何解决这个问题?

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();
    }
}

1 个答案:

答案 0 :(得分:0)

正如我在评论中所说,创建一个分层窗口:

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

将颜色透明度设置为与背景画笔相同:

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

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;

此代码有效,您无法获取鼠标消息,因为窗口是透明的。这是主要问题,而不是绘图。

修改

问题是如何获取鼠标消息。解决方案是在主窗口顶部创建第二个窗口,不透明度接近为零,因此它不可见但是会收到鼠标消息!

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);

让主窗口完全透明:

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

使克隆窗口几乎透明

//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);
}