Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > каталоги в TreeView


Автор: Domain 6.4.2010, 08:42
Всем привет. Делаю диплом и мне просто необходимо реализовать там следующие... Например я при помощи TDirectoryEdit выбираю каталог и получаю его имя. Потом мне нужно в TreeView отобразить все папки и подкаталоги, примерно таким образом:

Dir1
     -dir1.1
     -dir1.2
     -dir1.3
              --dir1.3.1
              --dir1.3.2
              --dir1.3.3
Dir2
     -dir2.1
     -dir2.2
     -dir2.3
              --dir2.3.1
              --dir2.3.2
              --dir2.3.3
где dir1.3.2 имеет следующий путь C:\Dir1\dir1.3\dir1.3.2

Т.е. основные директории лежат в основе дерева, подкаталоги второй уровень(т.е. узел) и т.д.

Функция для поиска папок и подкаталогов(причем всех) следующая:
Код

TStringList * __fastcall TfNewbk::GetSubDirs(AnsiString RootDir) 
{
 TStringList *Result = NULL;

 if (DirectoryExists(RootDir))
 {
   TSearchRec sr;
   AnsiString  MaskNameString;

   Result = new TStringList();
   Result->Clear();
   Result->Append(RootDir);

   for (int i = 0; i < Result->Count; i++)
   {
     MaskNameString = Result->Strings[i] + "\\*.*";
     for (int j = 0;;j++)
     {
       if (!j)
       {
         if (FindFirst(MaskNameString, faAnyFile, sr))
         {
           FindClose(sr);
           break;
         }
       }
       else
       {
         if (FindNext(sr))
         {
           FindClose(sr);
           break;
         }
       }
       if(sr.Attr&faDirectory)
       {
         if((sr.Name != ".") && (sr.Name != ".."))
         {
           Result->Append(Result->Strings[i] + "\\"+ sr.Name);
         }
       }
     }  
   }
   Result->Delete(0);
 }

 
 return Result;
}



но как все эти папки и подкаталоги потом раскидать по TreeView ума не приложу. Подскажите как быть? Может например искать подкаталоги и кидать их в TreeView, а потом искать в них подкаталоги, при этом создавая узлы. Кто знает помогите, оч нужно... 

Автор: Domain 13.4.2010, 11:39
хей багуп

Автор: ИванМ 13.4.2010, 14:15
Можно просто через FindFirst/FindNext искать все каталоги/файлы и в зависимости от этого создавать нужный узел. Оформить это в виде функции. И если это каталог, то вызывать эту функцию снова, рекурсивно, с новым значением маски.

Автор: Domain 15.4.2010, 10:53
а дай функцию для поиска подкаталогов первого уровня... 

Автор: SenkraD 15.4.2010, 11:05
Domain,  найди книгу Архангельского "C++ Builder
и Механизмы Windows" - там он писал приммеры файловых менеджеров
и обсуждались аспекты посторения деревьев по файловой системме

Автор: Domain 15.4.2010, 13:24
ну нормально. спс.

Автор: Domain 18.4.2010, 23:37
а как функцию переписать чтобы она мне подкаталоги только первого уровня показывала, а не всех?

Автор: SenkraD 19.4.2010, 10:22
Если идти по итнуиции, то сделать bool параметр для указания того,
что фун-ка работает рекурсивно или нет. и если нужен только первый уровень,
то передаём false.
А вообще, Domain,  какую функцию? Где код?

Автор: Domain 19.4.2010, 10:47
вот функция для поиска всех подкаталогов всех уровней

Код

TStringList * __fastcall TfNewbk::GetSubDirs(AnsiString RootDir) 
{
 TStringList *Result = NULL;
 if (DirectoryExists(RootDir))
 {
   TSearchRec sr;
   AnsiString  MaskNameString;
   Result = new TStringList();
   Result->Clear();
   Result->Append(RootDir);
   for (int i = 0; i < Result->Count; i++)
   {
     MaskNameString = Result->Strings[i] + "\\*.*";
     for (int j = 0;;j++)
     {
       if (!j)
       {
         if (FindFirst(MaskNameString, faAnyFile, sr))
         {
           FindClose(sr);
           break;
         }
       }
       else
       {
         if (FindNext(sr))
         {
           FindClose(sr);
           break;
         }
       }
       if(sr.Attr&faDirectory)
       {
         if((sr.Name != ".") && (sr.Name != ".."))
         {
           Result->Append(Result->Strings[i] + "\\"+ sr.Name);
         }
       }
     }  
   }
   Result->Delete(0);
 }
 
 return Result;
}

