RECT WindowMainRect{ 0, 0, 400, 400 };
HWND WindowMain;
HWND WindowChild;
INT main()
{
AdjustWindowRectEx(&WindowMainRect, WS_SYSMENU, FALSE, 0);
WNDCLASS WindowMainClass;
memset(&WindowMainClass, 0, sizeof(WNDCLASS));
WindowMainClass.lpfnWndProc = WindowMainProcedure;
WindowMainClass.lpszClassName = L"WindowMain";
if (!RegisterClass(&WindowMainClass)) MessageBox(NULL, L"Error", L"Register Class Error", MB_ICONWARNING);
WindowMain = CreateWindowEx(0, L"WindowMain", L"Window", WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, WindowMainRect.right, WindowMainRect.bottom, NULL, NULL, NULL, NULL);
ShowWindow(WindowMain, TRUE);
WindowChild = CreateWindow(L"Edit", NULL, WS_CHILD | WS_BORDER, 0, 0, 350, 350, WindowMain, NULL, NULL, NULL);
ShowWindow(WindowChild, TRUE);
MSG Msg;
Msg.message = WM_NULL;
while (Msg.message != WM_QUIT)
{
if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
}
The code above creates a window by 400 x 400 and adjusted by WS_SYSMENU.
Assumptively, the client area of this window should be 400 x 400 pixels with a 1:1 aspect ratio,
I create a child window at (0,0) with the width of 350, and height of 350.
Although, visibly the client area is not 1:1 and is vertically stretched.
Using photoshop I counted the pixels, I expected it to be above 400 pixels vertically and 400 pixels horizontally,
Although the results returned ~386 pixels in width, and ~394 pixels in height.
How do I fix this and have the client area 1:1?
Related
I have a window, which I want it to behave like a toggle button. Once clicked it will add 4px border and clicking after will make the border disappear. I figured how to make the window behave like a toggle button using BS_PUSHLIKE and Button_SetCheck() but can't seem to figure out how to adjust the border size for this window.
Thanks to all who take their time to help
Maybe you can use MoveWindow to resize the window, and then draw the border yourself, like this,
Draw a borderless window first:
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
100, 100, 800, 600, nullptr, nullptr, hInstance, nullptr);
LONG lStyle = GetWindowLong(hWnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
SetWindowLong(hWnd, GWL_STYLE, lStyle);
Then handle the window border in the WM_LBUTTONDOWN message:
int num = 0;
case WM_LBUTTONDOWN:
{
RECT rcWind;
HDC dc = GetDC(hWnd);
GetWindowRect(hWnd, &rcWind);
if (num >= 0)
{
num--;
RECT rcClient;
MoveWindow(hWnd, rcWind.left - 4, rcWind.top - 4, 8 + rcWind.right - rcWind.left, 8 + rcWind.bottom - rcWind.top, TRUE);
GetClientRect(hWnd, &rcClient);
HPEN hPen = CreatePen(PS_SOLID, 4, RGB(255, 128, 1));
HGDIOBJ hOldPen = SelectObject(dc, hPen);
Rectangle(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
DeleteObject(hPen);
}
else if (num < 0)
{
MoveWindow(hWnd, rcWind.left + 4, rcWind.top + 4, rcWind.right - rcWind.left - 8, rcWind.bottom - rcWind.top - 8, TRUE);
num++;
}
}
break;
I have a png image which has a transparent background and I want to use it as a background for a layered window. The goal is to be able to see through the window in the transparent sections of the image (even if the window is moved or the desktop behind it changes).
I tried lots of stuff, but I only managed to draw what is behind the window (when the window is created the image and the desktop behind is displayed but when the window is moved the transparent background no longer works)
I already checked Creating a transparent window in C++ Win32 and create transparent image from png, winapi but I cannot reproduce similar results
Minimal code example :
I use the following function for UpdateLayeredWindow from How To Use UpdateLayeredWindow
void display(HWND hwnd, const wchar_t* path)
{
// Load our PNG image
CImage img;
img.Load(path);
// Get dimensions
int iWidth = img.GetWidth();
int iHeight = img.GetHeight();
// Make mem DC + mem bitmap
HDC hdcScreen = GetDC(NULL);
HDC hDC = CreateCompatibleDC(hdcScreen);
HBITMAP hBmp = CreateCompatibleBitmap(hdcScreen, iWidth, iHeight);
HBITMAP hBmpOld = (HBITMAP)SelectObject(hDC, hBmp);
// Draw image to memory DC
img.Draw(hDC, 0, 0, iWidth, iHeight, 0, 0, iWidth, iHeight);
// Call UpdateLayeredWindow
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
POINT ptPos = { 0, 0 };
SIZE sizeWnd = { iWidth, iHeight };
POINT ptSrc = { 0, 0 };
UpdateLayeredWindow(hwnd, hdcScreen, &ptPos, &sizeWnd, hDC, &ptSrc, 0, &blend, ULW_ALPHA);
SelectObject(hDC, hBmpOld);
DeleteObject(hBmp);
DeleteDC(hDC);
ReleaseDC(NULL, hdcScreen);
}
To create the window :
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
{
SetProcessDPIAware();
GdiplusStartupInput gpStartupInput;
ULONG_PTR gpToken;
GdiplusStartup(&gpToken, &gpStartupInput, NULL);
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_POPUP | WS_EX_TOPMOST | WS_EX_LAYERED, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT,
700, 700,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GdiplusShutdown(gpToken);
return 0;
}
And in the message handler of the window :
case WM_CREATE:
{
const wchar_t* path = L"path_to_png_image";
display(hwnd, path);
}
break;
case WM_PAINT:
{
//doing nothing
}
break;
The problem of that code is simply that nothing is drawn : I just get a fully transparent window.
Also, I checked and WM_PAINT is called even if I don't use SetLayeredWindowAttributes
EDIT :
The solution as pointed in the commentaries is to set WS_EX_TOPMOST | WS_EX_LAYERED as the first parameter of CreateWindowEx :
hwnd = CreateWindowEx(
WS_EX_TOPMOST | WS_EX_LAYERED, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_POPUP, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT,
700, 700,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
When I create my window, it is smaller than the width and height specified, that should be 840x840. The actual window created is only approx 825x782 (not including menus etc). I can't work out why the window is small and have never had this problem before. Thanks in advance.
CreateWindowW(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 200, 840, 840,
NULL, NULL, NULL, NULL);
The solution is to use AdjustWindowRect function as commented by Simon Mourier, where rect is the size of the client window.
RECT rect = {0, 0, width, height};
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, true);
CreateWindowW(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 200,
rect.right - rect.left, rect.bottom - rect.top,
NULL, NULL, hPrevInst, NULL);
How to set a window to the right-down corner of the screen (not including the taskbar)? Can I accomplish it with CreateWindowEx? But I only saw CW_USEDEFAULT and there is no CW_ to set it to the corner.
HWND hwnd = CreateWindowEx(
NULL,
DUCKPROC_CLASS_NAME,
DUCKPROC_WINDOW_TIP_NAME,
WS_BORDER| WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
This is an example of placing the window to right bottom corner. (Here I set window's width and height are both 200.)
RECT desktopRect;
if (!GetWindowRect(GetDesktopWindow(), &desktopRect))
return FALSE;
int windowWidth = 200;
int windowHeight = 200;
int posX = desktopRect.right - windowWidth;
int posY = desktopRect.bottom - windowHeight;
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
posX, posY, windowWidth, windowHeight, nullptr, nullptr, hInstance, nullptr);
You can use CreateWindowEx but you don't have to because:
Creates an overlapped, pop-up, or child window with an extended window
style; otherwise, this function is identical to the CreateWindow
function.
HDC hdcScreen = GetDC(NULL);
HDC hdcWindow = GetDC(mWin);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
if (!hdcScreen || !hdcWindow || !hdcMem){
MessageBox(NULL, "could not locate hdc's", "Viewer", MB_ICONERROR);
}
if (!StretchBlt(hdcMem, 0, 0, 300, 300, hdcScreen, 0, 0, 300, 300, SRCCOPY)){
MessageBox(NULL, "stretchblt failed", "Viewer", MB_ICONERROR);
}
else if (!BitBlt(hdcWindow, 0, 0, 300, 300, hdcMem, 0, 0, SRCCOPY)){
// error
MessageBox(NULL, "stretchblt failed", "Viewer", MB_ICONERROR);
}
ReleaseDC(NULL, hdcScreen);
ReleaseDC(mWin, hdcWindow);
ReleaseDC(mWin, hdcMem);
A single call to StretchBlt from Screen to Window works fine, but the above does not.
Any helpful tips?
[Edit]
No errors are triggered, so everything seems to work fine, however the window associated with mWin is blank.
You need to create a bitmap and select it into the memory DC using SelectObject.