我编写了一个程序,创建一个具有 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 中设置第二个鼠标坐标,结果相同
对此,发送
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;
}
我想分享如何使用 WINAPI 和 GDI+ 在带有 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 文档