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.
Related
everyone !
I'm trying to have 2 buttons at same time in a C++ application and each other does 2 different actions.
Code :
MSG msg;
HWND m_hwnd = GetConsoleWindow();
HWND hwndButton1 = CreateWindow(TEXT("button"), TEXT("B1"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_FLAT, 100, 100, 100, 30, m_hwnd, NULL, (HINSTANCE)GetWindowLong(m_hwnd, GWL_HINSTANCE), NULL);
HWND hwndButton2 = CreateWindow(TEXT("button"), TEXT("B2"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_FLAT, 200, 100, 100, 30, m_hwnd, NULL, (HINSTANCE)GetWindowLong(m_hwnd, GWL_HINSTANCE), NULL);
ShowWindow(hwndButton2, SW_SHOW);
ShowWindow(hwndButton1, SW_SHOW);
UpdateWindow(hwndButton2);
UpdateWindow(hwndButton1);
while(1)
{
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
if((HIWORD(WPARAM)) == BN_CLICKED and ((HWND)LPARAM) == hwndButton1)
{
printf("1st clicked");
}
if((HIWORD(WPARAM)) == BN_CLICKED and ((HWND)LPARAM) == hwndButton2)
{
printf("2nd clicked");
}
}
but it gives me a CE in the 'if' : "expected primary-expression beore ')' token"(x2, for each 'if'). Can you help me ?
WPARAM and LPARAM are types. You should use msg.wParam and msg.lParam instead:
if((HIWORD(msg.wParam)) == BN_CLICKED and ((HWND)msg.lParam) == hwndButton1)
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.
I have an application in Win32/C++ that has three buttons located in the left side of the main window. When clicking on one of them, a group of radiobuttons has to be displayed to allow the user to switch views among different submenus.
The code looks like this:
case WM_CREATE:
{
HWND hWndButton=CreateWindowEx(NULL,
"BUTTON",
"Inserting",
WS_TABSTOP|WS_VISIBLE|
WS_CHILD|BS_DEFPUSHBUTTON,
10,
10,
100,
24,
hWnd,
(HMENU)INSERT_BUTTON,
GetModuleHandle(NULL),
NULL);
HWND hWndButton2=CreateWindowEx(NULL,
"BUTTON",
"Listing",
WS_TABSTOP|WS_VISIBLE|
WS_CHILD|BS_DEFPUSHBUTTON,
10,
60,
100,
24,
hWnd,
(HMENU)LIST_BUTTON,
GetModuleHandle(NULL),
NULL);
HWND hWndButton3=CreateWindowEx(NULL,
"BUTTON",
"Consulting",
WS_TABSTOP|WS_VISIBLE|
WS_CHILD|BS_DEFPUSHBUTTON,
10,
110,
100,
24,
hWnd,
(HMENU)SELECT_BUTTON,
GetModuleHandle(NULL),
NULL);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case INSERT_BUTTON:
{
HWND hGrpButtons=CreateWindowEx(WS_EX_WINDOWEDGE,
"BUTTON",
"Select a table:",
WS_VISIBLE | WS_CHILD| BS_GROUPBOX, // Styles
150,30,470,70,
hWnd,
NULL,
GetModuleHandle(NULL), NULL);
HWND hwndCB1 = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "TSector", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | WS_GROUP,
160, 60, 80, 20, hWnd,(HMENU)CB1, GetModuleHandle(NULL), NULL);
HWND hwndCB2 = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "TSeccio", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON ,
250, 60, 80, 20, hWnd,(HMENU)CB2, GetModuleHandle(NULL), NULL);
HWND hwndCB3 = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "TActivitat", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
340, 60, 80, 20, hWnd,(HMENU)CB3, GetModuleHandle(NULL), NULL);
HWND hwndCB4 = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "TClasse", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
430, 60, 80, 20, hWnd,(HMENU)CB4, GetModuleHandle(NULL), NULL);
HWND hwndCB5 = CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "TQuantitat", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
520, 60, 85, 20, hWnd,(HMENU)CB5, GetModuleHandle(NULL), NULL);
switch(HIWORD(wParam))
{
case CB1:
//Do something
break;
}
}
break;
}
break;
Maybe the switch after creating the radiobuttons is not well implemented but anyway, when compiling, any of the menus that I want to display when clicking on each radiobuttons are not recognised: the compile error I'm retrieving says that I need to declare each menu.
It sounds weird to me because it works in other cases.
Any help would be much appreciated.
CB1 is the identifier of your control, if it is undeclared then just declare using the #define, like this:
#define CB1 1000
the identifier cannot be repeated with id of others controls.
a good way to create menus is to create all the submenus hidden, and when someone click in an option, you just show the submenu using the ShowWindow function.
to create a hidden submenu, just remove the WS_VISIBLE in the CreateWindowEx.
see this example:
// Opts
#define Fruits 1
#define Colors 2
// Fruits
#define Apple 5
#define Pineapple 6
// Colors
#define Red 10
#define Blue 11
void HideAll(HWND hwnd)
{
// Fruits
ShowWindow(GetDlgItem(hwnd, Apple), SW_HIDE);
ShowWindow(GetDlgItem(hwnd, Pineapple), SW_HIDE);
// Colors
ShowWindow(GetDlgItem(hwnd, Red), SW_HIDE);
ShowWindow(GetDlgItem(hwnd, Blue), SW_HIDE);
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
// Menus - All created visible
CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Fruits", WS_VISIBLE | WS_CHILD,
10, 10, 80, 20, hwnd,(HMENU)Fruits, GetModuleHandle(NULL), NULL);
CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Colors", WS_VISIBLE | WS_CHILD,
10, 40, 80, 20, hwnd,(HMENU)Colors, GetModuleHandle(NULL), NULL);
// Fruits - All created Invisible
CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Apple", WS_CHILD,
100, 10, 80, 20, hwnd,(HMENU)Apple, GetModuleHandle(NULL), NULL);
CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Pineapple", WS_CHILD,
100, 40, 80, 20, hwnd,(HMENU)Pineapple, GetModuleHandle(NULL), NULL);
// Colors - All created Invisible
CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Red", WS_CHILD,
100, 10, 80, 20, hwnd,(HMENU)Red, GetModuleHandle(NULL), NULL);
CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "Blue", WS_CHILD,
100, 40, 80, 20, hwnd,(HMENU)Blue, GetModuleHandle(NULL), NULL);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case Fruits:
// Hide old
HideAll(hwnd);
// Show new
ShowWindow(GetDlgItem(hwnd, Apple), SW_SHOW);
ShowWindow(GetDlgItem(hwnd, Pineapple), SW_SHOW);
break;
case Colors:
// Hide old
HideAll(hwnd);
// Show new
ShowWindow(GetDlgItem(hwnd, Red), SW_SHOW);
ShowWindow(GetDlgItem(hwnd, Blue), SW_SHOW);
break;
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
This is the result of the program:
and when someone click in fruits, it show the fruits suboptions:
and when someone click in colors, the ShowWindow hide the old suboptions and show new suboptions:
I tried to create two overlapped windows but only one popped up. I plan to use 1 window to handle the buttons and another separate window(not child) to show images that changes every 1 second. Is it possible? I tried to use 1 window to handle both but the buttons went missing and are unable to click because the program is busy running the display. And what parameter to set for the HINSTANCE for the second window?
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
HWND hWnd2;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
100, 0,1000, 700, NULL, NULL, hInstance, NULL);
hWnd2= CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
100, 0,1000, 700, NULL, NULL, NULL, NULL);
CreateWindow(TEXT("button"), TEXT("\t Start Scanning\n"),
WS_VISIBLE | WS_CHILD | WS_BORDER,
810, 320, 150, 150,
hWnd, (HMENU) IDM_BEGIN, NULL, NULL);
CreateWindow(TEXT("button"), TEXT("\t STOP \n"),
WS_VISIBLE | WS_CHILD | WS_BORDER,
810, 480, 150, 150,
hWnd, (HMENU) IDM_PERMASTOP, NULL, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
You are creating two overlapped windows, but you are calling ShowWindow() on only the first time. Simply call ShowWindow() on the other one as well.
I created an up-down control by the following code.
HWND hEdit, hUpDown;
hEdit = CreateWindowExW(WS_EX_CLIENTEDGE,
L"EDIT",
Content.c_str(),
ES_LEFT | WS_VISIBLE | WS_CHILD,
600,
260,
100,
25,
hWndParent,
NULL,
hInstance,
NULL);
INITCOMMONCONTROLSEX iccx;
iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccx.dwICC = ICC_UPDOWN_CLASS;
InitCommonControlsEx(&iccx);
hUpDown = CreateWindowExW( 0,
UPDOWN_CLASSW,
L"",
UDS_ARROWKEYS | UDS_ALIGNRIGHT | WS_VISIBLE | WS_CHILD,
0,
0,
0,
0,
hWndParent,
NULL,
hInstance,
NULL);
SendMessageW(hUpDown, UDM_SETBUDDY, (WPARAM) hEdit, (LPARAM) NULL);
SendMessageW(hUpDown, UDM_SETRANGE32, (WPARAM) 0, (LPARAM) 100);
Sleep(5000);
SendMessageW(hUpDown, UDM_SETPOS32, (WPARAM) NULL, (LPARAM) 20);
Sleep(5000);
SendMessageW(hUpDown, UDM_SETPOS32, (WPARAM) NULL, (LPARAM) 60);
I checked the return values of the SendMessageW() functions. They terminate successfully by returning the previous position value as documented.
The created up-down control looks normal:
The problem is, sending the UDM_SETPOS32 message, clicking the up and down arrows and pressing the up and down keys on the keyboard have no effect. I can't change the contents of the edit control (the buddy window of the up-down control) without directly typing something into it. It just stays empty.
I am able to type anything in it manually by using keyboard:
How do I change the position/value of this up-down control by pressing keyboard arrow keys, by clicking the arrows in the GUI and by sending UDM_SETPOS32 in the code? What am I missing in my code?
Use the style UDS_SETBUDDYINT to the up-down control while creating it.
From MSDN documentation:
UDS_SETBUDDYINT
Causes the up-down control to set the text of the buddy window (using the WM_SETTEXT message) when the position changes. The text consists of the position formatted as a decimal or hexadecimal string.
Change the creation code of the up-down control like this by adding the UDS_SETBUDDYINT style:
hUpDown = CreateWindowExW( 0,
UPDOWN_CLASSW,
L"",
UDS_SETBUDDYINT | UDS_ARROWKEYS | UDS_ALIGNRIGHT | WS_VISIBLE | WS_CHILD,
0,
0,
0,
0,
hWndParent,
NULL,
hInstance,
NULL);