C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Сохранение и восстановление TreeView  (Прочитано 4948 раз)
Day
Участник


Сказали спасибо: +11/-1
Offline

Сообщений: 137


Сохранение и восстановление TreeView
« : 11 Февраль 2012, 19:39:32 »

Выкладываю, потому что никакие поиски не дали результата
Такая задача. Есть TreeView. Надо его сохранить в файле и потом восстановить так, чтобы сохранялось раскрытие узлов. Методы SaveToFile-LoadFromFile не подходят, тк они не учитывают ракрытие узлов дерева.
Сохранить удалось достаточно просто, рекурсивно обходя дерево и запоминая Level и Expanded
При восстановлении возникли проблемы. Задавать Expanded при построении узлов - не помогает. Пока дочерних узлов нет, это не работает.
Сделал так. При построении делаю nod->Data = (void *)(Признак раскрытия);
А уже после построения прохожусь по все узлам и nod->Expanded = nod->Data.
Конечно, если Data используется, придется немного исхитрится, скажем дополнить ее еще одним байтиком.
Если кто знает более простой способ - поделитесь.
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


Re: Сохранение и восстановление TreeView
« Ответ #1 : 11 Февраль 2012, 21:03:31 »

Не далее как позавчера давал ссылку на сохранение TreeView -> XML. Добавить еще один атрибут (expanded), и сделать еще одну функцию, вызываемую после создания дерева для установки каждому узлу свойства Expanded согласно значению этого атрибута - дело трех минут.

Вот ссылка: Exporting a TreeView to XML. Populating a TreeView from XML
Записан
SilverFish
Участник


Сказали спасибо: +14/-6
Offline

Сообщений: 784


Re: Сохранение и восстановление TreeView
« Ответ #2 : 12 Февраль 2012, 13:35:57 »

Цитата: volvo877 от 11 Февраль 2012, 21:03:31
дело трех минут.

А для какого и трех дней маловато будет.
Все никак не могу понять код паскаля. Внутри одной функции procedure другая…
Как это выглядит на С++? Мне тоже надо хранить в узде его уникальный индификатор и при загрузке дерева ассоциировать этот индификатор с узлом, чтобы затем использовать его в SQL запросах.
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


Re: Сохранение и восстановление TreeView
« Ответ #3 : 12 Февраль 2012, 14:02:29 »

Цитировать
Как это выглядит на С++?
Сохраняем :
Код
void ProcessTreeItem(TTreeNode *tn, IXMLNode *iNode)
{
if(tn)
{
IXMLNode *cNode = iNode->AddChild("item");
cNode->SetAttribute("text", tn->Text);
cNode->SetAttribute("imageIndex", tn->ImageIndex);
cNode->SetAttribute("stateIndex", tn->StateIndex);
cNode->SetAttribute("expanded", tn->Expanded);
 
for(tn = tn->getFirstChild(); tn; tn = tn->getNextSibling())
{
ProcessTreeItem(tn, cNode);
}
}
}
 
void Tree2XML(TTreeView *tree)
{
TXMLDocument *XMLDoc = new TXMLDocument(0);
XMLDoc->Active = true;
_di_IXMLNode iNode = XMLDoc->AddChild("tree2xml");
iNode->SetAttribute("app", ParamStr(0));
 
for(TTreeNode *tn = tree->TopItem; tn; tn = tn->getNextSibling())
{
ProcessTreeItem(tn, iNode);
}
XMLDoc->SaveToFile(ChangeFileExt(ParamStr(0), ".XML"));
XMLDoc = 0;
}

Восстанавливаем (с учетом раскрытия узлов) :
Код
void PostProcessNode(_di_IXMLNode node, TTreeNode *tree_node)
{
if(node)
{
if((bool)(node->GetAttribute("expanded")))
tree_node->Expanded = true;
 
tree_node = tree_node->getFirstChild();
for(_di_IXMLNode xml_node = node->ChildNodes->First();
xml_node && tree_node; xml_node = xml_node->NextSibling())
{
PostProcessNode(xml_node, tree_node);
tree_node = tree_node->getNextSibling();
}
}
}
 
