The "child " controls in a Tab control must not be child of the Tab control, but of the main window
I did a few changes and it seems to work correctly =>
#include <Windows.h>
#include <commctrl.h>
#include <windowsx.h>
#include <process.h>
#include <iostream>
#include <Uxtheme.h>
struct _WINDOW_HANDLES
{
HWND MainWindow;
HWND ListViewWindow;
HWND SplitterWindow;
HWND TabMainWindow;
HWND TabChildWindow;
} wh;
HINSTANCE ghInst;
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK SplitterProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK TabMainProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK TabChildWindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static WNDPROC SplitterWndProc;
static WNDPROC TabMainWndProc;
static WNDPROC TabChildWndProc;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow)
{
WNDCLASSW wc;
memset(&wc, 0, sizeof(WNDCLASSW));
wc.hbrBackground = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"MainWindowClass";
wc.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&wc))
{
return -1;
}
//wh.MainWindow = CreateWindowExW(WS_EX_COMPOSITED, L"MainWindowClass", L"GUI", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1300, 700, NULL, NULL, hInst, NULL);
wh.MainWindow = CreateWindowExW(0, L"MainWindowClass", L"GUI", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1300, 700, NULL, NULL, hInst, NULL);
ShowWindow(wh.MainWindow, ncmdshow);
MSG msg;
memset(&msg, 0, sizeof(MSG));
while (GetMessageW((&msg), NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
VOID InitializeComponent(HWND hWnd)
{
RECT rcMain;
GetClientRect(hWnd, &rcMain);
wh.ListViewWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, rcMain.right, 265, hWnd, (HMENU)0, ghInst, NULL);
ListView_SetExtendedListViewStyle(wh.ListViewWindow, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
SendMessage(wh.ListViewWindow, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);
LVCOLUMN lvc;
memset(&lvc, 0, sizeof(LVCOLUMN));
lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.iSubItem = 0;
lvc.cx = 125;
lvc.pszText = (LPWSTR)L"Column 1";
ListView_InsertColumn(wh.ListViewWindow, 0, &lvc);
lvc.iSubItem = 1;
lvc.cx = 125;
lvc.pszText = (LPWSTR)L"Column 2";
ListView_InsertColumn(wh.ListViewWindow, 1, &lvc);
LVITEM lvi;
memset(&lvi, 0, sizeof(LVITEM));
lvi.mask = LVIF_TEXT;
lvi.iItem = 0;
lvi.iSubItem = 0;
lvi.iImage = 0;
lvi.pszText = (LPWSTR)L"Item 1";
ListView_InsertItem(wh.ListViewWindow, &lvi);
ListView_SetItemText(wh.ListViewWindow, 0, 1, (LPWSTR)L"Item 2");
wh.SplitterWindow = CreateWindowEx(NULL, WC_STATIC, L"", WS_CHILD | WS_BORDER | WS_VISIBLE | SS_NOTIFY | SS_CENTER, 0, 265, rcMain.right, 17, hWnd, NULL, ghInst, NULL);
SplitterWndProc = (WNDPROC)SetWindowLongPtr(wh.SplitterWindow, GWLP_WNDPROC, (LONG_PTR)SplitterProcedure);
LOGFONT lf;
GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
HFONT GeneralFont = CreateFont(
19, 0,
lf.lfEscapement, lf.lfOrientation, lf.lfWeight,
lf.lfItalic, lf.lfUnderline, lf.lfStrikeOut,
lf.lfCharSet, lf.lfOutPrecision, lf.lfClipPrecision,
lf.lfQuality, lf.lfPitchAndFamily, NULL);
wh.TabMainWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TABCONTROL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, rcMain.left, 283, rcMain.right, 378, hWnd, NULL, ghInst, NULL);
//TabMainWndProc = (WNDPROC)SetWindowLongPtr(wh.TabMainWindow, GWLP_WNDPROC, (LONG_PTR)TabMainProcedure);
SendMessage(wh.TabMainWindow, WM_SETFONT, (WPARAM)GeneralFont, TRUE);
TCITEM tie;
tie.mask = TCIF_TEXT;
tie.iImage = 0;
tie.pszText = (LPWSTR)L"Tab";
TabCtrl_InsertItem(wh.TabMainWindow, 0, &tie);
//wh.TabChildWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, L"", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, rcMain.left, 25, rcMain.right, 348, wh.TabMainWindow, NULL, ghInst, NULL);
wh.TabChildWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, L"", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, rcMain.left, 25, rcMain.right, 348, hWnd, NULL, ghInst, NULL);
//TabChildWndProc = (WNDPROC)SetWindowLongPtr(wh.TabChildWindow, GWLP_WNDPROC, (LONG_PTR)TabChildWindowProcedure);
SendMessage(wh.TabChildWindow, WM_SETFONT, (WPARAM)GeneralFont, TRUE);
}
LRESULT CALLBACK SplitterProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bSplitterMoving;
RECT rcMain;
GetClientRect(wh.MainWindow, &rcMain);
switch (message)
{
case WM_SETCURSOR:
{
SetCursor(LoadCursor(NULL, IDC_SIZENS));
SetWindowLongPtr(hWnd, DWLP_MSGRESULT, TRUE);
return TRUE;
}
case WM_LBUTTONDOWN:
{
bSplitterMoving = TRUE;
SetCapture(wh.SplitterWindow);
return 0;
}
case WM_LBUTTONUP:
{
ReleaseCapture();
bSplitterMoving = FALSE;
return 0;
}
case WM_MOUSEMOVE:
{
if (bSplitterMoving)
{
POINT pt{ GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam) };
ClientToScreen(wh.SplitterWindow, &pt);
ScreenToClient(wh.MainWindow, &pt);
auto newSplitterPos = pt.y;
if (newSplitterPos <= 105 || newSplitterPos >= 265)
{
return 0;
}
else
{
HDWP hdwp = BeginDeferWindowPos(4);
DeferWindowPos(hdwp, wh.ListViewWindow, NULL, rcMain.left, rcMain.left, rcMain.right, newSplitterPos, NULL);
DeferWindowPos(hdwp, wh.SplitterWindow, NULL, rcMain.left, newSplitterPos, rcMain.right, 17, NULL);
DeferWindowPos(hdwp, wh.TabMainWindow, NULL, rcMain.left, newSplitterPos + 18, rcMain.right, rcMain.bottom - (newSplitterPos + 18), NULL);
RECT rcTab;
SetRect(&rcTab, rcMain.left, newSplitterPos + 18, rcMain.right, rcMain.bottom - rcMain.top);
TabCtrl_AdjustRect(wh.TabMainWindow, FALSE, &rcTab);
DeferWindowPos(hdwp,
wh.TabChildWindow, HWND_TOP, rcTab.left, rcTab.top,
rcTab.right - rcTab.left, rcTab.bottom - rcTab.top, 0
);
EndDeferWindowPos(hdwp);
//MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (newSplitterPos + 48), TRUE);
//UpdateWindow(wh.ListViewWindow);
// UpdateWindow(wh.SplitterWindow);
// UpdateWindow(wh.TabMainWindow);
}
return 0;
}
}
}
return CallWindowProc(SplitterWndProc, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK TabMainProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
PAINTSTRUCT ps;
RECT rc;
HDC hdc, hdcMem;
HBITMAP hbmMem, hbmOld;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
hdcMem = CreateCompatibleDC(hdc);
hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
hbmOld = ((HBITMAP)SelectObject(hdcMem, hbmMem));
FillRect(hdcMem, &rc, (HBRUSH)GetSysColorBrush(COLOR_3DFACE));
CallWindowProc(TabMainWndProc, hWnd, message, ((WPARAM)hdcMem), lParam);
BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmOld);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
return 0;
}
case WM_ERASEBKGND:
{
return (LRESULT)1;
}
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetBkColor(hdcStatic, RGB(0, 0, 0));
return (LRESULT)GetStockObject(BLACK_BRUSH);
}
}
return CallWindowProc(TabMainWndProc, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK TabChildWindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
PAINTSTRUCT ps;
RECT rc;
HDC hdc, hdcMem;
HBITMAP hbmMem, hbmOld;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
hdcMem = CreateCompatibleDC(hdc);
hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
hbmOld = ((HBITMAP)SelectObject(hdcMem, hbmMem));
FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
CallWindowProc(TabChildWndProc, hWnd, message, ((WPARAM)hdcMem), lParam);
BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmOld);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
return 0;
}
case WM_ERASEBKGND:
{
return (LRESULT)1;
}
}
return CallWindowProc(TabChildWndProc, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
int newSplitterPos = 0;
LPMINMAXINFO lpMMI = (LPMINMAXINFO)lp;
RECT rcMain, rcListView;
GetClientRect(hWnd, &rcMain);
GetClientRect(wh.ListViewWindow, &rcListView);
HMENU hMenu;
switch (msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_CREATE:
{
InitializeComponent(hWnd);
return 0;
}
//case WM_ERASEBKGND:
//{
// HDC hdc = (HDC)wp;
// RECT rect;
// GetClientRect(hWnd, &rect);
// FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
// return 1;
//}
case WM_ERASEBKGND:
{
return 1;
}
case WM_GETMINMAXINFO:
{
lpMMI->ptMinTrackSize.x = 1300;
lpMMI->ptMinTrackSize.y = 700;
break;
}
// For Read-Only Edit control
case WM_CTLCOLORSTATIC:
{
if (lp == (LPARAM)wh.TabChildWindow)
{
HDC hdcStatic = (HDC)wp;
SetBkColor(hdcStatic, RGB(0, 0, 0));
return (LRESULT)GetStockObject(BLACK_BRUSH);
}
}
break;
case WM_SIZE:
{
POINT pt{ GET_X_LPARAM(lp),GET_Y_LPARAM(lp) };
ClientToScreen(wh.SplitterWindow, &pt);
ScreenToClient(wh.MainWindow, &pt);
newSplitterPos = pt.y;
HDWP hdwp = BeginDeferWindowPos(4);
DeferWindowPos(hdwp, wh.ListViewWindow, NULL, rcMain.left, rcMain.left, rcMain.right, (newSplitterPos - rcMain.bottom) - 1, SWP_NOMOVE);
DeferWindowPos(hdwp, wh.SplitterWindow, NULL, rcMain.left, (newSplitterPos - rcMain.bottom) - 1, rcMain.right, 17, SWP_NOMOVE);
DeferWindowPos(hdwp, wh.TabMainWindow, NULL, rcMain.left, (newSplitterPos - rcMain.bottom) + 17, rcMain.right, rcMain.bottom - (rcListView.bottom + 22), SWP_NOMOVE);
RECT rcTab;
SetRect(&rcTab, rcMain.left, (newSplitterPos - rcMain.bottom) + 17, rcMain.right, rcMain.bottom - rcMain.top);
TabCtrl_AdjustRect(wh.TabMainWindow, FALSE, &rcTab);
DeferWindowPos(hdwp,
wh.TabChildWindow, HWND_TOP, rcTab.left, rcTab.top,
rcTab.right - rcTab.left, rcTab.bottom - rcTab.top, 0
);
EndDeferWindowPos(hdwp);
//MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (rcListView.bottom + 52), TRUE);
ListView_SetColumnWidth(wh.ListViewWindow, 1, LVSCW_AUTOSIZE_USEHEADER);
SetWindowText(wh.SplitterWindow, L"...");
return 0;
}
}
return DefWindowProcW(hWnd, msg, wp, lp);
}