Moving a child control to top - c++

How can i move a control to top of the other when they have overlap together in windows API.
For example i create 2 buttons b1 and b2
HWND b1 = CreateWindow(L"BUTTON", L"button1", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
100, 100, 200, 50, my_Window_handle, (HMENU)100, NULL, NULL);
HWND b2 = CreateWindow(L"BUTTON", L"button2", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
50, 100, 250, 50, my_Window_handle, (HMENU)101, NULL, NULL);
I want to move b1 to top of the b2 or any control.
I used the function SetWindowPos as
SetWindowPos(b1, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
but id does not work correctly.

You don't want the child window to be top most, you want it to be at the top of the z-order. Like this:
SetWindowPos(b1, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
The documentation says for HWND_TOP:
Places the window at the top of the Z order.

Topmost will not work here because the child window must stay at the same z-order as its parent and SetWindowPos with HWND_TOPMOST as Hwnd_InsertAfter will try to change it. Only thing you need here is WS_CLIPSIBLINGS and then b1 will remain on top of b2.
b1 = CreateWindow(L"BUTTON", L"button1", WS_CHILD | WS_VISIBLE | WS_TABSTOP,
100, 100, 200, 50, hWnd, (HMENU)100, NULL, NULL);
b2 = CreateWindow(L"BUTTON", L"button2", WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS, 50, 100, 250, 50, hWnd, (HMENU)101, NULL, NULL);

As well as setting the z-order, you need to set the WS_CLIPSIBLINGS style on the controls if they overlap, to stop them drawing over the top of each other.

Related

How to use the SetWindowPos function?

I'd like to create a Windows app consisting of a main parent window and several child windows. Here is an excerpt of the code I have so far:
...
// -----> CHILD WINDOWS <-----
HWND hWnd_child1 = CreateWindowW(L"STATIC", L"Child 1", WS_CHILD,
0, 0, 100, 80, hParentWnd, nullptr, hInstance, nullptr);
if (!hWnd_child1) {
MessageBox(NULL, L"CreateWindowW Child 1", L"Error!", MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
HWND hWnd_child2 = CreateWindowW(L"STATIC", L"Child 2", WS_CHILD,
10, 10, 160, 120, hParentWnd, nullptr, hInstance, nullptr);
if (!hWnd_child2) {
MessageBox(NULL, L"CreateWindowW Child 2", L"Error!", MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
HWND hWnd_child3 = CreateWindowW(L"STATIC", L"Child 3", WS_CHILD,
20, 20, 160, 120, hParentWnd, nullptr, hInstance, nullptr);
if (!hWnd_child3) {
MessageBox(NULL, L"CreateWindowW Child 3", L"Error!", MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
ShowWindow(hWnd_child3, nCmdShow);
SetWindowPos(hWnd_child2, HWND_TOP, 10, 10, 100, 80, NULL);
ShowWindow(hWnd_child2, nCmdShow);
SetWindowPos(hWnd_child1, HWND_TOP, 0, 0, 100, 80, NULL);
ShowWindow(hWnd_child1, nCmdShow);
ShowWindow(hParentWnd, nCmdShow);
UpdateWindow(hParentWnd);
// -------------------
...
The problem is with the SetWindowPos() function. I can't understand how it really works. I thought that calling it like this:
ShowWindow(hWnd_child3, nCmdShow);
SetWindowPos(hWnd_child2, HWND_TOP, 10, 10, 100, 80, NULL);
ShowWindow(hWnd_child2, nCmdShow);
SetWindowPos(hWnd_child1, HWND_TOP, 0, 0, 100, 80, NULL);
ShowWindow(hWnd_child1, nCmdShow);
Would move the Child 1 window to the top of all the app windows (as the doc says for the HWND_TOP option: Places the window at the top of the Z order).
BUT, the windows are still drawned in the creation order:
Shouldn't SetWindowPos() move firstly Child 2 over Child 3, and next Child 1 over Child 2, making the windows laid up in the reverse order than they were created, with Child 1 on top?
Make the child windows all have the window style WS_CLIPSIBLINGS along with WS_CHILD etc.
From Microsoft's documentation:
If WS_CLIPSIBLINGS is not specified and child windows overlap, it is
possible, when drawing within the client area of a child window, to
draw within the client area of a neighboring child window.
Basically if the child windows do not clip each other then the order in which they are painted (which is arbitrary) determines the visual z-order.
Below for instance is your code with the message box stuff removed, using WS_VISIBLE instead of ShowWindow, adding a border for visibility, and using WS_CLIPSIBLINGS.
BOOL CreateChildren(HWND hParentWnd) {
HWND hWnd_child1 = CreateWindowEx(WS_EX_CLIENTEDGE, L"STATIC", L"Child 1", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0, 0, 100, 80, hParentWnd, nullptr, g_hInstance, nullptr);
HWND hWnd_child2 = CreateWindowEx(WS_EX_CLIENTEDGE, L"STATIC", L"Child 2", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
10, 10, 160, 120, hParentWnd, nullptr, g_hInstance, nullptr);
HWND hWnd_child3 = CreateWindowEx(WS_EX_CLIENTEDGE, L"STATIC", L"Child 3", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
20, 20, 160, 120, hParentWnd, nullptr, g_hInstance, nullptr);
SetWindowPos(hWnd_child2, HWND_TOP, 10, 10, 100, 80, NULL);
SetWindowPos(hWnd_child1, HWND_TOP, 0, 0, 100, 80, NULL);
UpdateWindow(hParentWnd);
return TRUE;
}
which yields
child1 is on top.

Winapi - Removing EDIT window border c++

I have a button and an EDIT window i named "textbox" initially. What i want to achieve is: when i press the button, the EDIT window's border will be remove and it's text is also changed. Here is how i initial them:
HWND textbox; //global variable
//in WM_CREATE:
CreateWindowEx(NULL, L"BUTTON", L"Remove border",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 10, 150, 40, hwnd,
(HMENU)IDC_TEXTBOX, NULL, NULL);
textbox = CreateWindowEx(
NULL, L"EDIT", NULL,
WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE,
100, 100, 200, 100, hwnd, (HMENU) 0, NULL, NULL
);
SetWindowText(textbox, L"the initial text");
Since there is WS_BORDER in its style at the start, i thought removing it from window style will remove the border so this is my first attempt:
//In WM_COMMAND
case IDC_TEXTBOX: //if button is pressed
lStyle = GetWindowLongPtr(textbox, GWL_STYLE);
lStyle &= ~(WS_CHILD | WS_VISIBLE | ES_MULTILINE);
SetWindowLongPtr(textbox, GWL_STYLE, lStyle);
SetWindowPos(textbox, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE |
SWP_NOZORDER | SWP_NOOWNERZORDER);
SetWindowText(textbox, L"how to remove the border around this text???");
break;
The code above didn't work. The window disappeared after i pressed the button. In the second attempt i followed the answer in this question:
case IDC_TEXTBOX:
lStyle = GetWindowLongPtr(textbox, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
SetWindowLongPtr(textbox, GWL_STYLE, lStyle);
lExStyle = GetWindowLongPtr(textbox, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLongPtr(textbox, GWL_EXSTYLE, lExStyle);
SetWindowPos(textbox, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE |
SWP_NOZORDER | SWP_NOOWNERZORDER);
SetWindowText(textbox, L"how to remove the border around this text???");
break;
This time, the text has changed but the border is still around after pressing the button:
so the question is: What did i do wrong in the 1st and 2nd attempt? And what should i do to remove the EDIT window border?
I would have made this a comment under your answer, but I don't have enough reputation.
Others in the comments have said that "Many of the system controls cache their initial styles and never update them" but strangely you can add a border after creation but just not remove it. So it seems that the border style is actually not cached.
My current solution is to recreate the control. Even though I can live with this solution (at the moment), I do not like it.
-Edit-
Never mind the above. I found that adding WS_BORDER after creation is actually a different border than the border added with WS_BORDER at creation. When you create the edit control with WS_BORDER and add WS_BORDER to it again with SetWindowLong() then the edit control now has 2 visible borders appearing as a single 2 pixel border. The WS_BORDER added after creation can be removed after creation but the initial WS_BORDER added at creation cannot be removed. So it appears that the initial edit border actually does get cached.

Newline on win32 gui textbox when using SetWindowText

I create a textbox on a win32 gui app. Later on I'm trying to set a text to it but newline "\n" isn't working when using SetWindowText
g_ButtonManager.hWndThirtyText = CreateWindowExW(WS_EX_CLIENTEDGE, TEXT("Edit"), TEXT(""),
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE,
10, 95, //x,y
200, 60, //width, height
hWnd, (HMENU)IDM_THIRTYTEXT, NULL, NULL);
Even though I:
SetWindowTextA(g_ButtonManager.hWndThirtyText, "Hello\nThere");
It displays HelloThere in the same line.
---Edit
Even with | ES_WANTRETURN
g_ButtonManager.hWndThirtyText = CreateWindowExW(WS_EX_CLIENTEDGE, TEXT("Edit"), TEXT("Hello\nMy\nFriend"),
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | ES_WANTRETURN,,
10, 95, //x,y
200, 60, //width, height
hWnd, (HMENU)IDM_THIRTYTEXT, NULL, NULL);
Will not work.
Oh, I figured it.
\r\n is required for a newline.

Win 32 API, drawing two child windows with vertical splitter bar

Below is code, which I am using for creating child windows:
case WM_CREATE:
hInst = ((LPCREATESTRUCT) lParam) -> hInstance;
hWnd1 = CreateWindowEx( WS_EX_CLIENTEDGE | WS_EX_LEFT,
"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_MULTILINE | WS_VSCROLL,
0, 0, 0, 0,
hWnd, (HMENU) 1,
hInst, NULL );
hWnd2 = CreateWindowEx( WS_EX_CLIENTEDGE | WS_EX_LEFT,
"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_MULTILINE | WS_VSCROLL,
0, 0, 0, 0,
hWnd, (HMENU) 2,
hInst, NULL );
But this code produces horizontal splitter, and I want vertical splitter.
First I thought, if I change height and width parameters, I could create vertical splitter. But it was of no use.
For full code and sample example (in order to save space on SO):
http://old.sumitbirla.com/software/src/splitter.c
So, what is exactly keyword/parameter, which would produce vertical splitter bar.
The code you posted just creates two child windows. It has nothing to do with vertical or horizontal splitter. Handle the WM_SIZE message in the parent window to position and size the child windows for a vertical or horizontal split.

EDIT control text overflow

This is simple. I created an EDIT control like this:
HWND MYTEXT= CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD|WS_VISIBLE|ES_LEFT|ES_MULTILINE,
20, 120, 150, 20, hWnd, NULL, hInst, NULL);
but when I type text inside of it I can't type more text than the width of the EDIT control. When I reach the end it's like there's no more space and I get a beep. How can I make the text scroll in this situation?
You can give your edit control the WS_HSCROLL and/or WS_VSCROLL window styles. For instance:
HWND myText
= CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD | WS_VISIBLE | WS_HSCROLL | ES_LEFT | ES_MULTILINE,
20, 120, 150, 20, hWnd, NULL, hInst, NULL);
Alternately, as Matthew T. Staebler rightfully suggests, use ES_AUTOHSCROLL and/or ES_AUTOVSCROLL (note the ES_ prefix, as these are edit styles, not window styles).