WinAPI 32 和 GDI+ 在拖动具有透明度的某些区域的 PNG 图像时移动窗口

问题描述 投票:0回答:2

我编写了一个程序,创建一个具有 WS_POPUP 属性的窗口,以便加载具有透明部分的背景的 PNG 图像,

首先在案例 WM_MOUSEMOVE 中包含的代码中:我使用 SetWindowPos 函数来移动窗口,但是这个函数将窗口移动到左上角,这让我有点困扰,我希望图像能够正确跟随鼠标.

然后,PNG 图像有一个正确显示的透明部分,但就好像它把窗口下面的内容复制到窗口本身中。

无论如何,这是我写的代码。

#include <windows.h>
#include <gdiplus.h>

#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;

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

Image* image; // Declare the image pointer globally
int imageWidth = 0;
int imageHeight = 0;
bool isDragging = false;
POINT dragStartPos;
POINT prevMousePos;
POINT windowStartPos;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // Initialize GDI+
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // Load the PNG image
    image = Image::FromFile(L"C:\\Users\\hacktooth\\Downloads\\bg.png"); // Replace with your image path
    if (image) {
        imageWidth = image->GetWidth();
        imageHeight = image->GetHeight();
    }

    // Create the window class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = NULL; //(HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"WindowClass";
    wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);

    // Register the window class
    RegisterClassEx(&wcex);

    // Create the application window
    HWND hWnd = CreateWindow(
        L"WindowClass",
        L"PNG Image",
        WS_POPUP,
        NULL,
        NULL,
        imageWidth, // Set the window width to image width
        imageHeight, // Set the window height to image height
        NULL,
        NULL,
        hInstance,
        NULL
    );

    // Display the window
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

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

    // Clean up GDI+
    if (image) {
        delete image;
    }
    GdiplusShutdown(gdiplusToken);

    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    PAINTSTRUCT ps;
    HDC hdc;
    Graphics* graphics; // Declare the Graphics pointer
    POINT offset{}; //mouse coord offsets

    switch (message) {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        // Draw the image
        graphics = new Graphics(hdc);
        graphics -> DrawImage(image, 0, 0, imageWidth, imageHeight); // Scale image to fit window
        
        delete graphics; // Cleanup the Graphics object

        EndPaint(hWnd, &ps);
        break;

    case WM_LBUTTONDOWN:
        isDragging = true;

        offset.x = (int)(short)LOWORD(lParam); 
        offset.y = (int)(short)HIWORD(lParam);

        SetCapture(hWnd);
        break;

    case WM_LBUTTONUP:
        ReleaseCapture();
        isDragging = false;
        break;

    case WM_MOUSEMOVE:
        if (isDragging)
        {
            RECT mainWindowRect;
            POINT pos;
            short windowWidth, windowHeight;

            pos.x = (int)(short)LOWORD(lParam);
            pos.y = (int)(short)HIWORD(lParam);

            GetWindowRect(hWnd, &mainWindowRect);
            windowHeight = mainWindowRect.bottom - mainWindowRect.top;
            windowWidth = mainWindowRect.right - mainWindowRect.left;

            ClientToScreen(hWnd, &pos);            
            //MoveWindow(hWnd, pos.x, pos.y, windowWidth, windowHeight, TRUE);
            SetWindowPos(hWnd, NULL, pos.x - offset.x, pos.y - offset.y, windowWidth, windowHeight, 0);
        }
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

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

    return 0;
}

视频: 文字

我尝试使用 MOVEWINDOW 功能: //MoveWindow(hWnd, pos.x, pos.y, windowWidth, windowHeight, TRUE); 同样的结果... 我尝试在 WM_LBUTTONDOWN 中设置第二个鼠标坐标,结果相同

c++ winapi draggable gdi+
2个回答
1
投票

对此,发送

WM_NCLBUTTONDOWN
消息即可解决。
WM_NCLBUTTONDOWN
可以让您将图像拖到客户端区域。

   case WM_LBUTTONDOWN:  
    {
        x = LOWORD(lParam);
        y = HIWORD(lParam);
        if (x < imageWidth && y < imageHeight)
        {
            SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
        }
        break;
    }

您可以按照鼠标的位置正确拖动图像。 并且不会留下任何透明区域。如果该区域为空,则仅显示窗口背景。

