Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
670 views
in Technique[技术] by (71.8m points)

winapi - Add Controls To Specific Tab Page in TabControl in C++ Win32

I want to add some controls to the tab page in tabcontrol but it seems that it will be added to all pages and there is not tab page in tabcontrol by default.

I have read these links below but they did not help me and in some parts of them, confused me.

How to add controls to a Tab control

http://www.cplusplus.com/forum/windows/37161/

https://msdn.microsoft.com/en-us/library/bb760551.aspx

https://msdn.microsoft.com/en-us/library/hh298366.aspx

https://msdn.microsoft.com/en-us/library/ms645398.aspx

Here is my code :

[Code]:

#define ID_LBL 500              
#define ID_BTN 501              
#define ID_TBC 502              

HWND hWnd;

void InserTabItem(HWND handle, LPWSTR text, int id)
{
TCITEM tci = { 0 };
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = wcslen(text);
SendMessage(handle, TCM_INSERTITEM, id, LPARAM(&tci));
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CREATE:
{
    HWND button_handle = 0;
    HWND label_handle = 0;
    HWND tab_handle = 0;
    tab_handle = CreateWindowEx(WS_EX_CONTROLPARENT, WC_TABCONTROL, 0, WS_VISIBLE | WS_CHILD, 10, 10, 200, 150, hWnd, HMENU(ID_TBC), 0, 0);
    InserTabItem(tab_handle, L"page1", 0);
    InserTabItem(tab_handle, L"page2", 1);
    button_handle = CreateWindowEx(0, WC_BUTTON, L"test-button-page2", WS_VISIBLE | WS_CHILD, 10, 50, 150, 30, tab_handle, HMENU(ID_BTN), 0, 0);
    label_handle = CreateWindowEx(0, WC_STATIC, L"test-label-page1", WS_VISIBLE | WS_CHILD, 10, 100, 150, 30, tab_handle, HMENU(ID_LBL), 0, 0);
}
break;
case WM_CLOSE:
    DestroyWindow(hWnd);
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    break;
default:
    return DefWindowProc(hWnd, Msg, wParam, lParam);
    break;
}

return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreviewInstance, LPSTR lpcmdline, int ncmdshow)
{
WNDCLASSEX wndexcls;
wndexcls.lpszClassName = L"win";
wndexcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndexcls.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndexcls.hCursor = LoadCursor(NULL, IDC_ARROW);
wndexcls.hbrBackground = (HBRUSH)(COLOR_3DSHADOW + 1);
wndexcls.lpszMenuName = NULL;
wndexcls.style = NULL;
wndexcls.hInstance = hInstance;
wndexcls.cbSize = sizeof(WNDCLASSEX);
wndexcls.cbClsExtra = 0;
wndexcls.cbWndExtra = 0;
wndexcls.lpfnWndProc = WndProc;
RegisterClassEx(&wndexcls);

hWnd = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT, L"win", L"TestApp", WS_OVERLAPPEDWINDOW, 100, 100, 640, 380, 0, 0, hInstance, 0);
ShowWindow(hWnd, ncmdshow);
UpdateWindow(hWnd);



MSG wnd_msg;
while (GetMessage(&wnd_msg, NULL, 0, 0)>0)
{
    TranslateMessage(&wnd_msg);
    DispatchMessage(&wnd_msg);
}
return (int)wnd_msg.wParam;

}

I am looking for a safe and proper implementation.

Thanks for any help

========================================================

[Update]:

