Создание TreeView с узлами и флажками

Я создал TreeView так:

TreeView=CreateWindowEx(0, WC_TREEVIEW, TEXT("Tree View"), WS_VISIBLE | WS_CHILD, 0, 0, 200, 500, hwnd, (HMENU)ID_TREE_VIEW, GetModuleHandle(NULL), NULL);

Теперь я добавил один элемент, как показано на этом сайте.

Все хорошо, но после нескольких часов поисков я все еще не нашел ответа на эти вопросы:

  1. Как добавить подпункты (узлы)?

  2. Как добавить флажок для каждого элемента (как определить, установлен ли флажок)?

1 ответ

Решение

РЕДАКТИРОВАТЬ № 4:

В ответ на запрос OPs я добавил пример, который удаляет флажок из родительского узла.

Проблема в том, что поле контроля все еще появляется, когда пользователь выбирает узел и нажимает пробел.

Этот вопрос решает эту проблему.

РЕДАКТИРОВАТЬ № 3:

Я добавил код, который создает узел, который уже проверен.

Это второй ребенок Боде в WM_CREATE обработчик.

Конец редактирования

case WM_CREATE:
    {
        // this is your treeview

        TreeView = CreateWindowEx(0, WC_TREEVIEW, 
            TEXT("Tree View"), WS_VISIBLE | WS_CHILD, 
            0, 0, 200, 500, 
            hwnd, (HMENU)ID_TREE_VIEW, GetModuleHandle(NULL), NULL);

        /************ enable checkboxes **************/

        DWORD dwStyle = GetWindowLong( TreeView , GWL_STYLE);
        dwStyle |= TVS_CHECKBOXES;
        SetWindowLongPtr( TreeView , GWL_STYLE, dwStyle );

        /************ add items and subitems **********/

        // add root item

        TVINSERTSTRUCT tvis = {0};

        tvis.item.mask = TVIF_TEXT;
        tvis.item.pszText = L"This is root item";
        tvis.hInsertAfter = TVI_LAST;
        tvis.hParent = TVI_ROOT;

        HTREEITEM hRootItem = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , 
            TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );

        // and here is an example of removing a checkbox 
        // from a specific item/subitem in case you ever need it

        TVITEM tvi;
        tvi.hItem = hRootItem ;
        tvi.mask = TVIF_STATE;
        tvi.stateMask = TVIS_STATEIMAGEMASK;
        tvi.state = 0;
        TreeView_SetItem( TreeView, &tvi );

        // add firts subitem for the hTreeItem

        memset( &tvis, 0, sizeof(TVINSERTSTRUCT) );

        tvis.item.mask = TVIF_TEXT;
        tvis.item.pszText = L"This is first subitem";
        tvis.hInsertAfter = TVI_LAST;
        tvis.hParent = hRootItem;

        HTREEITEM hTreeSubItem1 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , 
            TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );

        // now we insert second subitem for hRootItem

        memset( &tvis, 0, sizeof(TVINSERTSTRUCT) );

        tvis.item.mask = TVIF_TEXT | TVIF_STATE; // added extra flag
        tvis.item.pszText = L"This is second subitem";
        tvis.hInsertAfter = TVI_LAST;
        tvis.hParent = hRootItem;

        // for demonstration purposes let us check this node;
        // to do that add the following code, and add the extra flag for 
        // mask member like above
        tvis.item.stateMask = TVIS_STATEIMAGEMASK;
        tvis.item.state = 2 << 12;

        HTREEITEM hTreeSubItem2 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , 
            TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );

        // let us expand the root node so we can see if checked state is really set
        TreeView_Expand( TreeView, hRootItem, TVE_EXPAND );
    }
    return 0L;

РЕДАКТИРОВАТЬ № 2:

Вот часть, которая объясняет, как проверить, отмечен ли элемент (теперь он правильно проверяется, когда вы нажимаете на флажок и нажимаете пробел!):

