Что-то не могу реализовать простейшее.
Есть TreeView, которое грузится из БД.
Добавляю новый узел, перезагружаю дерево (это касается только level = 1, поэтому не напряжно).
Хочу выделить (и раскрыть) узел, на котором пролизошло добавление.
Но почему-то код ниже не работает. Выделяется соседний узел.
i:=TV.Selected.Index;
try
// здесь должно быть добавление в базу записи,
// которая потом будет дочерним узлом для выделенного
// но пока ничего не добавляется, поэтому не должно влиять
finally
ReLoadTree; // очищает дерево и загружает повторно
TV.Items[i].Selected:=true; // i равно сохраненному
end;
С ItemId еще большая путаница.
Подскажите, как это реализовать.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
08-04-2025 23:48 | Сообщение от автора вопроса
Очень большое спасибо.
Да, сам убедился, что с AbsoluteIndex тоже работает не всегда правильно.
Поэтому сделал, как Вы посоветовали в предыдущем посте - стал использовать ID из базы, который хранится в структуре, привязанной к узлу.
Для небольшого количества поиск нужного узла по дереву никак не тормозит программу.
>>>переделал на Selected.AbsoluteIndex. Теперь всё работает как ожидалось. Нет ли в таком подходе "подводных камней"?
Смотря какую задачу, вы решаете.
Вы используете подход, в котором привязываете "прикладные данные" к "индексу позиционирования" узла в дереве.
Обычно же, используют другой подход. В "прикладных данных" выделяют уникальный идентификатор. И этот идентификатор добавляют к узлу дерева. Если дерево перезагружают (например, из БД), то позиционирование в дереве востанавливают по этому идентификатору. По нему же производится синхронизация данных из дерева TreeView и данных из БД.
>>>переделал на Selected.AbsoluteIndex
В моём первом посте закралась ошибка.
Под ItemId, я подразумевал AbsoluteIndex. Но и это верно лишь отчасти. Поскольку, AbsoluteIndex это индекс в общем списке TreeView.Items, а не закреплённый "идентификатор узла".
>>>В результате экспериментов заметил какую-то закономерность
Закономерность индексов в TreeView можно проследить с помощью следующих процедур:
// TfvMain = class(TForm)
// trvTree: TTreeView;
const
cMaxItems = 5;
cNodeName = 'Node_';
procedure TfvMain.TreeClear;
begin
trvTree.Items.Clear
end;
procedure TfvMain.TreeInsert;
var wNode, wNode2 :TTreeNode;
begin
wNode := trvTree.Selected;
wNode2 := trvTree.Items.Insert(wNode, '');
NodeSetName(wNode2);
end;
procedure TfvMain.TreeLoad;
procedure NodeSetName( aNode :TTreeNode);
begin
aNode.Text := cNodeName +
//индекс локальный, уникальный в ветке дерева TreeNode.Item[]
IntToStr(aNode.Index) + '_' +
//индекс глобальный, уникальный по всему дереву TreeView.Items[]
IntToStr(aNode.AbsoluteIndex) + '_' +
//дескриптор узла (win api), уникальный по всему дереву
IntToHex(Integer(aNode.ItemId), 8);
end;
var
wNode, wNode2 :TTreeNode;
i, j :integer;
begin
with trvTree.Items do
begin
BeginUpdate;
for i := 1 to cMaxItems do
begin
wNode := Add(nil, '');
NodeSetName(wNode);
for j := 1 to cMaxItems do
begin
wNode2 := AddChild(wNode, '');
NodeSetName(wNode2);
end;
end;
trvTree.FullExpand;
EndUpdate;
end;
end;
Если, после выполнения TreeLoad, в середину дерева вставить новый элемент, то сдвинутся все AbsoluteIndex в TreeView.Items[] после этого элемента и Index в TreeNode.Item[] в локальной ветке, тоже после этого элемента.
Спасибо за ответ.
При добавлении (удалении)узлов, я понимаю, что индексы должны меняться. Но в конкретном случае дерево не меняется.
В результате экспериментов заметил какую-то закономерность, но не стал анализировать, т.к. переделал на Selected.AbsoluteIndex.
Теперь всё работает как ожидалось. Нет ли в таком подходе "подводных камней"?
>>>Хочу выделить (и раскрыть) узел, на котором произошло добавление. Но почему-то код ниже не работает. Выделяется соседний узел.
Поясню на примере.
Представьте, что у вас есть линейный массив, который вы загружаете значениями из БД. Вы отмечаете в массиве, например, элемент с № 5. И запоминаете этот №. Теперь вы перезагружаете содержимое массива из БД. А после этого вставляете новый элемент между элементами №3 и №4.
Очевидно, что под № 5, в массиве будет элемент с другим содержимым, чем в первом случае. А нужный вам элемент, будет соседним с ним (№ 6).
Возвращаясь к TreeView, можно сказать, что индекс i в TreeView.Items[i], это такой же аналог индекса в массиве. А ItemId - это уникальный идентификатор элемента. На практике, он реализован через авто-инкремент при добавлении нового элемента. Поэтому, когда вы перезагружаете TreeView из БД (т.е. сначала удаляете все элементы дерева, а затем их создаёте), значение ItemId элементов будет тоже новым.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.