void ProcessNode(TTreeView *tree, _di_IXMLNode node, TTreeNode *tree_node)
{
if(node)
{
tree_node = tree->Items->AddChild(tree_node, node->GetAttribute("text"));
tree_node->ImageIndex = (int)(node->GetAttribute("imageIndex"));
tree_node->StateIndex = (int)(node->GetAttribute("stateIndex"));
 
for(_di_IXMLNode xml_node = node->ChildNodes->First();
xml_node; xml_node = xml_node->NextSibling())
{
ProcessNode(tree, xml_node, tree_node);
}
}
}
 
void XML2Tree(TTreeView *tree, TXMLDocument *XMLDoc)
{
tree->Items->Clear();
XMLDoc->FileName = ChangeFileExt(ParamStr(0), ".XML");
XMLDoc->Active = true;
 
_di_IXMLNode iNode = XMLDoc->DocumentElement->ChildNodes->First();
while(iNode)
{
ProcessNode(tree, iNode, 0);
iNode = iNode->NextSibling();
}
 
// Если раскрытие не нужно, а достаточно только восстановить дерево - то
// следующие 7 строк можно убрать. Функцию PostProcessNode() тоже...
TTreeNode *ti = tree->TopItem;
iNode = XMLDoc->DocumentElement->ChildNodes->First();
while(iNode)
{
PostProcessNode(iNode, ti);
iNode = iNode->NextSibling();
}
 
XMLDoc->Active = false;
}

Вызываем:
Код
void __fastcall TForm1::SaveButtonClick(TObject *Sender)
{
Tree2XML(TreeView1);
}
//---------------------------------------------------------------------------
 
void __fastcall TForm1::RestoreButtonClick(TObject *Sender)
{
XML2Tree(TreeView2, XMLDocument1);
}
Записан
Day
Участник


Сказали спасибо: +11/-1
Offline

Сообщений: 137


« Ответ #4 : 12 Февраль 2012, 14:05:52 »

Цитировать
хранить в узде
Забавная очепяточка. И не лишенная смысла.
А если серьезно - воспользуйтесь nod->Data
Код:
int Id;
nod->Data = (void *) Id;
 // Извлечение
Id = nod->Data;
[/cpp]
И пусть вас не смущают сомнительные приведения типов. Все работает (Builder 6)
Записан
Day
Участник


Сказали спасибо: +11/-1
Offline

Сообщений: 137


Re: Сохранение и восстановление TreeView
« Ответ #5 : 12 Февраль 2012, 14:39:38 »

Придется и мне выложиться

Код:
void __fastcall TForm1::TreeToFile()  // Запись дерева в файл
{
    FILE *f = fopen("tree.ctl", "w");
    TTreeNode *nod = TreeView1->Items->Item[0];
    while (nod!=NULL) {
      OutNode(f, nod);
      nod = nod->getNextSibling();
    }
    fclose(f);
}
/****************/
void __fastcall TForm1::OutNode(FILE *f, TTreeNode *nod)
{
  int k = nod->Expanded;
  fprintf(f, "%d=%d=%s\n", nod->Level, k, nod->Text.c_str());
  if (nod->HasChildren) {
    TTreeNode *nd = nod->getFirstChild();
    while (nd!=NULL) {
      OutNode(f, nd);
      nd = nd->getNextSibling();
    }
  }
}
/******************/
А это извлечение
Код:
void __fastcall TForm1::FileToTree(char *name)
{ FILE *f; char *p; int j; TTreeNode *nod;

     f = fopenany(name);
     if (f==NULL) return;
     TreeView1->Items->BeginUpdate();
     TreeView1->Items->Clear();
     nod = NULL;
     for(; (p=fgm0(f))!=NULL; free(p)) {
       XTD *x = xtdxr(p, '='); // Это просто разбор на строки (x->ns - их кол-во)
       if (x->ns >=3) nod = StroiNode(x, nod);
       delxtd(x);
     }
     fclose(f);
     afc(j, TreeView1->Items->Count) {
        nod = TreeView1->Items->Item[j];
        nod->Expanded = nod->Data;
     }
     TreeView1->Items->EndUpdate();
}
/****************/
TTreeNode* TForm1::StroiNode(XTD *x, TTreeNode *nod)
{ TTreeNode *nd; int Lev, Exp;
   Lev = atoi(x->ss[0]);  // Уровень
   Exp = atoi(x->ss[1]);  // Признак раскрытия
                          // x->ss[2] - строка с текстом узла
   if (nod==NULL || Lev==0) nd = TreeView1->Items->Add(NULL, x->ss[2]);
   else if (Lev==nod->Level) {
     nd = TreeView1->Items->Add(nod, x->ss[2]);
   }
   else if (Lev>nod->Level) {
     nd = TreeView1->Items->AddChild(nod, x->ss[2]);
   }
   else {
     while(nod!=NULL && Lev Level) nod = nod->Parent;
     nd = TreeView1->Items->Add(nod, x->ss[2]);
   }
   nd->Data = (void *)Exp;
   return nd;
}
/*******************/
Тут используется тип данных XTD - Это что-то вроде вектора или TList
Смысл его использования, надеюсь, понятен из комментариев.
Если что-то непонятно - спрашивайте.
Записан
SilverFish
Участник


