Delphi, какой идеальный метод для заполнения VirtualStringTree?

Итак, я работаю с Delphi 2010, и прошло некоторое время с тех пор, как я начал использовать VirtualTreeView (именно VirtualStringTree).. и кажется, что я делаю что-то не так.. поскольку все работает не так, как я ожидание.

Я пытаюсь заполнить свой VST узлами, которые указывают на описания файлов/подпапок, хранящиеся в записях данных и сгенерированные путем сканирования пути, указанного пользователем.. (более подробная информация показана на следующем изображении)

введите здесь описание изображения

Как показано, узлы отображаются странным образом ... и независимо от того, что я делаю, данные узлов не инициализируются должным образом ... заголовки узлов для столбца «Файл» - единственное, что работает хорошо.

и вот код, который я использую:

1- Объявление данных узла:

type  nodeData=record
            Text, Size, Path:String;
            ImageIndex:Integer;
           end;

  PNodeData=^nodeData;


var hashmap:TDictionary<String, PVirtualNode>; // hashmap-> to store parent nodes (Folder)
    filesList:TDictionary<Integer,nodeData>; // fileList to store records of data

2-Методы

а) сканировать путь, заданный пользователем

procedure AddAllFilesInDir(const Dir:String);
begin
// it scans the path 'Dir' and extract the "name & size" of each file/folder found in this dir
end;

b) создать словарь filesList... и изображения сохраняются в "treeImageLIst", который связан со свойством treeview.images.

procedure addFileToList(Name, Size:String);
var d:nodeData;
    parent:String;
    SHFileInfo :TSHFileINfo;
    Icon:TIcon;
begin
parent:=ExtractFileDir(Name);

//Get The Icon That Represents The File/Folder
SHGetFileInfo(PChar(Name), 0, SHFileInfo,  SizeOf(SHFileInfo),
                SHGFI_ICON or SHGFI_SMALLICON );


Icon := TIcon.Create;
Icon.Handle := SHFileInfo.hIcon;

// set The Name, Size, Path
d.Name:=ExtractFileName(Name);
d.Size:=Size;
d.Path:=parent;

// set the ImageIndex
d.ImageIndex:=Form1.treeImageList.AddIcon(Icon);

// add the node to fileList
filesList.Add(filesList.Count, d);

// Destroy the Icon
DestroyIcon(SHFileInfo.hIcon);
Icon.Free;
end;

в) создать дерево "theTree"

procedure createTree();
var theNode, Node:PVirtualNode;
    d:PNodeData;
    parent:String;
    nData:nodeData;
    i:integer;
begin