这是完整的代码:

#include <windows.h>
#include <gdiplus.h>
#include<windowsx.h>
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
Image* image; // Declare the image pointer globally
int imageWidth ;
int imageHeight ;
bool isDragging = false;
POINT dragStartPos;
POINT prevMousePos;
POINT windowStartPos;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // Initialize GDI+
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    // Load the PNG image
    image = Image::FromFile(L"C:\\Users\\Administrator\\Desktop\\bp.png"); // Replace with your image path
    if (image) {
        imageWidth = image->GetWidth();
        imageHeight = image->GetHeight();
    }
    // Create the window class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = NULL; //(HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"WindowClass";
    wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
    // Register the window class
    RegisterClassEx(&wcex);
    // Create the application window
    HWND hWnd = CreateWindow(
        L"WindowClass",
        L"PNG Image",
        WS_POPUP,
        500,
        150,
        imageWidth, // Set the window width to image width
        imageHeight, // Set the window height to image height
        NULL,
        NULL,
        hInstance,
        NULL
    );
    // Display the window
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    // Main message loop
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    // Clean up GDI+
    if (image) {
        delete image;
    }
    GdiplusShutdown(gdiplusToken);
    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    PAINTSTRUCT ps;
    HDC hdc;
    Graphics* graphics; // Declare the Graphics pointer
    POINT offset{}; //mouse coord offsets
    switch (message) {
    case WM_PAINT:
    {
        hdc = BeginPaint(hWnd, &ps);
        // Draw the image
        graphics = new Graphics(hdc);
        graphics->DrawImage(image, 0, 0, imageWidth, imageHeight); // Scale image to fit window
        delete graphics; // Cleanup the Graphics object
        EndPaint(hWnd, &ps);
        break;
        }
    case WM_LBUTTONDOWN:
    {
        int x = LOWORD(lParam);
        int y = HIWORD(lParam);   
        if (x < imageWidth && y < imageHeight)
        {
            SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
        }
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

0
投票

我想分享如何使用 WINAPIGDI+ 在带有 PNG 图像

的窗口上启用透明度

首先,我们需要在 CreateWindowsEx 中设置一个扩展控件,其第一个属性由 WS_EX_LAYERED

定义
// Create the application window
CreateWindowEx(
    WS_EX_LAYERED,
    L"WindowClass",
    L"CAPTION",
    WS_POPUP,
    500, //x
    500, //y
    Width, 
    Height, 
    NULL,
    NULL,
    hInstance,
    NULL
);

现在非常重要的是在窗口类上设置背景颜色记住在CreateWindowEx函数示例之前创建窗口类:

    // Create the window class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
--->    wcex.hbrBackground = CreateSolidBrush(RGB(1, 1, 1)); 
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"WindowClass";
    wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);

最后在 CreateWindowEx 函数下,您必须使用 SetLayeredWindowAttributes()

BOOL SetLayeredWindowAttributes(
  [in] HWND     hwnd,
  [in] COLORREF crKey,
  [in] BYTE     bAlpha,
  [in] DWORD    dwFlags
);

此功能允许使用 KEY COLOR “像绿屏” 设置透明度,在窗口中设置不透明度或混合不透明度 + 键颜色,然后您必须使用 COLORREF* 声明用作键的颜色 为了生成 COLORREF,我们使用 RGB 宏。

颜色键

    COLORREF transparentColor = RGB(1, 1, 1);
    SetLayeredWindowAttributes(hWnd, transparentColor, NULL, LWA_COLORKEY);

设置不透明度

    COLORREF transparentColor = RGB(1, 1, 1);
    SetLayeredWindowAttributes(
    hWnd,
    transparentColor, 
    50, //OPACITY AMOUNT
    LWA_ALPHA);

不透明度+主色

    COLORREF transparentColor = RGB(1, 1, 1);
    SetLayeredWindowAttributes(
    hWnd,
    transparentColor, //RGB STRUCTURE FOR COLOR KEY
    50, //OPACITY VALUE
    LWA_ALPHA | LWA_COLORKEY //BLEND OPACITY + COLOR KEY
    );

更多信息请访问 Microsoft 文档

视频

© www.soinside.com 2019 - 2024. All rights reserved.