Thanks for comments but no answer in detail :(

Although that is not the implementation I am looking for(NotDialogBased), But from the forth link I mentioned :

How to Create a Tabbed Dialog Box :

https://msdn.microsoft.com/en-us/library/hh298366.aspx

Here is my code of that page :

[resource.h]:

#define IDD_Page1                       101
#define IDD_Page2                       102
#define IDD_Page3                       103
#define IDD_Main_Dialog                 104
#define IDC_BTN_Page1                   1001
#define IDC_BTN2_Page1                  1002
#define IDC_BTN_Page2                   1013
#define IDC_BTN_Page3                   1014

[Resource.rc]:

#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

 //////////////////////////////////////////////////
 //
 // Dialog
  //

 IDD_Page1 DIALOGEX 0, 0, 313, 178
 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
 PUSHBUTTON      "Button2-Page1",IDC_BTN2_Page1,129,107,67,22
 PUSHBUTTON      "Button-Page1",IDC_BTN_Page1,127,77,67,22
 END

 IDD_Page2 DIALOGEX 0, 0, 309, 177
 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
 PUSHBUTTON      "Button-Page2",IDC_BTN_Page2,120,77,60,18
 END

 IDD_Page3 DIALOGEX 0, 0, 309, 177
 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
 PUSHBUTTON      "Button-Page3",IDC_BTN_Page3,120,73,64,25
 END

 IDD_Main_Dialog DIALOGEX 0, 0, 309, 177
 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
 END


////////////////////////////////////////////
//
// DESIGNINFO
 //

 #ifdef APSTUDIO_INVOKED
 GUIDELINES DESIGNINFO
 BEGIN
 IDD_Page1, DIALOG
 BEGIN
    LEFTMARGIN, 7
    RIGHTMARGIN, 306
    TOPMARGIN, 7
    BOTTOMMARGIN, 171
END

IDD_Page2, DIALOG
BEGIN
    LEFTMARGIN, 7
    RIGHTMARGIN, 302
    TOPMARGIN, 7
    BOTTOMMARGIN, 170
END

IDD_Page3, DIALOG
BEGIN
    LEFTMARGIN, 7
    RIGHTMARGIN, 302
    TOPMARGIN, 7
    BOTTOMMARGIN, 170
END

IDD_Main_Dialog, DIALOG
BEGIN
    LEFTMARGIN, 7
    RIGHTMARGIN, 302
    TOPMARGIN, 7
    BOTTOMMARGIN, 170
END
END
#endif    // APSTUDIO_INVOKED

#endif    

[Main.cpp]:

#include <windows.h>
#include <CommCtrl.h>
#include "resource.h"
#pragma comment(lib, "ComCtl32.lib")
#define C_PAGES 3 

INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

HWND Win_Handle;
HWND Dailog_Handle;
HINSTANCE hInstance_Win_Global;

typedef struct {
WORD      dlgVer;
WORD      signature;
DWORD     helpID;
DWORD     exStyle;
DWORD     style;
WORD      cDlgItems;
short     x;
short     y;
short     cx;
short     cy;
WORD      pointsize;
WORD      weight;
BYTE      italic;
BYTE      charset;
} DLGTEMPLATEEX;

typedef struct tag_dlghdr {
HWND hwndTab;       // tab control 
HWND hwndDisplay;   // current child dialog box 
RECT rcDisplay;     // display rectangle for the tab control 
DLGTEMPLATEEX *apRes[C_PAGES];
} DLGHDR;

void InserTabItem(HWND handle, LPWSTR text, int id)
{
TCITEM tci = { 0 };
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = wcslen(text);
SendMessage(handle, TCM_INSERTITEM, id, LPARAM(&tci));
}

DLGTEMPLATEEX* DoLockDlgRes(LPCTSTR lpszResName)
{
HRSRC hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);
HGLOBAL hglb = LoadResource(hInstance_Win_Global, hrsrc);
return (DLGTEMPLATEEX *)LockResource(hglb);
}

VOID WINAPI OnChildDialogInit(HWND hwndDlg)
{
HWND hwndParent = GetParent(hwndDlg);
DLGHDR *pHdr = (DLGHDR *)GetWindowLong(
    hwndParent, GWL_USERDATA);
SetWindowPos(hwndDlg, NULL, pHdr->rcDisplay.left,
    pHdr->rcDisplay.top,//-2,
    (pHdr->rcDisplay.right - pHdr->rcDisplay.left),
    (pHdr->rcDisplay.bottom - pHdr->rcDisplay.top),
    SWP_SHOWWINDOW);

return;
} 
VOID OnSelChanged(HWND hwndDlg)
{
DLGHDR *pHdr = (DLGHDR *)GetWindowLong(hwndDlg, GWL_USERDATA);
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);
if (pHdr->hwndDisplay != NULL)
    DestroyWindow(pHdr->hwndDisplay);
