I wrote a program that creates a window with the WS_POPUP attribute, in order to load a PNG image for background with transparent part,
first of all in the code contained in case WM_MOUSEMOVE: I use the SetWindowPos function to move the window, but this function moves the window to the top left corner, this bothers me a bit and I would like the image to follow the mouse correctly.
then, the PNG image have a trasparent part that show correcly, but it's as if it took what's under the window and copied it into the window itself.
Anyway this is the code i wrote.
#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;
}
VIDEO : text
I try with MOVEWINDOW function : //MoveWindow(hWnd, pos.x, pos.y, windowWidth, windowHeight, TRUE); same result... I try with a second mouse coord setted in WM_LBUTTONDOWN same result
I want to share how to enable trasparency on a windows with PNG image using WINAPI and GDI+
First of all we need to set a Extended control in CreateWindowsEx with the first attribute defined with 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
);
Now very important is to set a background color on your window class remember to create window class before CreateWindowEx function example:
// 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);
Finally under CreateWindowEx function you must use SetLayeredWindowAttributes()
BOOL SetLayeredWindowAttributes(
[in] HWND hwnd,
[in] COLORREF crKey,
[in] BYTE bAlpha,
[in] DWORD dwFlags
);
This function allow to set a trasparency using KEY COLOR "like a green screen", set opacity at your window or blend opacity + key color, than you must declare the color you use as key using COLORREF* To generate a COLORREF, we use the RGB macro.
COLOR KEY
COLORREF transparentColor = RGB(1, 1, 1);
SetLayeredWindowAttributes(hWnd, transparentColor, NULL, LWA_COLORKEY);
SET OPACITY
COLORREF transparentColor = RGB(1, 1, 1);
SetLayeredWindowAttributes(
hWnd,
transparentColor,
50, //OPACITY AMOUNT
LWA_ALPHA);
OPACITY + KEY COLOR
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
);
More info at Microsoft Documentation