Hiding and showing container windows based on tab - c

I have created a tab control that contains two tabs. Inside each tab there will be a container window to hold other controls (in the code example, a static control for instance). The idea is that when a new tab is selected, it will hide/show the correct container window that holds a bunch of controls. However I am struggling to get the container windows holding the static controls to show. This is the code so far:
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
#define ID_TABCTRL 1
#define ID_STATIC0 2
#define ID_STATIC1 3
#define ID_TAB0 4
#define ID_TAB1 5
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND hTab, hTab0, hTab1;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wc = { 0 };
wc.lpszClassName = TEXT("Tab control");
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
CreateWindow(wc.lpszClassName, TEXT("Tab control"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 200, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
TCITEM tie;
INITCOMMONCONTROLSEX icex;
switch (msg)
{
case WM_CREATE:
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&icex);
tie.mask = TCIF_TEXT;
///// Create Tab Control /////
hTab = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 150, hwnd, (HMENU)ID_TABCTRL, NULL, NULL);
///// Create Individual Tabs /////
tie.pszText = TEXT("First");
SendMessage(hTab, TCM_INSERTITEM, 0, (LPARAM)(LPTCITEM)&tie);
tie.pszText = TEXT("Second");
SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM)(LPTCITEM)&tie);
///// Create Container windows for each tab /////
hTab0 = CreateWindow(0, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 150, hTab, (HMENU)ID_TAB0, NULL, NULL);
hTab1 = CreateWindow(0, NULL, WS_CHILD, 0, 0, 200, 150, hTab, (HMENU)ID_TAB1, NULL, NULL);
///// Add example control to one of the tab container windows /////
CreateWindow(TEXT("Static"), TEXT("Yay!"), WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 30, 50, 25, hTab0, (HMENU)ID_STATIC0, NULL, NULL);
CreateWindow(TEXT("Static"), TEXT("It appears to be working"), WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 30, 100, 50, hTab1, (HMENU)ID_STATIC1, NULL, NULL);
break;
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case TCN_SELCHANGE:
switch (TabCtrl_GetCurSel(hTab))
{
///// Show or Hide the appropriate tabs /////
case 0:
ShowWindow(hTab1, SW_HIDE);
ShowWindow(hTab0, SW_SHOW);
case 1:
ShowWindow(hTab0, SW_HIDE);
ShowWindow(hTab1, SW_SHOW);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hwnd, msg, wParam, lParam));
}
Is it just a case of the container windows hTab0 and hTab1 being stuck behind the tab window (hTab)?

