Узлы VirtualTreeview, передать их в другую форму? - PullRequest
1 голос
/ 04 февраля 2011

Мое приложение будет проходить через виртуальные узлы и проверять их данные. Я использую другую форму, чтобы сделать это, чем форма, содержащая VirtualStringTree. (У меня есть свои причины;))

Мой вопрос: как я могу передать эти узлы + их данные в функцию в другой форме, которая затем сможет циклически проходить через узлы (я знаю, как зацикливаться, мне просто нужно, чтобы узлы были доступны в моя другая форма).

Также обратите внимание, что форма, содержащая VirtualStringTree, уничтожается при отображении формы обработки!

Как я мог это сделать? Я думаю о создании динамического VirtualStringTree и как-то передать узлы из одного дерева в другое, но я бы сначала попросил здесь о каких-либо лучших решениях. :)

Спасибо, Джефф.

1 Ответ

13 голосов
/ 04 февраля 2011

Я уже говорил , что вы делаете что-то не так, и теперь вы поймете, почему.

Вы используете древовидный элемент управления для хранения ваших данных. Он предназначен для отображения данных. У вас должна быть отдельная структура данных, задача которой only - хранить ваши данные. Вероятно, это будет дерево , но не дерево control . Именно эту древовидную структуру данных вы дадите форме обработки, поскольку для нее не нужно отображать узлы.

Когда вы хотите отобразить свои данные, вы узнаете, сколько узлов имеется на первом уровне вашего дерева, а затем вы задаете для свойства RootNodeCount элемента управления вашего дерева это число. Элемент управления выделит столько узлов - не вызывайте AddNewNode для массовых операций, таких как заполнение элемента управления. Когда дерево будет отображать узел на экране, который не отображался ранее, он запустит обработчик события OnInitNode. Здесь вы инициализируете узел и связываете его со значением в вашей структуре данных. Древовидный элемент управления сообщит вам, какой узел он инициализирует - и через указатель PVirtualNode, и через индекс, который сообщает, какой это узел, относительно его родителя. Когда вы инициализируете узел, вы сообщаете дереву, есть ли у узла дочерние элементы. Вам не нужно указывать сколько детей еще; если контроль хочет знать, он попросит вас о другом событии.

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

Смотри также:


Вы сказали, что у вас есть только один уровень узлов. Это нормально. Дерево только с одним уровнем более широко известно как список . Есть несколько вещей, которые вы можете использовать для отслеживания списка. Самым простым является массив . Вы также можете использовать TList или создать свой собственный связанный список. В этом примере будет использоваться массив, потому что я хочу сосредоточиться на древовидном элементе управления.

Давайте предположим, что данные для каждого узла представлены записью TData, поэтому у вас есть массив таких:

var
  Data: array of TData;

После того, как вы загрузили массив с информацией из любого имеющегося у вас источника, вы готовы заполнить древовидный элемент управления. Это так же просто, как две строки кода (одна, если элемент управления пуст):

Tree.ResetNode(nil); // remove all existing nodes from tree
Tree.RootNodeCount := Length(Data); // allocate new nodes for all data

Поскольку дерево определяет, что ему нужно больше информации о любом из этих узлов, оно будет запускаться, вызывая событие OnInitNode. Вам ничего не нужно делать для этого события, поскольку поля Index узла будет достаточно, чтобы мы могли найти запись TData, которая соответствует любому данному узлу дерева.

procedure TJeffForm.TreeInitNode(Sender: TBaseVirtualTree;
    ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
begin
  Assert(Node.Index < Length(Data), 'More nodes than data elements!?');
  InitialStates := []; // If the node had children, or if it should be
                       // initially disabled, you'd set that here.
end;

Когда дерево хочет нарисовать себя, оно спросит вас, какой текст отображать для каждого видимого узла, вызвав событие OnGetText. Поле Index узла сообщает вам, какой это элемент относительно его родителя. (Поскольку у вас просто есть список, этот индекс соответствует индексу в вашем списке.)

procedure TJeffForm.TreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
    Column: TColumnIndex; TextType: TVSTTextType; var CellText: UnicodeString);
begin
  if TextType = ttStatic then
    exit;
  case Column of
    NoColumn,
    0: CellText := Data[Node.Index].Name;
    1: CellText := 'Second column';
    else
      Assert(False, 'Requested text for unexpected column');
  end;
end;

Выше я предположил, что TData имеет строковое поле с именем Name, и это то, что мы должны отобразить в главном столбце. Если дерево запрашивает текст для чего-либо после второго столбца, мы получим ошибку подтверждения, сигнализирующую, что мы еще не готовы выпустить продукт.

Обратите внимание, как мы используем индекс узла, чтобы посмотреть на совершенно отдельную структуру данных массива. Мы могли бы полностью уничтожить древовидный контроль, и данные по-прежнему существовали бы. Когда вашей форме обработки требуется обработать данные, присвойте ей массив Data, а не элемент управления tree.

...