How to Expand/Collapse TreeCtrl nodes by using Enter Key?

2 01 2009


You can see Tree Control, almost in every heavy windows applications. They are very convineant  method for organize things in hierarchy. But by default Tree control doesn’t support expand/collapse of its tree nodes by Enter key. Is there any way to do that?

expandcollapsetreectrl
Picture Courtesy – hawaiibonsai


Yes, you can! All you want to do is – Override PreTranslateMessage() in your dialog and handle all WM_KEYDOWN messages for your tree control. If, the key is VK_RETURN, i.e. enter key, then check whether the current selected node in TreeCtrl is expanded or collapsed and modify the key stroke as WM_ADD key or WM_SUBSTRACT key accordingly. The idea is, if you press +, then tree node expands and for – key, the tree node collapse – which is the default behavior of tree control. Well, have a look at the code snippet.

BOOL CRabbitDlg::PreTranslateMessage(MSG* pMsg)
{
    // Check whether its a keypress.
    if( pMsg->message == WM_KEYDOWN )
    {
        // Check whether its for our tree control.
        UINT CtrlId = ::GetDlgCtrlID( pMsg->hwnd );
        if( CtrlId == IDC_TREECTRL )
        {
            // Check whether its enter key.
            if( pMsg->wParam == VK_RETURN)
            {
                // Check whether the currently selected item is
                HTREEITEM CurrentItem = m_TreeCtrl.GetSelectedItem();
                if( m_TreeCtrl.GetItemState( CurrentItem, TVIS_EXPANDED )
                        & TVIS_EXPANDED )
                {
                    // Current Item is Expanded.
                    // So send - Key code to collapse it.
                    pMsg->wParam = VK_SUBTRACT;
                }
                else
                {
                    // Current Item is Collapsed.
                    // So send + Key code to Expand it.
                    pMsg->wParam = VK_ADD;
                }
            }
        }
    }

    return CDialog::PreTranslateMessage(pMsg);
}


If you want the expand entire child nodes under a perticular node, then press * key. I used to use this techniqe to report performance bugs. 😉


Targeted Audience – Intermediate.





How to iterate child controls in your Dialog?

23 05 2008


Assume you’ve a dialog with hundreds of child controls and you want to enable and disable them. Its not practical to get each control by control and disable them. Here iterating child controls comes to your help. Instead of getting control by control you can iterate all child controls of your dialog.


You can iterate the child windows by two methods –

1. Enumerate Child Windows
For enumeration you’ve to call the function – EnumChildWindows() by passing a callback function pointer. For each child window, the callback function will be called by passing child windows handle as parameter. See the sample code snippet.

// Enumerate Child Windows
EnumChildWindows( GetSafeHwnd(), EnumChildProc, 0 );
...

// For each child window, this callback will be called.
BOOL CALLBACK EnumChildProc( HWND hwnd, LPARAM lParam )
{
    // If you need hwnd, you can use it.
    // If you need the Control ID of child window then,
    UINT CtrlID = GetDlgCtrlID( hwnd );
    // Use the Control ID.

    return TRUE;
}

2. Get First and Next child window
If you don’t prefer a callback kind of child window iteration, then you can use – GetWindow() function. For getting the first window, you’ve to call the GetWindow() by passing GW_HWNDFIRST. For next window you should pass – GW_HWNDNEXT. You can also move backwards by using – GW_HWNDPREV. See the sample code snippet.

// Get the first child window. Use it.
HWND hwnd = ::GetWindow( GetSafeHwnd(),
                         GW_CHILD | GW_HWNDFIRST );

while( hwnd )
{
    // Get the next window. Use it.
    hwnd = ::GetWindow( hwnd, GW_HWNDNEXT );
}


While iterating in either methods you’ll get the child window handle. If you need the Ctrl ID, just call GetDlgCtrlID().


Targeted Audience – Beginners.