[ТЕМА ЗАКРЫТА]
22.08.2007 18:28
Петя
 
Всем известный шаблон классификатора супермага содержит следующую информацию
Id Tree Name

Например

1 1. Мясо
2 1.1. Говядина
3 1.2. Свинина

Пытаюсь реализовать классификатор компонентом TreeView в Делфи.
Пока получилось только упрощенным двойным перебором, работает при
1000 ветках примерно секунд 5-7, если веток 10000-15000 работает долго.
Интересно какие алгоритмы могут предложить участники форума.
Возможно предварительно загрузить в файл... Или как то рекурсивно
подойти...
23.08.2007 13:18
dmware
 
Цитата:
Петя Всем известный шаблон классификатора супермага содержит следующую информацию
Id Tree Name

Например

1 1. Мясо
2 1.1. Говядина
3 1.2. Свинина

Пытаюсь реализовать классификатор компонентом TreeView в Делфи.
Пока получилось только упрощенным двойным перебором, работает при
1000 ветках примерно секунд 5-7, если веток 10000-15000 работает долго.
Интересно какие алгоритмы могут предложить участники форума.
Возможно предварительно загрузить в файл... Или как то рекурсивно
подойти...
А разве это настолько существенный момент?
Можно создавать форму при запуске приложения, заполняя при этом TreeView (один единственный раз).
Еще... Не видел кода... поэтому все-таки посоветую: отключи автообновление при заполнении дерева. .Items.BeginUpdate()/.Items.EndUpdate()

Просто интересно: "Упрощенный двойной перебор" - это как?
23.08.2007 15:20
YuraZ
 