for i := 0 to filesList.Count - 1 do
begin

 nData:=filesList.Items[i];  parent:=nData.Path;

 if(hashmap.ContainsKey(parent))then theNode:=hashmap.Items[parent]
 else theNode:=nil;

 Node:=Form1.theTree.AddChild(theNode);

 // add a checkbox and make it checked
 Node.CheckType:=ctCheckBox;
 Node.CheckState:=csCheckedNormal;

 // get the newly created node data
 d:=Form1.theTree.GetNodeData(Node);

 // assign a data  to the newly created node
 d^:=nData;

 // add the node to hashmap if it's a new folder node
 if((ExtractFileExt(nData.Text)='')and(not hashmap.ContainsKey(nData.Path+'\'+nData.Text)))
 then hashmap.Add(nData.Path+'\'+nData.Text, Node);

end;

 Form1.theTree.Expanded[Form1.theTree.TopNode]:=True;
end;

г) древовидные события

procedure TForm1.theTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var d:PNodeData;
begin
  d := Sender.GetNodeData(Node);
  Finalize(d^);
end;


procedure TForm1.theTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
var d:PNodeData;
begin
 d:=Sender.GetNodeData(Node);

 case Column of
  0:CellText:=d^.Text;
  1:CellText:=d^.Size;
 end;
end;


procedure TForm1.theTreeGetImageIndex(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
  var Ghosted: Boolean; var ImageIndex: Integer);

var d:PNodeData;
begin
d:=Sender.GetNodeData(Node);

if(Kind in [ikNormal, ikSelected])then
begin
 if(Column=0)then ImageIndex:=d^.ImageIndex;
end;

end;

Я действительно расстроен прямо сейчас ... и я не знаю, почему узлы не создаются должным образом ... хотя я проверил данные записей, и они созданы хорошо, но когда я тестировал событие onNodeClick, я обнаружил, что запись данных, указанная узлом, возвращает только первое поле... в то время как другие поля либо пусты, либо генерируют исключение нарушения прав доступа.


person DZkid    schedule 02.04.2013    source источник
comment
Вы действительно не заполняете виртуальный элемент управления. Виртуальный элемент управления не хранит данные для своих узлов, он запрашивает их всякий раз, когда ему нужно показать информацию об узле. Все, что вам действительно нужно, чтобы запустить виртуальное дерево, — это установить количество его корневых узлов. Пример использования TVirtualStringTree, который получает данные из отдельной строки данных, можно найти в мой ответ о том, как заставить несколько узлов отображать одни и те же данные   -  person Marjan Venema    schedule 02.04.2013
comment
@Marjan: да, но мои данные хранятся в словаре списка файлов. Я сделал следующее: theTree.NodeDataSize:=sizeof(PNodeData)*5; .. и сейчас все отлично работает... есть какие-нибудь объяснения по этому поводу? Попробую также просмотреть предоставленную вами ссылку.   -  person DZkid    schedule 02.04.2013
comment
Если бы умножение размера на (казалось бы) произвольное число 5 решило вашу проблему, я бы дважды и трижды проверил ваши знания о том, что такое указатель на тип данных и как работает SizeOf. SizeOf(SomePointerType) возвращает размер указателя, а не то, на что он указывает. Таким образом, ваше умножение на 5, заставляющее все работать, должно сказать вам, что теперь вы говорите VST зарезервировать достаточно памяти для хранения ваших записей. Что снова говорит о том, что вы должны использовать размер записи вашего узла, а не размер указателя на ваш тип записи. iow: theTree.NodeDataSize:=SizeOf(nodeData) (обратите внимание на отсутствие P)   -  person Marjan Venema    schedule 02.04.2013
comment
Я собирался написать об этой проблеме. Должен ли sizeOf() быть SizeOF(Pointer) или SizeOf(RecodData)? Потому что в учебнике, который я прочитал, я обнаружил, что это SizeOf (Pointer) (но данные были только записью целого числа) .. и это звучит немного неправильно для меня.   -  person DZkid    schedule 02.04.2013
comment
Если запись содержит только целое число, она имеет тот же размер, что и указатель (по крайней мере, в Win32).   -  person Uwe Raabe    schedule 02.04.2013
comment
Учебник, который вы нашли, почти наверняка был неправильным. Иногда люди не понимают, где именно находятся данные узла. Если они думают, что должны выделить их сами, то обычно так и делают, а затем сохраняют указатель на эти данные в области GetNodeData. Если у вас есть запись с данными вашего узла, вы должны всегда говорить NodeDataSize := SizeOf(TNodeData).   -  person Rob Kennedy    schedule 02.04.2013
comment
@Uwe: Наверное, да... следование вводящему в заблуждение учебнику может привести к нежелательным и ужасным результатам. Спасибо всем за вашу помощь.   -  person DZkid    schedule 02.04.2013
comment
Вы не должны использовать AddChild. Это для совместимости при переносе с TTreeView. Вместо этого вы должны использовать OnInitNode или OnInitChildren и использовать его для подключения дерева к вашим виртуальным данным в TDictionary, а затем получать данные при запуске события OnGetText. Вы пытаетесь использовать его как TTreeView, который не находится в виртуальном режиме. Демонстрации доступны в репозитории Google Code.   -  person Ken White    schedule 03.04.2013
comment
Я даже потрудился посмотреть исходник в Демо. В проекте Minimal есть очень простой пример правильного использования здесь на Main.pas   -  person Ken White    schedule 03.04.2013
comment
@Ken: в данный момент я использую VST, просто выполните эту задачу в самое ближайшее время... и AddChild отлично сработало для меня. Но мне обязательно придется реализовать свой код снова, когда появится время, чтобы воспользоваться преимуществами виртуальности VST... а что касается вашей проблемы с просмотром исходного кода...... очень признателен и спасибо всем еще раз.   -  person DZkid    schedule 03.04.2013
comment
@DZKid: Ваш код не работает должным образом (на самом деле, это далеко не рабочий код), и я разместил ссылку на простой пример того, как это сделать правильно. Зачем тратить время на то, чтобы сделать что-то неправильно, если вам уже нужно проделать большую работу над кодом, чтобы он все равно работал?   -  person Ken White    schedule 03.04.2013
comment
Сейчас он работает хорошо... и, как я уже сказал, время имеет решающее значение для меня в данный момент.   -  person DZkid    schedule 03.04.2013
comment
Делая это правильно, вы бы сэкономили время сейчас   -  person David Heffernan    schedule 03.04.2013


Ответы (1)


Вы разместили слишком много кода, чтобы задать полезный вопрос. Каждый день публикуются сотни вопросов, в которых нет примеров кода или недостаточно примеров кода. Вы ушли в другую сторону, очень далеко в другую сторону.

Лучший способ «заполнить» виртуальное древовидное представление — НЕ заполнять его. Вместо этого вы только устанавливаете rootNodeCount, а затем итеративно, когда вам нужно, устанавливаете количество дочерних узлов для дочерних узлов. Для свернутого узла достаточно, чтобы древовидное представление знало, есть ли дочерние элементы, или что их нет. Как только вы расширите дочерний узел, вы можете заполнить подэлементы.

Обратите внимание, что когда вы делаете это так, как должны делать виртуальные элементы управления, вы не пишете тонны кода. Вместо этого вы просто «отвечаете на вопросы о базовом состоянии объектов вашей модели». Сколько корневых узлов? Вы сообщаете виртуальному дереву этот номер. Затем оттуда вы просто отвечаете на вопросы, когда он вас спрашивает. Какой текст для столбца 0, для узла № 3 под корневым узлом? (Он вызывает событие, которое вы обрабатываете, и возвращаете эту информацию). Обратите внимание, что инициализация ДАННЫХ — это то, что большинство людей, плохо знакомых с VirtualTreeViews, часто неправильно понимают. В идеале эти DATA должны содержать указатель на реальный объект модели, который может отвечать на вопросы, которые ему задает VirtualTreeView. Наиболее эффективные классы, отвечающие на эти вопросы, могут даже не нуждаться в создании реального объекта модели для каждого видимого узла в дереве, хотя это, безусловно, приемлемо и распространено. Важно, чтобы вы понимали, что это не является строго НЕОБХОДИМЫМ.

Во-вторых, если ваша цель состояла в том, чтобы использовать TVirtualTreeView для эмуляции обозревателя оболочки, этот код уже сделан за вас, просмотрите подраздел Advanced демонстрации VT, доступный на веб-сайте VirtualTreeview. Смотрите вкладку, которую я указал здесь:

введите здесь описание изображения

person Warren P    schedule 02.04.2013
comment
Как я уже сказал < i>здесь Я знаю, что использую VST не лучшим образом... но в настоящий момент для меня важным фактом является время... и для демонстрации, на которую вы указали... Я видел это раньше, и это казалось слишком сложным для того, кто никогда не использовал VST. - person DZkid; 03.04.2013
comment
Вы не сможете быстро работать в виртуальном контроле, пока не поймете модель и идеи, которые она использует. - person Warren P; 03.04.2013
comment
Но в данный момент я не ищу виртуальный элемент управления. Мне просто нужен TreeView, который лучше, чем TTreeView, поставляемый с delphi. - person DZkid; 03.04.2013
comment
Затем получите другой вид дерева. Вы сойдете с ума, пытаясь превратить виртуальный элемент управления в невиртуальный. Говорю вам, я потратил более 100 часов на изучение VirtualTreeView. Если вам нужно простое в освоении невиртуальное древовидное представление, которое лучше (я полагаю, вы имеете в виду красивее?), чем TTreeView, вам нужно купить его, потому что не существует бесплатного невиртуального простого в использовании древовидного представления для Delphi. . TTreeView и TJvTreeView - все это оболочки вокруг представления дерева общих элементов управления Windows. - person Warren P; 03.04.2013
comment
Под «лучше» я подразумеваю функции, а не то, что делает его красивым. Мне нужен VST только для выполнения эту задачу в ближайшие пару дней. - person DZkid; 03.04.2013
comment
Ключевой вещью, которую я никогда не находил бесплатно, является невиртуальный элемент управления с несколькими столбцами, который сочетает в себе возможности Grid (столбцы) и Tree (вложенность) в одном элементе управления. Хотя VirtualTreeView — замечательный компонент, он не прост, и вы не единственный, кому сложно его изучить. - person Warren P; 03.04.2013