powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Проход по всему дереву FMX.TTReeView
17 сообщений из 17, страница 1 из 1
Проход по всему дереву FMX.TTReeView
    #39432334
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
К сожалению у стандартного дерева в Firemonkey нет возможность подключить таблицу типа "id, parent, name".
Поэтому приходится извращаться, чтобы заполнить дерево.
Зачем нужен проход по всему дереву? Чтобы найти к чему прикрепить очередной узел, т.е. найти родителя.

т.е. процедура построения дерева такая:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
function TfmTree.BuildTree: boolean;
Var
  TreeViewItem, TreeViewItemParent: TTreeViewItem;
begin
// 0 - id, 1- parent, 2 - name
// fmTree.qTree.SQL.Text := 'select id, parent, name from regions order by parent';

  if not qTree.Active then qTree.Open;
  if qTree.RecordCount <= 0 then exit(false);
  qTree.First;
  TreeView1.Clear;
  TreeView1.BeginUpdate;


  try
    while not qTree.Eof do
    begin
      if VarIsNull(qTree.Fields[1].Value) then
      begin
        AddChild(nil, qTree.Fields[2].Value, qTree.Fields[0].Value, TreeView1);// создаем root (нулевые)  TTreeViewItem`ы

      end
      else
      begin
        TreeViewItem := ItemByTag(qTree.Fields[1].Value);// ищем родителя, у которого tag = Fields[1]
        AddChild(TreeViewItem, qTree.Fields[2].Value, qTree.Fields[0].Value, TreeView1);// добавляем дочерний TTreeViewItem
      end;// else

      qTree.Next;
    end;// while

  finally
    TreeView1.EndUpdate;

  end;
  result := True;
end;




проблема с функцией ItemByTag:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
function TfmTree.ItemByTag(id: integer): TTreeViewItem;
var
  Item: TTreeViewItem;
  I: Integer;
begin
// взял как пример на основе ItemByText из исходников FMX
  Result := nil;
  for I := 0 to Pred(TreeView1.GlobalCount) do
  begin
    Item := TreeView1.ItemByGlobalIndex(I);
    if Item.Tag = id then
      Exit(Item);
  end;
end;


из-за того, что само дерево не предоставляет глобального индекса, а ClobalCount - это всего лишь "количество всех видимых элементов дерева (первого уровня и подэлементов) в этом древовидном представлении".
http://docwiki.embarcadero.com/Libraries/Berlin/en/FMX.TreeView.TCustomTreeView.GlobalCount


ну и собственно AddChild

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
Function TfmTree.AddChild(parent: TFMXObject; Text: string; key_val: integer; TreeView: TTreeView): TTreeViewItem;
begin
  Result := TTreeViewItem.Create(TreeView);

  if not assigned(parent) then
    Result.parent := TreeView
  else
    Result.Parent := parent;


  Result.Text:= text;
  Result.Tag := key_val;
  if not assigned(parent) then
    OutputDebugString(pwidechar('add: ' + Result.Text))
  else
    OutputDebugString(pwidechar('add: ' + TTreeViewItem(parent).Text + '.' + Result.Text));
end;




Мне предлагают какого-то монстра (EnumControls), чтобы пройтись по всему дереву:
http://docwiki.embarcadero.com/Libraries/Seattle/en/FMX.Controls.TControl.EnumControls
А как им пользоваться, моих мозгов скилов не хватает, чтобы переложить тамошний пример на мою задачу.
Заранее благодарен за любую помощь.

Может быть кто-то знает, как проще наполнить дерево FMX из таблицы?
Delphi 10.1 (multi-platform app)
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432335
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, я понимаю, что построение всего дерева сразу - не комильфо, а нужно строить по мере открытия узлов.
Но по дереву нужно организовать поиск, получается, что нужно его сперва построить.
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432410
Фотография JayDi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X11,

>> select id, parent, name from regions order by parent

Однопроходный вариант работать не будет из-за того, что элементы могут создаваться в разное время (id идут не последовательно). Можно использовать оракловский запрос для деревьев с connect by level, чтобы правильно отсортировать, либо делать заполнение в два прохода (сначала плоский список, а потом по родителям перемещаем -- я так у себя девовский трилист сортирую).
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432427
чччД
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X11,
хочешь TVirtualTreeView на FMX, славы и денег?

Портируй VTV на FMX!
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432430
чччД
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X11Да, я понимаю, что построение всего дерева сразу - не комильфо, а нужно строить по мере открытия узлов.
Но по дереву нужно организовать поиск, получается, что нужно его сперва построить.
Если ты все еще используешь FireBird (а также мс скл, оракл...) - примени CTE:

7067436
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432431
чччД
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X11, и для поиска вовсе нет нужды строить все дерево: ищи нужный узел в базе, потом вытягивай всю цепочку родителей (до корня), а потом, в дереве, начиная от корня, пробегись по цепочке в обратную сторону, если нужно, подгружая пока отсутсвующие элементы, в итоге ты быстро найдешь нужный узел без перебора всего дерева.
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432502
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JaDiОднопроходный вариант работать не будет из-за того, что элементы могут создаваться в разное время (id идут не последовательно).

у меня "order by parent", значит родители всегда будут раньше создаваться
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432505
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чччДхочешь TVirtualTreeView на FMX

я его боюсь
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432506
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чччДЕсли ты все еще используешь FireBird

на андроиде - SQLite

FireBird c Андроидом плохо дружит
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432507
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ребята, тут проблема не с базой данных, а с сами деревом. Нужно абстрагироваться от БД.
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432508
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем, дали пример. На большом количестве записей не знаю, будет ли медленная загрузка.
http://fire-monkey.ru/topic/4018-цикл-по-ttreeview-обходит-не-все-уровни/?do=findComment&comment=25397