pHdr->hwndDisplay = CreateDialogIndirect(hInstance_Win_Global,
    (DLGTEMPLATE *)pHdr->apRes[iSel], hwndDlg,DialogProc);
}
HRESULT OnTabbedDialogInit(HWND hwndDlg)
{
INITCOMMONCONTROLSEX iccex;
DWORD dwDlgBase = GetDialogBaseUnits();
int cxMargin = LOWORD(dwDlgBase) / 4;
int cyMargin = HIWORD(dwDlgBase) / 8;

TCITEM tie;
RECT rcTab;
HWND hwndButton;
RECT rcButton;
int i;

iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&iccex);

DLGHDR *pHdr = (DLGHDR *)LocalAlloc(LPTR, sizeof(DLGHDR));
SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)pHdr);

pHdr->hwndTab = CreateWindow(
    WC_TABCONTROL, L"",
    WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
    0, 0, 300, 200,
    hwndDlg, NULL, hInstance_Win_Global, NULL
    );
if (pHdr->hwndTab == NULL)
{
    return HRESULT_FROM_WIN32(GetLastError());
}

tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = L"First";
TabCtrl_InsertItem(pHdr->hwndTab, 0, &tie);
tie.pszText = L"Second";
TabCtrl_InsertItem(pHdr->hwndTab, 1, &tie);
tie.pszText = L"Third";
TabCtrl_InsertItem(pHdr->hwndTab, 2, &tie);

pHdr->apRes[0] = DoLockDlgRes(MAKEINTRESOURCE(IDD_Page1));
pHdr->apRes[1] = DoLockDlgRes(MAKEINTRESOURCE(IDD_Page2));
pHdr->apRes[2] = DoLockDlgRes(MAKEINTRESOURCE(IDD_Page3));

SetRectEmpty(&rcTab);
for (i = 0; i < C_PAGES; i++)
{
    if (pHdr->apRes[i]->cx > rcTab.right)
        rcTab.right = pHdr->apRes[i]->cx;
    if (pHdr->apRes[i]->cy > rcTab.bottom)
        rcTab.bottom = pHdr->apRes[i]->cy;
}

MapDialogRect(hwndDlg, &rcTab);

TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab);
OffsetRect(&rcTab, cxMargin - rcTab.left, cyMargin - rcTab.top);

CopyRect(&pHdr->rcDisplay, &rcTab);
TabCtrl_AdjustRect(pHdr->hwndTab, FALSE, &pHdr->rcDisplay);

SetWindowPos(pHdr->hwndTab, NULL, rcTab.left, rcTab.top,
    rcTab.right - rcTab.left, rcTab.bottom - rcTab.top,
    SWP_NOZORDER);

hwndButton = GetDlgItem(hwndDlg, IDC_BTN_Page1);
SetWindowPos(hwndButton, NULL,
    rcTab.left, rcTab.bottom + cyMargin, 0, 0,
    SWP_NOSIZE | SWP_NOZORDER);

GetWindowRect(hwndButton, &rcButton);
rcButton.right -= rcButton.left;
rcButton.bottom -= rcButton.top;

hwndButton = GetDlgItem(hwndDlg, IDC_BTN2_Page1);
SetWindowPos(hwndButton, NULL,
    rcTab.left + rcButton.right + cxMargin,
    rcTab.bottom + cyMargin, 0, 0,
    SWP_NOSIZE | SWP_NOZORDER);

SetWindowPos(hwndDlg, NULL, 0, 0,
    rcTab.right + cyMargin + (2 * GetSystemMetrics(SM_CXDLGFRAME)),
    rcTab.bottom + rcButton.bottom + (2 * cyMargin)
    + (2 * GetSystemMetrics(SM_CYDLGFRAME))
    + GetSystemMetrics(SM_CYCAPTION),
    SWP_NOMOVE | SWP_NOZORDER);

OnSelChanged(hwndDlg);