Автор: Domain 22.4.2010, 11:12
SenkraD братушечка выручай ... еее ..

Автор: DCamer 22.4.2010, 12:30
Domain, этот "Файловый менеджер" будет работать с папками на компьютере?

Автор: SenkraD 22.4.2010, 12:32
Domain,  builder'а под рукой нет - так, что получи почти кросплатформенный вариант
Код
//--------------------------------------------------------------------------------------------------
#include <io.h>

#include <string>
#include <vector>
#include <iostream>


//--------------------------------------------------------------------------------------------------
std::size_t getSubfolderList(std::string const& path, std::vector<std::string>& items)
{
    struct _finddata_t fileInfo = { 0 };
    intptr_t fileHandle = _findfirst((path + "/*.*").c_str(), &fileInfo);
    if (fileHandle != -1L)
    {
        do
        {
            std::string const itemName = fileInfo.name;
            bool isDirectory = (fileInfo.attrib & _A_SUBDIR);
            bool isDotFolder = isDirectory && ((itemName == ".") || (itemName == ".."));
            if (isDirectory && !isDotFolder)
            {
                items.push_back(itemName);
            }
        } while (_findnext(fileHandle, &fileInfo) == 0);
        _findclose(fileHandle);
    }
    return items.size();
}
//--------------------------------------------------------------------------------------------------
// Application entry point
//
int main(int argc, char const* const argv[])
{
    std::vector<std::string> items;
    std::string const folder = "C:/";
    if (getSubfolderList(folder, items) > 0)
    {
        std::cout << "Folder (" << folder << ") subfolders list:\n";
        for (std::vector<std::string>::const_iterator it = items.begin(), last = items.end(); it != last; ++it)
        {
            std::cout << "\t" << *it << "\n";
        }
        std::cout.flush();
    }
    return 0;
}

//--------------------------------------------------------------------------------------------------
P.S. Неужели 

Автор: DCamer 22.4.2010, 12:50
Domain, чтобы отобразить путь в лейбле нужно на форму кинуть лейбл и в свойствах TDirectoryListBox указать имя лейбла в DirLabel

Автор: xvr 23.4.2010, 13:12
При создании TTreeView заполняешь ему один уровень именами каталогов. В каждом каталоге делаешь 1 вложенный item c текстом типа '<Loading...>'. На раскрытие item'ов вешаешь событие, которое сканирует соотвествующий подкаталог (на 1 уровень, без рекурсий) и по окончании заменяет узел '<Loading...>' на построенный список. Построенный уровень так же должен содержать '<Loading...>' для всех вложенных каталогов


Автор: Domain 23.4.2010, 17:26
ну сам принцип я давно догнал, тока что не мог убрать рекурсию из той функции, которую я написал уже дважды тут. просто она нормально работает, только так  не понял где там рекурсию убрать. xvr может ты мне подскажешь? в том что SenkraD написал я еще не разбирался. имхо у меня еще пока не такой уровень, чтобы потом этот код грамотно в bcb поместить. может тогда скажете в каком месте я получаю путь к каталогу, чтобы потом его например в StringList добавить?

Автор: xvr 23.4.2010, 17:46
У каждого элемента в TreeView есть ассоциированные данные (TTreeNode::Data). В них можно хранить не только указатели, но и просто числа (приведя тип). Каждый элемент соотвествует какому то пути на диске. К сожалению этот путь придется хранить отдельно, и адресоваться к нему по самому TTreeNode (через его TTreeNode::Data) или непосредственно по указателю на TTreeNode.
Для этого можно создать где то в классе вектор или мэп из строк (std::vector<AnsiString> или std::map<TTreeNode*,AnsiString>), второе даже лучше - не надо заморачиваться с индексами.
А дальше все просто - при раскрытии TTreeNode из вектора или мэпа извлекается ее путь (полный), и для него делается цикл из FindFirst & FindNext (безо всяких рекурсий, один голый цикл для одного пути). Все, что нашли добавляется в TreeView и одновременно в вектор (или мэп)


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)