Сказали спасибо: +14/-6
Offline

Сообщений: 784


Re: Сохранение и восстановление TreeView
« Ответ #6 : 13 Февраль 2012, 15:07:22 »

Спасибо.
Записан
SilverFish
Участник


Сказали спасибо: +14/-6
Offline

Сообщений: 784


Re: Сохранение и восстановление TreeView
« Ответ #7 : 13 Февраль 2012, 16:09:37 »

Я пытаюсь добавить атрибут в котором буду хранить Data узла, чтобы потом использовать это в SQL запросе.

Вот така пытаюсь:
В void ProcessTreeItem(TTreeNode *tn, IXMLNode *iNode) добавила строку:
cNode->SetAttribute("data", tn->Data);

В void ProcessNode(TTreeView *tree, _di_IXMLNode node, TTreeNode *tree_node) добавила:
tree_node->Data = reinterpret_cast(node->GetAttribute("data"));

Как правильно это исправить?
Cannot cast from 'OleVariant' to 'int'

Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


Re: Сохранение и восстановление TreeView
« Ответ #8 : 13 Февраль 2012, 16:26:19 »

Код
cNode->SetAttribute("data", (int)(tn->Data));
// ...
tree_node->Data = (void*)(node->GetAttribute("data"));
Записан
SilverFish
Участник


Сказали спасибо: +14/-6
Offline

Сообщений: 784


Re: Сохранение и восстановление TreeView
« Ответ #9 : 13 Февраль 2012, 16:34:32 »

Цитировать
tree_node->Data = (void*)(node->GetAttribute("data"));

[BCC32 Error] UnitXML.cpp(77): E2015 Ambiguity between '_fastcall operator Variant::IUnknown *()' and '_fastcall operator Variant::wchar_t * *()'

Вот так откомпилировалось:
tree_node->Data = (void*)(int)(node->GetAttribute("data"));

Можно так оставить?
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


Re: Сохранение и восстановление TreeView
« Ответ #10 : 13 Февраль 2012, 16:41:38 »

Откуда вы эти проблемы на свою... Хм... голову находите?
Записан
SilverFish
Участник


Сказали спасибо: +14/-6
Offline

Сообщений: 784


Re: Сохранение и восстановление TreeView
« Ответ #11 : 13 Февраль 2012, 17:53:43 »

Может потому, что у меня XE...
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


Re: Сохранение и восстановление TreeView
« Ответ #12 : 13 Февраль 2012, 18:19:13 »

Странно как-то XE себя ведет... Ну, оставь двойное преобразование тогда, записывала в файл так: void* -> int -> в XML, обратно - XML -> int -> void*
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  




....

Powered by SMF 1.1.21 | SMF © 2025, Simple Machines
Страница сгенерирована за 0.087 секунд. Запросов: 20.