Related
I want to disable the radio buttons when I select the checkbox. It works when I pass hwnd in addFunc2(), however, I need it to be in the second tab but somehow I can't find any way to make it work.
I apologize if its confusing, I'm very new at this, and my first time posting here. Please let me know if I need to clarify it more. Please refer to the images and some of my code below:
Result of code:
What I need:
HWND hRadio1, hRadio2, hTab, g_tabPanes[2];
HWND CreateTabPane(HWND tabctrl, int id, HINSTANCE instance)
{
RECT rcTab;
GetClientRect(tabctrl, &rcTab);
TabCtrl_AdjustRect(tabctrl, FALSE, &rcTab);
int wd = rcTab.right - rcTab.left;
int hgt = rcTab.bottom - rcTab.top;
return CreateWindow(
L"static", L"",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
rcTab.left, rcTab.top, wd, hgt,
tabctrl,
(HMENU)id,
instance,
NULL
);
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
addControl(hwnd);
HINSTANCE hInst = GetModuleHandle(NULL);
RECT rc; int dx, dy;
GetClientRect(hwnd, &rc);
dx = rc.right - rc.left;
dy = rc.bottom - rc.top;
TCITEM tie = {
TCIF_TEXT | TCIF_IMAGE,
0, 0,
NULL,
0, -1, 0
};
hTab = CreateWindowEx(NULL, WC_TABCONTROL, _T(""),
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0, 0, dx, dy, hwnd,
(HMENU)1001, hInst, NULL
);
tie.pszText = (LPWSTR)_T("Tab 1");
TabCtrl_InsertItem(hTab, 0, &tie);
tie.pszText = (LPWSTR)_T("Tab 2");
TabCtrl_InsertItem(hTab, 1, &tie);
for (int i = 0; i < 2; i++)
g_tabPanes[i] = CreateTabPane(hTab, TAB_ID + i, hInst);
addFunc1(g_tabPanes[0]);
addFunc2(g_tabPanes[1]);
break;
}
case WM_COMMAND:
{
switch (wParam)
{
case ID_CHECKBOX:
{
switch (HIWORD(wParam))
{
case BN_CLICKED:
if (SendDlgItemMessage(hwnd, ID_CHECKBOX, BM_GETCHECK, 0, 0))
{
EnableWindow(hRadio1, true);
EnableWindow(hRadio2, true);
}
else
{
EnableWindow(hRadio1, false);
EnableWindow(hRadio2, false);
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR ns = (LPNMHDR)lParam;
if ((ns->idFrom == 1001) && (ns->code == TCN_SELCHANGE))
{
int pane = TabCtrl_GetCurSel(hTab);
for (int i = 0; i < 2; i++)
if (pane == i)
ShowWindow(g_tabPanes[i], SW_SHOW);
else
ShowWindow(g_tabPanes[i], SW_HIDE);
}
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
void addFunc2(HWND hwnd)
{
HWND hCheckbox;
CreateWindow(TEXT("static"), TEXT("Duplex: "), WS_CHILD | WS_VISIBLE,
75, 10, 90, 25, hwnd, NULL, NULL, NULL);
hCheckbox = CreateWindow(L"button", L"Print on both sides", WS_CHILD | WS_VISIBLE |
BS_AUTOCHECKBOX | WS_TABSTOP,
75, 30, 150, 30, hwnd, (HMENU)ID_CHECKBOX, g_hinst, NULL);
hRadio1 = CreateWindow(L"button", L"Flip on long edge", WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON | WS_TABSTOP,
75, 55, 150, 30, hwnd, (HMENU)ID_RADIO1, g_hinst, NULL);
hRadio2 = CreateWindow(L"button", L"Flip on short edge", WS_CHILD | WS_VISIBLE |
BS_AUTORADIOBUTTON | WS_TABSTOP,
75, 80, 150, 30, hwnd, (HMENU)ID_RADIO2, g_hinst, NULL);
SendMessage(hCheckbox, BM_SETCHECK, BST_CHECKED, 0);
SendMessage(hRadio1, BM_SETCHECK, BST_CHECKED, 0);
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.
Hello i am making my first windows application code.
I want to know how can i make a CreateWindow(TEXT("STATIC") child window, inside my main window, in which when the user clicks to add text on it,i want the
CreateWindow(TEXT("STATIC"), TEXT("REPORT") "REPORT" text to dissapear.
(Some of the text is in greek)
Example: like this "Email or username" and "password" texts, that dont interrupt the user
https://www.codecademy.com/login?redirect=about%3A%2F%2Fblank
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
switch(Message) {
case WM_COMMAND:{
break;
}
case WM_CREATE:{
HMENU hMenubar= CreateMenu();
HMENU hFile= CreateMenu();
HMENU hOptions= CreateMenu();
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hFile, "File");
AppendMenu(hMenubar, MF_POPUP, NULL, "Edit");
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hOptions, "Options");
AppendMenu(hFile, MF_STRING, NULL, "Open");
AppendMenu(hOptions, MF_STRING, NULL, "Correction");
AppendMenu(hOptions, MF_STRING, NULL, "Search");
SetMenu(hwnd,hMenubar);
CreateWindow(TEXT("edit"), TEXT(""),
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
10, 10, 200, 30,
hwnd, (HMENU) ID_NAMEBOX, NULL, NULL
);
CreateWindow(TEXT("STATIC"), TEXT("NAME"),
WS_VISIBLE | WS_CHILD,
10, 10, 200, 30,
hwnd, (HMENU) ID_VNAMEBOX, NULL, NULL
);
CreateWindow(TEXT("edit"), TEXT("CALL1"),
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
220, 10, 200, 30,
hwnd, (HMENU) ID_CALLBOX, NULL, NULL
);
CreateWindow(TEXT("edit"), TEXT("CALL2"),
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
220, 50, 200, 30,
hwnd, (HMENU) ID_CALLBOX, NULL, NULL
);
CreateWindow(TEXT("edit"), TEXT("REPORT"),
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
10, 90, 410, 100,
hwnd, (HMENU) ID_REPORTBOX, NULL, NULL
);
hwnd= CreateWindow(TEXT("button"), TEXT("SUBMIT"),
WS_VISIBLE | WS_CHILD,
55, 50, 100, 30,
hwnd, (HMENU) ID_SUBMITBOX, NULL, NULL
);
break;
}
/* Upon destruction, tell the main thread to stop */
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
/* All other messages (a lot of them) are processed using default procedures */
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
The following is my winapi program that window contains 3 sets of controls:
The controls that created directly in the window
The controls in Group1
The controls in Group2
When I press Tab-key , it only traverse in set1.
Why I can't switch to the child control of the group1 and group2 by Tab-key?
#include <Windows.h>
LRESULT __stdcall WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(0, 0, 255));
SetBkMode(hdcStatic, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////
void CreateEdit(const HWND &parent, const int &x, const int &y, const int &id) {
CreateWindow(L"EDIT", L"", WS_BORDER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, x, y, 200, 20, parent, (HMENU)id, NULL, NULL);
}
////////////////////////////////////////////////////////////////////////////
int __stdcall wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
WNDCLASSEX wndclass{};
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.hbrBackground = CreateSolidBrush(RGB(255, 128, 255));
wndclass.lpszClassName = L"test";
RegisterClassEx(&wndclass);
HWND hWndMainWindow = CreateWindow(
wndclass.lpszClassName,
L"test",
WS_EX_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE,
100, 100, 500, 500,
NULL, NULL, hInstance, NULL);
::ShowWindow(hWndMainWindow, SW_SHOW);
::UpdateWindow(hWndMainWindow);
//Creating Controls~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int x = 10, y = 20, id = 100;
HWND g1 = CreateWindow(L"button", L"Group1", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 0, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
//Controls in Group1
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
HWND g2 = CreateWindow(L"button", L"Group2", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 260, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
y = 20;
//Controls in Group2
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
//The controls that create directly in the main window
y = 270;
CreateWindow(L"static", L"Main Window Controls", WS_CHILD | WS_VISIBLE, x, y, 200, 30, hWndMainWindow, (HMENU)++id, NULL, NULL);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
if (!IsDialogMessage(hWndMainWindow, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
The two child windows that host "Group1" and "Group2" both need to be marked as "control parents" with the WS_EX_CONTROLPARENT style. This style means:
The window itself contains child windows that should take part in
dialog box navigation. If this style is specified, the dialog manager
recurses into children of this window when performing navigation
operations such as handling the TAB key, an arrow key, or a keyboard
mnemonic
Change your code to create those windows as follows:
HWND g1 = CreateWindowEx(WS_EX_CONTROLPARENT, L"button", L"Group1", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 0, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
HWND g2 = CreateWindowEx(WS_EX_CONTROLPARENT, L"button", L"Group2", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 260, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
(As an aside, it seems wrong to make your windows children of the groupbox. They don't need to be - you can just position them inside it but make them siblings of it instead of children. The groupbox is specifically designed to work this way - I don't know how well it will work with the controls as children.)
Since you're not creating a dialog box, your main window should be created with the WS_EX_CONTROLPARENT style.
Make sure that you only place this style on your main window. The child windows should not be using this style.
I know it is a very simple question but i currently cant create a parent window...
My code:
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
static HWND paste;
static HWND update_list;
/*HWND changeuser = CreateWindow(0, 0,
0,
0, 0, x, y,
0, (HMENU)changeuser2, 0, NULL); */
switch(msg)
{
case WM_CREATE:
meniu(hwnd);
CreateWindow(TEXT("static"), TEXT("\nSuckers online:"),
WS_VISIBLE | WS_CHILD | SS_CENTER,
0, 0, x, 55,
hwnd, (HMENU)delete, NULL, NULL);
connected = CreateWindow(TEXT("edit"), TEXT(""),
WS_VISIBLE | WS_CHILD | WS_VSCROLL| ES_MULTILINE ,
0, 60, x, 340,
hwnd, (HMENU)delete2, NULL, NULL);
CreateWindow(TEXT("static"), TEXT(""),
WS_VISIBLE | WS_CHILD | SS_CENTER|BS_PUSHBUTTON,
0, 405, x, 358,
hwnd, (HMENU) delete3, NULL, NULL);
paste = CreateWindow(TEXT("Edit"), TEXT("Paste the ip here"),
WS_VISIBLE | WS_CHILD | SS_CENTER,
x/2 - 60, 410, 120, 40,
hwnd, (HMENU) ip, NULL, NULL);
CreateWindow(TEXT("Button"), TEXT("Connect!"),
WS_VISIBLE | WS_CHILD | SS_CENTER | BS_PUSHBUTTON,
x/2 - 120, 450, 120, 40,
hwnd, (HMENU) connect2, NULL, NULL);
update_list = CreateWindow(TEXT("Button"), TEXT("Update the list!"),
WS_VISIBLE | WS_CHILD | SS_CENTER | BS_PUSHBUTTON,
x/2, 450, 120, 40,
hwnd, (HMENU) update, NULL, NULL);
_beginthread( lista, 0, (void*)(0) );//begin thread lista
break;
case WM_CTLCOLORSTATIC : {
HBRUSH br = CreateSolidBrush(RGB(80,67,77)); // change background color
SetTextColor((HDC)wParam,RGB(0,102,51)); //the controls text color
return (LRESULT) br;
}
case WM_COMMAND:
switch LOWORD(wParam)
{
case exit:
PostQuitMessage(0);
break;
case ip:
int nr;
nr = GetWindowTextLength(paste);
if (nr >= 17)
SetWindowText(paste, "");
break;//omor textul, ca sa pot sa fac paste
case connect2:
GetWindowText(paste,adresa,16);
_beginthread( start, 0, (void*)(0) ); //as\ici se face conexiunea principala
//DestroyWindow(hwnd);
MessageBox(0,"Connected with the user","Ok",0);
break;
case update:
exit2 = true;
Sleep(100);
SetWindowText(connected,"");
_beginthread( lista, 0, (void*)(0) );//begin thread lista
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I want the other windows created to be the child of the changeuser window...
I just cant make it happen...
Any help will be appreciated!
To change the window of a parent, use SetParent().
But i would think about the structure - if you need to change the parent of one or more windows in a normal dialog setting, it is likely these windows should have a different parent.
In your case there is a problem in your handling of window messages though:
If your message handler receives WM_DESTROY you call PostQuitMessage(), which probably results in your application closing.
There are two ways you can handle that:
use different window processes for your main dialog and child dialogs (preferably)
or use the hwnd parameter to decide wether you call PostQuitMessage()
You can't 'replace' a window. If you need to tear down and replace your main window, delete it and make a new one. Windows only get the parent flag when they have children, not because you tell them to.