Я бы предложил использовать TVirtualTreeView от Mike Lischke (. Попробуй просто добавить 10000 записей в стандартный TreeView и ты поймешь почему у тебя тормоза - это сам TreeView тормозит.
Ну а по алгоритму - подгружай только те строки классификатора, которые видны в данный момент на экране. Т.е. первоначально отбираешь все группы первого уровня. В момент разворачивания одной из них, подтягиваешь из базы группы расположенные в ней и отображаешь. При сворачивании группы - удаляешь вложенные подгруппы.
23.08.2007 15:38
dmware
 
Цитата:
YuraZ Я бы предложил использовать TVirtualTreeView от Mike Lischke (. Попробуй просто добавить 10000 записей в стандартный TreeView и ты поймешь почему у тебя тормоза - это сам TreeView тормозит.
Хотелось бы еще раз заострить внимание на следующем (возможно дело именно в этом)
Если попробовать поступить так:
Код:
TreeView.Items.Add(nil, [Наименование узла])
будет добавлен очередной элемент, после чего автоматически будет выполнена перерисовка.
Чтобы запретить компоненту перерисовываться вплоть до добавления последнего элемента используются упомянутые мною методы BeginUpdate() (До того, как элементы начнут добавляться) и EndUpdate() (После того, как процедура будет завершена)
Таким образом, "тормоза" должны будут стать менее очевидными, ведь мы избавляем компонент от необходимости перерисовки такое количество раз, сколько элементов к нему добавляем.
Конечно же, самую важную роль играет еще и сам алгоритм, по которому будут извлечены/добавлены элементы...
23.08.2007 15:46
YuraZ
 
Цитата:
dmware Хотелось бы еще раз заострить внимание на следующем (возможно дело именно в этом)
Если попробовать поступить так:
Код:
TreeView.Items.Add(nil, [Наименование узла])
будет добавлен очередной элемент, после чего автоматически будет выполнена перерисовка.
Чтобы запретить компоненту перерисовываться вплоть до добавления последнего элемента используются упомянутые мною методы BeginUpdate() (До того, как элементы начнут добавляться) и EndUpdate() (После того, как процедура будет завершена)
Таким образом, "тормоза" должны будут стать менее очевидными, ведь мы избавляем компонент от необходимости перерисовки такое количество раз, сколько элементов к нему добавляем.
Конечно же, самую важную роль играет еще и сам алгоритм, по которому будут извлечены/добавлены элементы...
Это понятно. Но уже давным давно выяснено, что основная проблема TreeView в том, что он не предназначен для отображения большого кол-ва узлов - тормозит дико. Я в свое время с этим столкнулся. Добавил в классификатор для теста 10.000 записей и ошалел. После перехода на указанный ранее VirtualTreeView скорость заполнения 10.000 записей ~1 секунда.
23.08.2007 15:52
Петя
 
Цитата:
подгружай только те строки классификатора, которые видны в данный момент на экране. Т.е. первоначально отбираешь все группы первого уровня. В момент разворачивания одной из них, подтягиваешь из базы группы расположенные в ней и отображаешь. При сворачивании группы - удаляешь вложенные подгруппы.
Гениально, спасибо за идею
23.08.2007 15:54
dmware
 
Цитата:
YuraZ Это понятно. Но уже давным давно выяснено, что основная проблема TreeView в том, что он не предназначен для отображения большого кол-ва узлов - тормозит дико. Я в свое время с этим столкнулся. Добавил в классификатор для теста 10.000 записей и ошалел. После перехода на указанный ранее VirtualTreeView скорость заполнения 10.000 записей ~1 секунда.
Интересно. Нужно будет посмотреть в свободное время.
23.08.2007 15:54
Петя
 
Цитата:
Можно создавать форму при запуске приложения, заполняя при этом TreeView (один единственный раз).
А если другой пользователь после загрузки TreeView
скажем удалил ветку,
а мы будем пользоваться "старым" TreeView
23.08.2007 15:59
Петя
 
Цитата:
Просто интересно: "Упрощенный двойной перебор" - это как?
Возможно неправильно выразился, т е алг со сложностью n^2,
взяли первый просмотрели все,
взяли второй просмотрели все,
..
"упрощенный" - я имел в виду, что просматривать все не надо, ветки отсортированны специальным образом, что после первого мы практически сразу находим то что нужно
23.08.2007 16:07
Петя
 
Цитата:
Я бы предложил использовать TVirtualTreeView от Mike Lischke (.
Сори, где там чего скачивать чего то не найду
23.08.2007 16:08
YuraZ
 
Цитата:
Петя А если другой пользователь после загрузки TreeView
скажем удалил ветку,
а мы будем пользоваться "старым" TreeView
Тут уже не важно каким TreeView мы будем пользоваться :)
В худшем случае, после сворачивания ветки ты очистишь ее содержимое, а при попытке развернуть ее заново, окажется, что у нее внутри нет ничего. Конечно в этом случае перед попыткой добавления в такую группу новых узлов надо проверить существует ли сама эта группа.
23.08.2007 16:18
YuraZ
 
Цитата:
Петя Сори, где там чего скачивать чего то не найду
Извиняюсь. У них изменился адрес
29.04.2008 11:54
karachun
 
вот последние что я сделал по этой теме. Работает через ADO, но это вообще непринципиально. Работает с любым классификатором СМ. Работает очень быстро!!!
1. Создал юнит :
Код:
unit Unit_ProceduresAndFunctions_TreeP;

interface

uses
  Windows, SysUtils, Forms, ComCtrls, StdCtrls, DB, ADODB, DBTables, Classes;

type
  pADOQyery = ^TADOQuery;
  pStringStream = ^TStringStream;

{Процедуры}
procedure chTreeClassifierP(NameTableClassifier: PString; QueryName: pADOQyery; ResultStringStream: pStringStream);

implementation

procedure chTreeClassifierP(NameTableClassifier: PString; QueryName: pADOQyery; ResultStringStream: pStringStream);
function QuantitySymbolsInString(Line, Symbol: PString) : Integer;
var
    i: Integer;
begin
  Result:=0;
  for i:=1 to Length(Line^) do
  begin
    if Line^[i] = Symbol^ then
    begin
      inc(Result);
    end;
  end;
end;
var
  i, CurrentLevel, MaxLevel: Integer;
  StringForStream,l,s: String;
begin
  //Определяем максимальный уровень вложенности дерева
  //Изначально задаём максимальный уровень вложенности дерева 0
  MaxLevel:=0;
  //Подготавлеваем запрос
  QueryName^.SQL.Clear;
  QueryName^.SQL.Add('select TREE from ' + NameTableClassifier^);
  //Выполняем запрос
  QueryName^.Open;

  //Пробегаем по запросу и определяем максимальный уровень вложенности дерева
  s:='.';
  while not QueryName^.Eof do
  begin
    l:=QueryName^.FieldByName('TREE').AsString;
    CurrentLevel:=QuantitySymbolsInString(@l,@s);
    if MaxLevel < CurrentLevel then
    begin
      MaxLevel:=CurrentLevel;
    end;
    QueryName^.Next;
  end;
  //Закрываем запрос
  QueryName^.Close;

  //Подготавлеваем запрос на выборку из вьювера со структурой дерева
  QueryName^.SQL.Clear;
  QueryName^.SQL.Add('select ID,TREE,NAME,');
  for i:=0 to MaxLevel - 1 do
  begin
    QueryName^.SQL.Add('nvl(To_number(substr(Classifier.GetTreeItem(tree,'+IntToStr(i)+'),1,Length(Classifier.GetTreeItem(tree,'+IntToStr(i)+'))-1)),0) as Item' + IntToStr(i));
    if i <> MaxLevel - 1 then
    begin
      QueryName^.SQL.Add(',');
    end;
  end;
  QueryName^.SQL.Add(' from ' + NameTableClassifier^ + ' order by ');
  for i:=0 to MaxLevel - 1 do
  begin
    QueryName^.SQL.Add('Item'+IntToStr(i));
    if i <> MaxLevel - 1 then
    begin
      QueryName^.SQL.Add(',');
    end;
  end;
  //QueryName^.SQL.SaveToFile('d:\cardclass.sql');
  //Выполняем запрос
  QueryName^.Open;

  //Пробегаем по запросу и заполняем строковый поток
  s:='.';
  while not QueryName^.Eof do
  begin
    l:=QueryName^.FieldByName('TREE').AsString;
    CurrentLevel:=QuantitySymbolsInString(@l,@s);
    StringForStream:='';
    for i:=0 to CurrentLevel - 1 do
    begin
      StringForStream:=StringForStream + ' ';
    end;
    if QueryName^.FieldByName('TREE').AsString <> '#' then
    begin
      StringForStream:=StringForStream + QueryName^.FieldByName('TREE').AsString + ' ';
    end;
    StringForStream:=StringForStream + QueryName^.FieldByName('NAME').AsString + char(13);
    ResultStringStream^.WriteString(StringForStream);
    QueryName^.Next;
  end;
  //Закрываем запрос
  QueryName^.Close;
  //Устанавливам позицию потока в начало
  ResultStringStream^.Position:=0;
end;

end.
2. Вызываем так :
Код:
procedure TForm_Card.FormCreate(Sender: TObject);
var
  TreeStringStream: TStringStream;
  NameTableClassifier: String;
begin
...
  //Создаём поток
  TreeStringStream:=TStringStream.Create('');
  //Задаём имя таблицы
  NameTableClassifier:='sacardclass';
    //в процедуру передаём всё как указатели на объекты
chTreeClassifierP(@NameTableClassifier,@ADOQuery_CardClass,@TreeStringStream);
  //загрузаем в деревово содержимое потока
  TreeView_CardClass.LoadFromStream(TreeStringStream);
  // ну и "KILLALL"
  ADOQuery_CardClass.Close;
  TreeStringStream.Free;
...
end;
Если чтото не заработает пишите я проверю и исправлю. Т.е. у меня то работает на 100%, может я сдесь ошибся.
Опции темы


Часовой пояс GMT +3, время: 23:51.

 

Форум сделан на основе vBulletin®
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd. Перевод: zCarot и OlegON
В случае заимствования информации гипертекстовая индексируемая ссылка на Форум обязательна.