Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Проход по всему дереву FMX.TTReeView / 17 сообщений из 17, страница 1 из 1
03.04.2017, 20:24
    #39432334
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проход по всему дереву FMX.TTReeView
К сожалению у стандартного дерева в 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
03.04.2017, 20:25
    #39432335
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проход по всему дереву FMX.TTReeView
Да, я понимаю, что построение всего дерева сразу - не комильфо, а нужно строить по мере открытия узлов.
Но по дереву нужно организовать поиск, получается, что нужно его сперва построить.
...
Рейтинг: 0 / 0
03.04.2017, 22:45
    #39432410
JayDi
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проход по всему дереву FMX.TTReeView
X11,

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

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

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

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

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

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

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

FireBird c Андроидом плохо дружит
...
Рейтинг: 0 / 0
04.04.2017, 08:33
    #39432507
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проход по всему дереву FMX.TTReeView
Ребята, тут проблема не с базой данных, а с сами деревом. Нужно абстрагироваться от БД.
...
Рейтинг: 0 / 0
04.04.2017, 08:36
    #39432508
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проход по всему дереву FMX.TTReeView
В общем, дали пример. На большом количестве записей не знаю, будет ли медленная загрузка.
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
04.04.2017, 10:19
    #39432619
JayDi
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проход по всему дереву FMX.TTReeView
X11JaDiОднопроходный вариант работать не будет из-за того, что элементы могут создаваться в разное время (id идут не последовательно).

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

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

Код: 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
08.01.2018, 19:06
    #39580641
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проход по всему дереву FMX.TTReeView
При работе в 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
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Проход по всему дереву FMX.TTReeView / 17 сообщений из 17, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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