Работает.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
Function TfmTree.ItemByTag(id_parent: integer): TTreeViewItem;
var
  aItem: TTreeViewItem;
begin
  aItem := nil;

  TreeView1.EnumControls(
    function(Control: TControl): TEnumControlsResult
    begin
      if (Control is TTreeViewItem) then
      begin
        if TTreeViewItem(Control).Tag = id_parent then
        begin
          aItem  := TTreeViewItem(Control);
          Result := TEnumControlsResult.Discard;
        end
        else
          Result := TEnumControlsResult.Continue;
      end
      else
        Result := TEnumControlsResult.Continue;
    end);

  Result := aItem;
end;
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432619
Фотография JayDi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X11JaDiОднопроходный вариант работать не будет из-за того, что элементы могут создаваться в разное время (id идут не последовательно).

у меня "order by parent", значит родители всегда будут раньше создаваться
Нет, не будут. Если поменяется структура дерева (какую-то ветку перебросят на уровень выше), всё накроется медным тазом.
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432625
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кто перебросит?
Кто перебросит в момент построения дерева?
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432650
Фотография JayDi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
X11,

речь про дерево в базе данных, которое может измениться или быть записанным совсем не в той последовательно, которая нам удобна.
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39432711
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не забывайте, что речь не про сетевое приложение, а про локальное.
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39580630
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Может кому-то пригодится.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
function BuildTree(TreeView1: TTreeView; qTree: TUniQuery): boolean;
Var
  TreeViewItem: TTreeViewItem;
begin
  qTree.close;
  qTree.Open;// select id, parent, name
  if qTree.RecordCount <= 0 then exit(false);
  qTree.First;
  TreeView1.Clear;
  TreeView1.BeginUpdate;

  try
    while not qTree.Eof do
    begin
      if VarIsNull(qTree.Fields[1].Value) then
        AddChild(nil, qTree.Fields[2].Value, qTree.Fields[0].Value, TreeView1)
      else
      begin
        TreeViewItem := ItemByTag(TreeView1, qTree.Fields[1].Value);
        TreeViewItem.Name := 'TreeViewItem' + qTree.Fields[1].AsString;
        TreeViewItem.Height := 40;
        AddChild(TreeViewItem, qTree.Fields[2].Value, qTree.Fields[0].Value, TreeView1);
      end;// else

      qTree.Next;
    end;// while

  finally
    TreeView1.EndUpdate;

  end;
  result := True;
end;


procedure AddChild(parent: TFMXObject; Text: string; key_val: integer; TreeView: TTreeView);
Var
 TreeViewItem: TTreeViewItem;
 ALabel: TLabel;
begin
  TreeViewItem := TTreeViewItem.Create(TreeView);
  TreeViewItem.Name := 'TreeViewItem' + key_val.ToString;
  TreeViewItem.StyleLookup := 'treeviewitemstyle';

  if not assigned(parent) then
    TreeViewItem.parent := TreeView
  else
    TreeViewItem.Parent := parent;

  ALabel := TLabel.create(TreeViewItem);
  ALabel.Parent := TreeViewItem;
  ALabel.Align := TAlignLayout.Right;
  ALabel.TextSettings.HorzAlign := TTextAlign.Trailing;
  ALabel.Text := key_val.ToString;
//  ALabel.Padding.Right := 5;

  TreeViewItem.Text:= text;
  TreeViewItem.Tag := key_val;
end;


Function ItemByTag(TreeView1: TTreeView; id_parent: integer): TTreeViewItem;
var
  aItem: TTreeViewItem;
begin
  aItem := nil;

  TreeView1.EnumControls(
    function(Control: TControl): TEnumControlsResult
    begin
      if (Control is TTreeViewItem) then
      begin
        if TTreeViewItem(Control).Tag = id_parent then
        begin
          aItem  := TTreeViewItem(Control);
          Result := TEnumControlsResult.Discard;
        end
        else
          Result := TEnumControlsResult.Continue;
      end
      else
        Result := TEnumControlsResult.Continue;
    end);

  Result := aItem;
end;


Function FindItemByText(val: String; TreeView: TTreeView): TTreeViewItem;
var
  aItem: TTreeViewItem;
begin
  aItem := nil;
  val := AnsiUpperCase(val);

  TreeView.EnumControls(
    function(Control: TControl): TEnumControlsResult
    begin
      if (Control is TTreeViewItem) then
      begin
        if ContainsText((TTreeViewItem(Control).Text), val) then
        begin
          aItem  := TTreeViewItem(Control);
          Result := TEnumControlsResult.Discard;
        end
        else
          Result := TEnumControlsResult.Continue;
      end
      else
        Result := TEnumControlsResult.Continue;
    end);

  Result := aItem;
end;


procedure SelectItemByText(const sText: String; TreeView: TTreeView);
var
 TreeViewItem: TTreeViewItem;
begin
  TreeViewItem := FindItemByText(sText, TreeView);
  if assigned(TreeViewItem) then
    TreeViewItem.Select;
end;
...
Рейтинг: 0 / 0
Проход по всему дереву FMX.TTReeView
    #39580641
Фотография X11
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
При работе в Firemonkey с TTreeViewItem нужно помнить, что есть Parent, а есть ParentItem.
Т.е. если нужен цикл по родителям, то нужно шагать по ParentItem

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
function GetPathFromTreeViewItem(AItem: TTreeViewItem): String;
begin
  if AItem = nil then exit('nothing selected');

  while Assigned(AItem) and (AItem is TTreeViewItem) do
  begin
    Result := AItem.Text + '\' + Result;
    AItem := TTreeViewItem(AItem.ParentItem);
  end;

  Delete(Result, Length(Result), 1);
end;
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Проход по всему дереву FMX.TTReeView
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]