Создание 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 ответ
РЕДАКТИРОВАТЬ № 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
узел проверен или нет.