case WM_NOTIFY:
    {
        LPNMHDR lpnmh = (LPNMHDR) lParam;

        if( lpnmh->idFrom == ID_TREE_VIEW  )  // if this is our treeview control
        {
            switch( lpnmh->code )  // let us filter notifications
            {
            case TVN_KEYDOWN:  // tree has keyboard focus and user pressed a key
                {

                    LPNMTVKEYDOWN ptvkd = (LPNMTVKEYDOWN)lParam; 

                    if( ptvkd->wVKey == VK_SPACE )  // if user pressed spacebar
                    {

                        // get the currently selected item
                        HTREEITEM ht = TreeView_GetSelection( ptvkd->hdr.hwndFrom );

                        // Prepare to test items state

                        TVITEM tvItem;

                        tvItem.mask = TVIF_HANDLE | TVIF_STATE;
                        tvItem.hItem = (HTREEITEM)ht;
                        tvItem.stateMask = TVIS_STATEIMAGEMASK;

                        // Request the information.
                        TreeView_GetItem( ptvkd->hdr.hwndFrom, &tvItem );

                        // Return zero if it's not checked, or nonzero otherwise.
                        if( (BOOL)(tvItem.state >> 12) - 1 )
                            MessageBox( hwnd, L"Not checked!", L"", MB_OK );
                        else
                            MessageBox( hwnd, L"Checked!", L"", MB_OK );

                    }
                }
                return 0L;  // see the documentation for TVN_KEYDOWN

            case NM_CLICK:  // user clicked on a tree
                {
                    TVHITTESTINFO ht = {0};

                    DWORD dwpos = GetMessagePos();

                    // include <windowsx.h> and <windows.h> header files
                    ht.pt.x = GET_X_LPARAM(dwpos);
                    ht.pt.y = GET_Y_LPARAM(dwpos);
                    MapWindowPoints( HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1 );

                    TreeView_HitTest(lpnmh->hwndFrom, &ht);

                    if(TVHT_ONITEMSTATEICON & ht.flags)
                    {
                        // Prepare to receive the desired information.

                        TVITEM tvItem;

                        tvItem.mask = TVIF_HANDLE | TVIF_STATE;
                        tvItem.hItem = (HTREEITEM)ht.hItem;
                        tvItem.stateMask = TVIS_STATEIMAGEMASK;

                        // Request the information.
                        TreeView_GetItem( lpnmh->hwndFrom, &tvItem );

                        // Return zero if it's not checked, or nonzero otherwise.
                        if( (BOOL)(tvItem.state >> 12) - 1 )
                            MessageBox( hwnd, L"Not checked!", L"", MB_OK );
                        else
                            MessageBox( hwnd, L"Checked!", L"", MB_OK );

                    }
                }
            default:
                break;
        }
    }
}
break;

Соответствующей идеей для правильного тестирования при нажатии пробела является обработка сообщения TVN_KEYDOWN.

Мы используем это сообщение для заполнения структуры NMTVKEYDOWN, которая даст нам код виртуальной клавиши нажатой кнопки и HWND дерева, которое отправило уведомление.

Теперь мы используем TreeView_GetItem() макрос, чтобы получить текущий выбранный узел, и мы проверяем его состояние так же, как мы делали это при тестировании нажатия.

Моя единственная проблема связана с этой частью из документации для TVN_KEYDOWN:

Возвращаемое значение

Если член wVKey в lParam представляет собой символьный код клавиши, этот символ будет использоваться как часть инкрементного поиска. Вернуть ненулевое значение, чтобы исключить символ из добавочного поиска, или ноль, чтобы включить символ в поиск. Для всех остальных ключей возвращаемое значение игнорируется.

Я просто не знаю, что делать с возвращаемым результатом, поэтому я поставил 0L,

Важное примечание: если вам нужно вернуть значение из процедуры диалогового окна, используйте что-то вроде этого:

SetWindowLongPtr( hwnd, DWLP_MSGRESULT, (LONG_PTR)1 );
return TRUE;

см. примечания для Return value в этой документации и используйте SetWindowLongPtr вместо SetWindowLong так что вы можете поддержать оба x32 а также x64 версии Windows,

Это было бы все. Надеюсь, у вас есть проблема решена. Если вам нужна дополнительная помощь, оставьте комментарий.

Конец редактирования

Я никогда не проверял, проверен ли элемент дерева, но я считаю, что принятый ответ на этот вопрос - путь.

НОТА:

Я был бы очень признателен, если бы кто-то, кто может предоставить фрагмент кода для показа, как определить, если treeview узел проверен или нет.

Другие вопросы по тегам