![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
работа с treeview
123456 © (2010-09-20 14:10:00)Здравствуйте!
имеется дерево с узлами и подузлами, которое через определенный интервал времени(с помощью таймера) обновляется из базы. после обновления все узлы сворачиваются. как сохранить текущее состояние дерево, чтоб она оставалась без изменении. при обновлении дерево формируется с нуля. просто неудобно, когда рассматриваешь какой-то под узел и тут сразу обновляется и все сворачиваются, приходится все заново раскрывать.
Ega23 (2010-09-20 15:16:00) [1]
> можно ли по одному перебирать узлы в базе и затем проверить
> его в treeview на раскрытость и ставить значение в базе
> 0 или 1.
А ты возьми и сравни, что в данном случае менее затратно по времени: "сорок раз по разу" или "один раз сорок раз".
По времени будет очень долго.
linuxoid (2010-09-20 15:02:00) [2]можно ли по одному перебирать узлы в базе и затем проверить его в treeview на раскрытость и ставить значение в базе 0 или 1.
затем после обновления процедура сама будет проверять. по любому вначале будут раскрываться узлы, затем подузлы а дальше подподузлы. родитель подузла по любому не поменяется. подузел не будет раскрыт если его узел не раскрыт.
Ega23 (2010-09-20 14:47:00) [3]В случае TreeView нельзя никогда заранее предугадать, какой элемент будет отображён в качестве корня. Поэтому построение дерева возможно только в том случае, когда на клиент получен ВЕСЬ НД, целиком. Есть возможность задания всяких Order By, но это не совсем верно в идеологическом плане (ИМХО).
Далее. В случае дерева у тебя нет никакой гарантии того, что данные в хранилище не изменились. Т.е. даже если ты запомнишь всю "карту" раскрытых узлов, то нет никакой гарантии, что у какого-то узла не поменялся "родитель".
Поэтому, ИМХО, хранить полную карту - бессмысленно. Проще сохранять последний SelectedNodeID, после обновления НД ставить его Selected и раскрывать всё вверх до корня (ЕМНИП, в случае TTreeView это произойдёт автоматом).
Ega23 (2010-09-20 14:42:00) [4]
> а где написать процедуру запоминания и раскрытия?
Поясняю.
Если абстрагироваться от конкретных реализаций, то схема работы DB-Aware-компонентов примерно такова:
1. Сделали запрос к хранилищу данных, получили некий набор данных.
2. Перевели полученный набор данных в некую унифицированную структуру (например - в список рекордов)
3. На пользовательском компоненте отобразили видимую в данный моментчасть данных.
4. Связали каждый элемент своего контрола (строчка в DBGrid, узел в TreeView и т.д.) с конкретным элементом в своей унифицированной структуре.
linuxoid (2010-09-20 14:36:00) [5]вот исходник: вначале раскрываются родительские parentid=0. затем по цепочке и подузлы.
а где написать процедуру запоминания и раскрытия? придется по базе перебрать все узлы до обновления?
subjecttree.Items.BeginUpdate;
if subjecttree.Items.Count >0 then
begin
subjecttree.Items.Clear
end;
basequery.Active:=false;
basequery.SQL.Clear;
basequery.SQL.Text:='select *'+
'from node where parentid=:parentid';
basequery.Parameters.ParseSQL(basequery.SQL.Text,true);
basequery.Parameters.ParamByName('parentid').Value:=0;
try
baseconnect.Open;
basequery.Active:=true;
if basequery.RecordCount<>0 then
begin
while not basequery.Eof do
begin
TreeNode:=subjecttree.Items.AddObject(nil, basequery.Fields[2].asstring,
pointer(basequery.Fields[0].asinteger));
subjecttree.Items.AddChildObject(TreeNode ,'' , nil);
TreeNode.ImageIndex:=strtoint(basequery.Fields.Fields[3].asstring);
treenode.SelectedIndex:=treenode.ImageIndex;
basequery.Next;
end;
end; //if
finally
BaseConnect.Close; //Закрываем коннект
end;
SubjectTree.Items.EndUpdate; //Разрешить прорисовку
begin
BaseQuery.Active := false;
BaseQuery.SQL.Clear;
//Составление запроса и ввод параметров
//Выбираем элементы не имеющие родителя, т.е. корневые
BaseQuery.SQL.Text := 'SELECT NodeID, ParentID, NodeName, NodeType '+
'FROM node WHERE ParentID = :ParentID';
BaseQuery.Parameters.ParseSQL(BaseQuery.SQL.Text, true);
BaseQuery.Parameters.ParamByName('ParentID').Value := Integer(tn.Data);
BaseQuery.Active := true;
if BaseQuery.RecordCount <> 0 then
begin
while not BaseQuery.Eof do
begin
TreeNode := SubjectTree.Items.AddChildObject(tn,
BaseQuery.Fields[2].AsString,
Pointer(BaseQuery.Fields[0].AsInteger));
TreeNode.ImageIndex:=strtoint(basequery.Fields.Fields[3].asstring);
treenode.SelectedIndex:=treenode.ImageIndex;
BaseQuery.Next;
end; //while
Child := tn.getFirstChild;
while Child <> nil do
begin
FillBranch(Child);
Child := Child.GetNextSibling;
end;//while
end; //if
end; {FillBranch}
Ega23 (2010-09-20 14:27:00) [6]Писал в своё время DBTreeView.
Сразу замечание: Не надо обновлять по таймеру. Обновлять нужно по желанию пользователя, т.е. должна быть кнопка "Обновить".
Ну а с разворачиванием-сворачиванием всё просто: запоминаешь ID открытого элемента (не Node.ID, а ID из базы).
После перестроения дерева обходишь ноды, ищешь нужный по последнему ID, ставишь его Selected. Всё что "выше" - должно само раскрыться.