return S_OK;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CREATE:
{
    Dailog_Handle = CreateDialogParam(hInstance_Win_Global, MAKEINTRESOURCE(IDD_Main_Dialog), hWnd, DialogProc, 0);
    ShowWindow(Dailog_Handle, SW_SHOWDEFAULT);
    UpdateWindow(Dailog_Handle);
    SetWindowPos(Dailog_Handle, 0, 10, 10, 500, 300, SWP_NOZORDER);

}
break;
case WM_CLOSE:
    DestroyWindow(hWnd);
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    break;
default:
    return DefWindowProc(hWnd, Msg, wParam, lParam);
    break;
}

return 0;
}
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_INITDIALOG:
{

    OnTabbedDialogInit(hWnd);
    OnChildDialogInit(hWnd);

    return (INT_PTR)TRUE;
}
    break;
case WM_NOTIFY:
{
    switch (((LPNMHDR)lParam)->code)
    {
    case TCN_SELCHANGE:
    {
        OnSelChanged(hWnd);
    }
    break;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

One problem is here:

pHdr->hwndDisplay = CreateDialogIndirect(hInstance_Win_Global, 
    (DLGTEMPLATE*)pHdr->apRes[iSel], hwndDlg, DialogProc);

You are reusing the same dialog procedure for both main dialog and child dialogs. Main dialog creates child dialogs, child dialogs use the same procedure to create child dialogs... Also there are no error checks.

Beyond that, this code is too complicated. Just use a dialog box for main window. Create a new dialog IDD_DIALOG1 and drag/drop a tab control in it. Assign IDC_TAB1 for tab control ID. Try starting with this code instead:

#include <Windows.h>
#include <CommCtrl.h>
#include "Resource.h"

#pragma comment(lib,"comctl32.lib")
#pragma comment(linker,""/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"")

HINSTANCE g_hinst;

struct TData {
    HWND page1, page2, page3;
    HWND tab;
} data;

BOOL CALLBACK DialogPage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch(msg) {
    case WM_COMMAND:
        switch (wp) {
            //...
        }
    }
    return FALSE;
}

void OnSelChange() {
    int sel = TabCtrl_GetCurSel(data.tab);
    ShowWindow(data.page1, (sel == 0) ? SW_SHOW : SW_HIDE);
    ShowWindow(data.page2, (sel == 1) ? SW_SHOW : SW_HIDE);
}

BOOL CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg) {
    case WM_INITDIALOG: {
        data.page1 = CreateDialog(g_hinst, MAKEINTRESOURCE(IDD_Page1), hwnd, DialogPage);
        data.page2 = CreateDialog(g_hinst, MAKEINTRESOURCE(IDD_Page2), hwnd, DialogPage);

        data.tab = GetDlgItem(hwnd, IDC_TAB1);
        if (data.tab)
        {
            TCITEM tci = { 0 };
            tci.mask = TCIF_TEXT;
            tci.pszText = L"Page1";
            TabCtrl_InsertItem(data.tab, 0, &tci);
            tci.pszText = L"Page2";
            TabCtrl_InsertItem(data.tab, 1, &tci);

            RECT rc;//find tab control's rectangle
            GetWindowRect(data.tab, &rc);
            POINT offset = { 0 };
            ScreenToClient(hwnd, &offset);
            OffsetRect(&rc, offset.x, offset.y); //convert to client coordinates
            rc.top += 50;
            SetWindowPos(data.page1, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_HIDEWINDOW);
            SetWindowPos(data.page2, 0, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_HIDEWINDOW);

            OnSelChange();
        }

        break;
    }

    case WM_NOTIFY: {
        switch (((LPNMHDR)lp)->code) {
        case TCN_SELCHANGE:
            OnSelChange();
            break;
        }
    }
    break;

    case WM_COMMAND:
        switch (wp) {
        case IDOK: EndDialog(hwnd, wp);  break;
        case IDCANCEL:  EndDialog(hwnd, wp);  break;
        }
    }

    return FALSE;
}

int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE, LPWSTR, int)
{
    g_hinst = hinst;
    DialogBox(hinst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc);
    return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...