Controlling Inner CTabControl Items with TAB and Arrow Keys

134 views Asked by At

I have an issue Controlling CTabControl Inner tab items with TAB and Arrow keys.

here is my code and a few screenshots:

OnInitDialog() method of the main dialog window:

BOOL PressetsDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // AUTO GENERATED MFC DIALOGUE CODE HERE
    ...
    // ..

    // TODO: Add extra initialization here
    CTabCtrl* pTabCtrl = (CTabCtrl*)GetDlgItem(IDC_TAB1);
    m_one.Create(IDD_TAB_ONE, pTabCtrl);

    CTabCtrl* pTabCtrl2 = (CTabCtrl*)GetDlgItem(IDC_TAB1);
    m_two.Create(IDD_TAB_TWO, pTabCtrl2);

    TCITEM item1, item2, item3;
    item1.mask = TCIF_TEXT | TCIF_PARAM;
    item1.lParam = (LPARAM)&m_one;
    item1.pszText = L"Normal Presets";
    pTabCtrl->InsertItem(0, &item1);

    item2.mask = TCIF_TEXT | TCIF_PARAM;
    item2.lParam = (LPARAM)&m_two;
    item2.pszText = L"Movement Presets";
    pTabCtrl2->InsertItem(1, &item2);

    CRect rcItem;
    pTabCtrl->GetItemRect(0, &rcItem);
    m_one.SetWindowPos(NULL, rcItem.left, rcItem.bottom + 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

    CRect rcItem2;
    pTabCtrl2->GetItemRect(0, &rcItem2);
    m_two.SetWindowPos(NULL, rcItem2.left, rcItem2.bottom + 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

    m_one.ShowWindow(SW_SHOW);
    m_two.ShowWindow(SW_HIDE);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

and the OnTcnSelchangeTab method:

void PressetsDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
    // TODO: Add your control notification handler code here
    
    int nSelect = m_Tab.GetCurSel();

    if (nSelect == 0)
    {
        m_one.ShowWindow(SW_SHOW);
        m_two.ShowWindow(SW_HIDE);
    }
    else if (nSelect == 1)
    {
        m_two.ShowWindow(SW_SHOW);
        m_one.ShowWindow(SW_HIDE);
    }
    else
    {
        m_one.ShowWindow(SW_SHOW);
        m_two.ShowWindow(SW_HIDE);
    }
    *pResult = 0;
}

[to see the tab design click here](https://i.stack.imgur.com/Tt8c1.jpg)

I've set the tab order with Ctrl + D for each dialogue resource and set Tabstop property to either True or False and still nothing happens.

At first I thought that this feature is supposed to be supported automatically but it seems that it's not.

the dialogue window moves between tabs and buttons that placed on it but as soon as I try to move to "inner Items" of each tab, it doesn't reach them. I suspect the reason is probably that each tab is a separate window and that's probably the reason that the inner items are unreachable..

1

There are 1 answers

0
Alex On BEST ANSWER

I've made a few changes and now Moving with TAB and arrow keys functions properly.

first of all I set the Control Property of both child dialogs to True. You go to Resource View >> (Solution name) >> (project name) >> IDD + (the id you gave to the dialog) doble click on it >> Properties >> Control.

Essentially what it did is to add the flag WS_CONTROL as mentioned here early to each of the Child windows so that they could be accessed from the main dialog window that contains them.

Of course that alone didn't do much because I also had a few bugs in the code, after days of searching for it I found an example online which helped me solve the bugs.

Then I've changed my code to this: and it started working:

   // first we create two modeless dialogs and embed them as child windows
   // of CTabControlTutorialDlg. 
   // Have a look using Spy++ to see the layout of the controls as they
   // appear to windows
    m_one.Create(IDD_TAB_ONE, this);
    m_two.Create(IDD_TAB_TWO, this);

    // next we get the captions of the dialogs and use these as the caption
    // for the tab window. Of course we could just load a string from the 
    // resources or hard code a string for the text of the tab.
    
    TCITEM item1, item2;
    item1.mask = TCIF_TEXT | TCIF_PARAM;
    item1.lParam = (LPARAM)&m_one;
    item1.pszText = L"Normal Presets";
    m_Tab.InsertItem(0, &item1);

    item2.mask = TCIF_TEXT | TCIF_PARAM;
    item2.lParam = (LPARAM)&m_two;
    item2.pszText = L"Custom Presets";
    m_Tab.InsertItem(1, &item2);

    // finally we set the tab order correctly for the so that we can tab through the dialogs and into
    // the cancel and ok buttons. If we don;t do this then the tab order is tab control, ok button, cancel
    // button embedded dialogs.
    CRect rcItem;
    m_Tab.GetItemRect(0, &rcItem);
    m_one.SetWindowPos(NULL, rcItem.left, rcItem.bottom + 5, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER);

    CRect rcItem2;
    m_Tab.GetItemRect(0, &rcItem2);
    m_two.SetWindowPos(NULL, rcItem2.left, rcItem2.bottom + 5, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER);

    m_one.ShowWindow(SW_SHOW);

I found reference in this site:https://www.codeproject.com/Articles/4408/Creating-embedded-dialogs-in-MFC but in order to get their code example you need to register to the website.

It works!