First, you need to change the position of the tab and static form, otherwise it will block the generated content.
Then you can define the generated static text directly through CreateWindow, by using WC_STATIC.
#include <Windows.h>
#include <commctrl.h>
LRESULT CALLBACK WndProc(HWND, UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam)
{
static HINSTANCE hInstance;
static HWND hwndTab = 0 , hwndStatic1,hwndStatic2;
TCITEM tie;
RECT rcClient;
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
TCHAR tabLBL1[256];
GetClientRect(hwnd, &rcClient);
switch (message)
{
case WM_CREATE:
{
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
hwndTab = CreateWindow(WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hwnd, NULL, hInstance, NULL);
//Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
wsprintf(tabLBL1, L"tab1");
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
wsprintf(tabLBL1, L"tab2");
TabCtrl_InsertItem(hwndTab, 1, &tie);
hwndStatic1 = CreateWindow(WC_STATIC, L"123",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
hwndStatic2 = CreateWindow(WC_STATIC, L"456",
WS_CHILD | WS_VISIBLE | WS_BORDER,
400, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
ShowWindow(hwndStatic1, TRUE);
ShowWindow(hwndStatic2, FALSE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NOTIFY:
if (((LPNMHDR)lParam)->code == TCN_SELCHANGE)
{
int tabID = TabCtrl_GetCurSel(hwndTab);
switch (tabID)
{
case 0:
ShowWindow(hwndStatic1, TRUE);
ShowWindow(hwndStatic2, FALSE);
break;
case 1:
ShowWindow(hwndStatic1, FALSE);
ShowWindow(hwndStatic2, TRUE);
break;
default:
break;
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

Zhu Song's answer helped solved the problem (the container windows needing to be a static control, and needing to be positioned inside the tab control's space, below the clickable tabs).
Here is the result, swapping the two container window creation lines:
hTab0 = CreateWindow(TEXT("Static"), NULL, WS_CHILD | WS_VISIBLE, 1, 25, 197, 123, hTab, (HMENU)ID_TAB0, NULL, NULL);
hTab1 = CreateWindow(TEXT("Static"), NULL, WS_CHILD, 1, 25, 197, 123, hTab, (HMENU)ID_TAB1, NULL, NULL);
Note how the container window sizes and position are small enough to just fit inside the main tab control window (you can add WS_BORDER to the style to see where exactly it fits).

Related

How to call another screen in this code below

Good night, I would like some help with this code below, I have to do an exercise that calls another registration screen, the first screen I managed to assemble, make the buttons work too, but I don't find a practical example on the internet to be able to call this one another screen, I've tried in several ways and without success, I would like some help so to be able to call another screen in this code below. I have to call this other screen there on the Register button, you can see that I've already tried and nothing happens.
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
const TCHAR CLSNAME[] = TEXT("helloworldWClass");
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);
void addControls(HWND);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow)
{
//return MessageBox(NULL, "hello, world", "caption", 0);
WNDCLASSEX wc = { };
MSG msg;
HWND hwnd;
wc.cbSize = sizeof (wc);
wc.style = 0;
wc.lpfnWndProc = winproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
//wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLSNAME;
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, TEXT("Could not register window class"),
NULL, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
_T("Covid-19"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hwnd) {
MessageBox(NULL, TEXT("Could not create window"), NULL, MB_ICONERROR);
return 0;
}
ShowWindow(hwnd, cmdshow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void addControls(HWND hwnd) {
CreateWindowW(L"Static", L"Login", WS_CHILD | WS_VISIBLE, 600, 0, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"", WS_CHILD | WS_VISIBLE, 600, 40, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Static", L"Senha", WS_CHILD | WS_VISIBLE, 600, 80, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"", WS_CHILD | WS_VISIBLE, 600, 120, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Button", L"Login", WS_CHILD | WS_VISIBLE, 600, 160, 100, 18, hwnd, (HMENU) 1, NULL, NULL);
CreateWindowW(L"Button", L"Cadastrar", WS_CHILD | WS_VISIBLE, 600, 200, 100, 18, hwnd, (HMENU) 2, NULL, NULL);
}
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) {
HWND hwndCadastrar;
switch (wm) {
case WM_CREATE:
addControls(hwnd);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_COMMAND:
if (LOWORD(wp) == 1) {
hwndCadastrar = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
_T("Covid-19 - Cadastrar - Paciente"),
WS_CHILDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hwnd,
NULL);
ShowWindow(hwndCadastrar, SW_SHOW);
SetForegroundWindow(hwndCadastrar);
SetFocus(hwndCadastrar);
Window(hwnd);
MessageBox(0, (LPCWSTR)L"Login Efetuado Com Sucesso", (LPCWSTR)L"Login", 0);
} else if (LOWORD(wp) == 2) {
MessageBox(0, (LPCWSTR)L"Cadastro Efetuado Com Sucesso", (LPCWSTR)L"Cadastrar", 0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, wm, wp, lp);
}
}
The child window failed to create.
You cannot pass a HWND to a HINSTANCE parameter.(argument of type HWND is incompatible with parameter of type HINSTANCE)
You cannot create a top-level child window(ERROR_TLW_WITH_WSCHILD).
CW_USEDEFAULT is valid only for overlapped windows; if CW_USEDEFAULT is specified for a pop-up or child window, the nWidth and nHeight parameter are set to zero.
If you want to see the child window caption, add WS_CAPTION.
Finally, the code looks like this:
hwndCadastrar = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
_T("Covid-19 - Cadastrar - Paciente"),
WS_CAPTION |WS_CHILDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
1000,
1000,
hwnd,
NULL,
GetModuleHandle(NULL),
NULL);
For more information about child windows, see Creating, Enumerating, and Sizing Child Windows

Change text type of buttons in Win32 API [duplicate]

This question already has answers here:
Normal looking button with c++ / win32
(4 answers)
Programming In C + Win API: How To Get Windows 7 Look For Controls?
(3 answers)
Closed 2 years ago.
I'm working on a program that disables Windows Explorer. I did it before in Python, but when I build it in C it is faster to start the program.
I want the buttons to look elegant, like the title text style and font. How do I make the text of the buttons look nice? I hope you can help me.
My code:
#include <windows.h>
#define ID_BTNHI0 0
#define ID_BTNHI1 1
#define ID_BTNHI2 2
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
WNDCLASSEX class_;
int WINAPI WinMain(HINSTANCE hInstanciaAct, HINSTANCE hInstanciaPrev, LPSTR IpCmdLine, int iCmdShow){
ShowWindow(GetConsoleWindow(), SW_HIDE);
HWND hWnd;
MSG msg;
class_.cbSize = sizeof(WNDCLASSEX);
class_.cbWndExtra = 0;
class_.cbClsExtra = 0;
class_.style = CS_HREDRAW|CS_VREDRAW;
class_.lpfnWndProc = WndProc;
class_.hInstance = hInstanciaAct;
class_.hIcon = LoadImage(NULL, "icoff.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
class_.hIconSm = LoadImage(NULL, "icoff.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
class_.hCursor = LoadCursor(NULL, IDC_ARROW);
class_.lpszClassName = "MICLASE";
class_.lpszMenuName = NULL;
class_.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
if(!RegisterClassEx(&class_)){
MessageBox(NULL, "NON", "ERROR", MB_ICONERROR);
return EXIT_FAILURE;
}
hWnd = CreateWindowEx(0, "MICLASE", "Windows Explorer Toggle", WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 340, 140, HWND_DESKTOP, NULL, hInstanciaAct, NULL);
if(hWnd == NULL){
MessageBox(NULL, "NON2", "ERROR", MB_ICONERROR);
return EXIT_FAILURE;
}
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0) > 0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
HWND hBtn0;
HWND hBtn1;
HWND hBtn2;
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg){
case WM_CREATE:{
hBtn0 = CreateWindow("BUTTON", "Disable Windows Explorer", WS_VISIBLE | WS_CHILD | BS_FLAT, 82.5, 24.5, 175, 22.5, hWnd, (HMENU)ID_BTNHI0, GetModuleHandle(NULL), NULL);
//SetFocus(hBtn0);
hBtn1 = CreateWindow("BUTTON", "Enable Windows Explorer", WS_VISIBLE | WS_CHILD | BS_FLAT, 82.5, 24.5, 175, 22.5, hWnd, (HMENU)ID_BTNHI1, GetModuleHandle(NULL), NULL);
ShowWindow(hBtn1, SW_HIDE);
hBtn2 = CreateWindow("BUTTON", "Open Folder", WS_VISIBLE | WS_CHILD | BS_FLAT, 82.5, 48, 175, 22.5, hWnd, (HMENU)ID_BTNHI2, GetModuleHandle(NULL), NULL);
break;
}
case WM_COMMAND:{
switch(LOWORD(wParam)){
case ID_BTNHI0:{
system("TASKKILL /F /IM explorer.exe");
//clase.hIcon = LoadImage(NULL, "icoff.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
//clase.hIconSm = LoadImage(NULL, "icoff.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
ShowWindow(hBtn0, SW_HIDE);
ShowWindow(hBtn1, SW_SHOW);
//SetFocus(hBtn1);
break;
}
case ID_BTNHI1:{
system("start %SystemRoot%\\explorer.exe");
//clase.hIcon = LoadImage(NULL, "icon.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
//clase.hIconSm = LoadImage(NULL, "icon.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
ShowWindow(hBtn1, SW_HIDE);
ShowWindow(hBtn0, SW_SHOW);
//SetFocus(hBtn0);
break;
}
case ID_BTNHI2:{
system("start .");
//SetFocus(hBtn0);
break;
}
}
break;
}
case WM_DESTROY:{
PostQuitMessage(0);
break;
}
default:{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
return 0;
}
You need to get rid of the BS_FLAT window style on the buttons, and also enable ComCtrl32 v6.0 Visual Styles for your program, if you haven't already. Then the buttons will have a modern look.

Button didn't show up when menu value is set and shows odd style when not set

I'd like to set a specific window as the parent of a button, but I'm getting an expected behavior.
When the hMenu value on CreateWindow() is set, the button don't show up:
CreateWindow(L"Button",
L"Click me!",
WS_TABSTOP,
20,
50,
60,
90,
NULL,
(HMENU)1,
NULL, NULL);
But when I remove the hMenu parameter, the button does show up, but in a odd style:
CreateWindow(L"Button",
L"Click me!",
WS_TABSTOP,
20,
50,
60,
90,
NULL,
NULL,
NULL, NULL);
I'm not passing the HWND returned by the CreateWindow() of the main window into hwndParent of the button because they aren't called in that order.
The below code is a reduced version from my real one.
What am I missing?
Full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow) {
MSG msg = {0};
WNDCLASSW wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClassW(&wc);
HWND
hwndMainWindow = CreateWindow(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 350,
NULL, NULL, hInstance, NULL);
HWND hButton = CreateWindow(L"Button",
L"Click me!",
WS_TABSTOP,
20,
50,
60,
90,
NULL,
NULL,
NULL, NULL);
SetParent(hButton, hwndMainWindow);
ShowWindow(hButton, SW_SHOWNORMAL);
UpdateWindow(hwndMainWindow);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
You are not specifying the WS_CHILD style on the button. SetParent() does not set this style for you.
When you set the "parent" of a window that does not have WS_CHILD, you are actually setting its "owner" instead. Owner and Parent are not the same thing. Also see A window can have a parent or an owner but not both.
Your button does not appear in the main window because the button is not a child of the main window.
So, when creating the button, you need to include the WS_CHILD style. You should also include the WS_VISIBLE style instead of using ShowWindow() (unless you want to create the button hidden initially). And you should specify the parent window at the time of creation, instead of using SetParent().
You should also move your button creation into the WM_CREATE handler of your main window's WndProc().
Try this:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow) {
MSG msg = {0};
WNDCLASS wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
HWNDhwndMainWindow = CreateWindow(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 350,
NULL, NULL, hInstance, NULL);
ShowWindow(hwndMainWindow, SW_SHOWNORMAL);
UpdateWindow(hwndMainWindow);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
CreateWindow(L"Button",
L"Click me!",
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
20,
50,
60,
90,
hwnd,
(HMENU)1,
NULL, NULL);
break;
case WM_COMMAND:
if ((LOWORD(wParam) == 1) && (HIWORD(wParam) == BN_CLICKED)) {
MessageBox(hwnd, L"Yea, you clicked me!", L"Window", MB_OK);
return 0;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

How do I make a tab control with children elements?

I'm learning WINAPI, I read there's no children control in the sense a C#'s TabControl control does, so you have to create elements and show/hide by yourself. I read it may be done by drawing a dialog box inside tab page's area so I went to create a borderless dialog box being tab control's child, to make it have effect like C#'s. But I still couldn't make it. My dialog box is floating rather being tab control's child. I don't know to make it inside the tab page, I've tried setting the hWndParent to tab control's HWND and WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT flags in dwExStyle but still is floating over the tab control. Different approaches to solve this are welcome. I'm creating the tab control like this:
void AddTabControl(HWND hwnd)
{
hTab = CreateWindowW(WC_TABCONTROLW, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
0, 30, 250, 250,
hwnd,
(HMENU) 9,
NULL,
NULL);
InsertTabItem(hTab, 10, L"A");
InsertTabItem(hTab, 11, L"B");
}
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text)
{
TCITEMW tci = {0};
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = lstrlenW(text);
if(SendMessage(tabHwnd, TCM_INSERTITEMW, id, (LPARAM) &tci) == -1) {
MessageBox(NULL,
L"couldn't create the new tab page",
L"tab errror",
MB_OK | MB_ICONERROR);
}
}
And the dialog box like this:
void CreateDialogBox(HWND hwnd)
{
CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT, // WS_EX_TOOLWINDOW to hide window from ALT+TAB
L"DialogClass", L"Dialog Box",
WS_VISIBLE | WS_POPUP | WS_SYSMENU,
100, 100, 400, 150,
hTab, NULL, ghInstance, NULL
);
}
the result is:
the expected result (made from C#, just for example, ignore the color differences, I'll fix this later):
here's the full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#define UNICODE
#include <windows.h>
#include <Commctrl.h>
#include <strsafe.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
void CreateDialogBox(HWND);
void RegisterDialogClass(HWND);
void AddTabControl(HWND hwnd);
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text);
HINSTANCE ghInstance;
HWND mainWindow;
HWND hTab;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow) {
MSG msg = {0};
HWND hwnd;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
RegisterClassW(&wc);
hwnd = CreateWindowW(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 350, NULL, NULL, hInstance, NULL);
mainWindow = hwnd;
ghInstance = hInstance;
while( GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
RegisterDialogClass(hwnd);
AddTabControl(hwnd);
CreateDialogBox(hwnd);
break;
case WM_COMMAND:
CreateDialogBox(hwnd);
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg) {
case WM_CREATE:
CreateWindowW(L"button", L"A",
WS_VISIBLE | WS_CHILD ,
50, 50, 80, 25, hwnd, (HMENU) 1, NULL, NULL);
CreateWindowW(L"button", L"B",
WS_VISIBLE | WS_CHILD ,
150, 50, 80, 25, hwnd, (HMENU) 2, NULL, NULL);
CreateWindowW(L"button", L"C",
WS_VISIBLE | WS_CHILD ,
250, 50, 80, 25, hwnd, (HMENU) 3, NULL, NULL);
break;
case WM_COMMAND:
DestroyWindow(hwnd);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
}
return (DefWindowProcW(hwnd, msg, wParam, lParam));
}
void RegisterDialogClass(HWND hwnd)
{
WNDCLASSEXW wc = {0};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.lpfnWndProc = (WNDPROC) DialogProc;
wc.hInstance = ghInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpszClassName = L"DialogClass";
RegisterClassExW(&wc);
}
void CreateDialogBox(HWND hwnd)
{
CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT, // WS_EX_TOOLWINDOW to hide window from ALT+TAB
L"DialogClass", L"Dialog Box",
WS_VISIBLE | WS_POPUP | WS_SYSMENU,
100, 100, 400, 150,
hTab, NULL, ghInstance, NULL
);
}
void AddTabControl(HWND hwnd)
{
hTab = CreateWindowW(WC_TABCONTROLW, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
0, 30, 250, 250,
hwnd,
(HMENU) 9,
NULL,
NULL);
InsertTabItem(hTab, 10, L"A");
InsertTabItem(hTab, 11, L"B");
}
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text)
{
TCITEMW tci = {0};
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = lstrlenW(text);
if(SendMessage(tabHwnd, TCM_INSERTITEMW, id, (LPARAM) &tci) == -1) {
MessageBox(NULL,
L"couldn't create the new tab page",
L"tab errror",
MB_OK | MB_ICONERROR);
}
}
When you created the dialog box control, you lacked the WS_CHILD style and added the WS_POPUP style, which caused the dialog box you generated to float.
You only need to modify it to the WS_CHILD style, and appropriately modify the size of the control to achieve your desired effect.
void CreateDialogBox(HWND hwnd)
{
CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT, // WS_EX_TOOLWINDOW to hide window from ALT+TAB
L"DialogClass", L"Dialog Box",
WS_VISIBLE | WS_SYSMENU | WS_CHILD ,
10, 30, 350, 150,
hTab, NULL, ghInstance, NULL
);
}
void AddTabControl(HWND hwnd)
{
hTab = CreateWindowW(WC_TABCONTROLW, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
10, 30, 400, 250,
hwnd,
(HMENU)9,
NULL,
NULL);
InsertTabItem(hTab, 10, L"A");
InsertTabItem(hTab, 11, L"B");
}
It works like this:

SB_THUMBTRACK is not sent repeatedly

MSDN says the following about SB_THUMBTRACK:
The user is dragging the scroll box. This message is sent repeatedly
until the user releases the mouse button. The HIWORD indicates the
position that the scroll box has been dragged to.
However, I am only getting this message once (when I click on the scroll box).
This is my code:
#include <Windows.h>
HWND hEdit;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_HSCROLL:
if (LOWORD(wParam) == SB_THUMBTRACK)
{
// Display some text
SendMessage(hEdit, WM_CHAR, 'a', 0);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
//--------------------------------------------
// Create Window
HWND hWnd = CreateWindowEx(0, "WinClass", "My Title", WS_OVERLAPPEDWINDOW, 200, 200, 500, 300, NULL, NULL, hInstance, NULL);
// Create horizontal Scrollbar
CreateWindowEx(0, "SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE| SBS_HORZ, 50, 50, 300, 20, hWnd, NULL, hInstance, NULL);
// Create Edit control
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, 10, 10, 250, 21, hWnd, NULL, hInstance, NULL);
// Show Window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//--------------------------------------------
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Because you do not set the scrollbar info, the system could not calculate the track position.
After setting the scrollinfo,
#include "stdafx.h"
#include <Windows.h>
#include <string.h>
#include <stdlib.h>
#include <Commctrl.h>
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "Comctl32.lib")
HWND hEdit;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_HSCROLL:
if (LOWORD(wParam) == SB_THUMBTRACK)
{
int i = 0;
char buf[3];
_itoa_s(HIWORD(wParam), buf, 3, 10);
SetWindowText(hEdit, buf);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
//--------------------------------------------
InitCommonControls();
// Create Window
HWND hWnd = CreateWindowEx(0, "WinClass", "My Title", WS_OVERLAPPEDWINDOW, 200, 200, 500, 300, NULL, NULL, hInstance, NULL);
// Create horizontal Scrollbar
HWND hScroll = CreateWindowEx(0, "SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE | SBS_HORZ, 50, 50, 300, 20, hWnd, NULL, hInstance, NULL);
// Create Edit control
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, 10, 10, 250, 21, hWnd, NULL, hInstance, NULL);
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = 100;
si.nPage = 10;
si.nPos = 0;
si.nTrackPos = 0;
SetScrollInfo(hScroll, SB_CTL, &si, true);
// Show Window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//--------------------------------------------
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
everything should work well.

Resources