Я это достаточно давно сделал, может быть по-топорному, но не стал ничего менять - работает устойчиво и ладно. Делал так:
| Код | //--------------------------------------------------------------------------- // Метод: BuildTree // Построение дерева каталогов // Список записей, поддерживающих метод GetMasterUni и GetNodeName находитя // в списке pList // pTr - Дерево bool TMAN_ADODBTree::BuildTree(TTreeView *pTr,TList * pList) { int i,Master,cM; TMAN_ADOVrec *CurRec; TTreeNode *CurNode,*RootNode; TStack *pStack; AnsiString aN;
// Стек нужен для временного хранения перебираемых узлов pStack = new TStack; CurRec = NULL;
// Шаг 1 - очищаю дерево // и помечаю во всех записях списка узлы как неразмеченные pTr->Items->Clear(); for (i=0;i<pList->Count;i++) { CurRec = (TMAN_ADOVrec*)pList->Items[i]; CurRec->Node = NULL; }
// Шаг 2 - Создаю корневой узел дерева RootNode = pTree->Items->AddChildObject(NULL,RootName,NULL); Master = 0; // Для начала - нужен мастер - корневой уровень CurNode = RootNode; if (MainImageIndex != -1) RootNode->StateIndex = MainImageIndex;
// Шаг 3 - бегу по списку и добавляю в дерево узлы // Бегу пока в стеке есть записи // while(pStack->Count()>0) do { for (i=0;i<pList->Count;i++) { CurRec = (TMAN_ADOVrec*)pList->Items[i];
// Если запись уже есть в дереве - пропускаем if (CurRec->Node != NULL) continue;
// Если мастер нас не устраивает - пропускаем cM = CurRec->GetMasterUni(); if (cM != Master) continue;
// Нашли запись для добавления // Запоминаем ее в стеке и помещаем в дерево aN = CurRec->GetNodeName(); CurRec->Node = pTree->Items->AddChildObject( CurNode, aN, CurRec); if (MainImageIndex != -1) { CurRec->Node->StateIndex = MainImageIndex; CurRec->Node->SelectedIndex = MainImageIndex; CurRec->Node->ImageIndex = MainImageIndex; } CurRec->FType = 1; // Признак каталога // Запоминаем этот узел pStack->Push(CurRec); } // for (i=0;i<pList->Count;i++) // Все записи помещены в текущий уровень. Извлекаю из стека // последнюю записанную запись
// Если стек пуст (ни одной записи не осталось) - выхожу if (pStack->Count() == 0) break;
CurRec = (TMAN_ADOVrec*)pStack->Pop(); CurNode = CurRec->Node; Master = CurRec->Uni;
} while(true);
pTree->Selected = RootNode; return true; }
|
Пояснения к коду: В pList у меня полный список записей из БД. Записи БД загнаны в мой собственный класс, поэтому из кода нужно взять только алгоритм заполнения.
В списке pList объекты моего собственного класса, от них требуются следующие вещи: Поле Node - предназначено для хранения узла дерева (изначально обнуляется) Поле Uni содержит ключ текущей записи. Метод GetNodeName Возвращает строку, которую отобразить в качестве названия узла Метод GetMasterUni Возвращает ключ записи, к которой привязана текущая Если подменить эти участки на собственные - то можно пользоваться, в общем то. Правда там еще пиктограммки ставятся, но это просто можно убрать.
Моя схема при зацикливании дерева просто обрезает зацикленные ветви. Я проверяю на зацикленность не при каждом построении дерева, а из служебной части - чтобы при зацикленном дереве сохранять более-менее работоспособность. Если после построения дерева останутся записи, в которых узел дерева нулевой - значит было зацикливание. |