Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Как упростить работу с TTreeView?

375
21 июня 2007 года
dominator
199 / / 16.10.2003
Здравствуйте!
Подскажите пожалуйста, как упростить работу с TTreeView. Ситуация следующая...
В указанном компоненте - разделы программы. Рядом DBGrid.
Кликаем по узлу - выполняется соответствующий запрос. Грид обновляется. Теперь: одновременно с этим выполняется целый ряд процедур. Некоторые из них что-либо добавляют к запросу перед его выполнением в зависимости от состояния программы, или же совершают иные манипуляции.
Что приходится делать: в каждой процедуре оператор case, который прогоняет проверку с целью определения выделенного пользователем узла. Упрощенно:
 
Код:
case NodeId of
  //Узел 1, 2 ... n
end;

А теперь добавляем к дереву новый узел. И приходится каждую такую процедуру модифицировать. Очень неудобно.
Как сделать это грамотно (как можно меньше телодвижений при достижении того же результата:)
1.9K
21 июня 2007 года
Borland_prog
149 / / 25.01.2006
скажи конкретно какая задача преследуется.
Необходимо, говоря языком формальной математики сделать отображение, которое и будет преобразовать номер выделенного узла в необходимую информацию.
10
21 июня 2007 года
Freeman
3.2K / / 06.03.2004
Цитата: dominator
Что приходится делать: в каждой процедуре оператор case, который прогоняет проверку с целью определения выделенного пользователем узла.


Нужно пользоваться свойством TTreeView.Selected и TTreeNode.Data. В последнюю загоняешь указатель на произвольные данные, нужные для реализации логики программы - для этого и предусматривалось свойство.

375
21 июня 2007 года
dominator
199 / / 16.10.2003
Цитата: Borland_prog
скажи конкретно какая задача преследуется.
Необходимо, говоря языком формальной математики сделать отображение, которое и будет преобразовать номер выделенного узла в необходимую информацию.



Цитата: Freeman
Нужно пользоваться свойством TTreeView.Selected и TTreeNode.Data. В последнюю загоняешь указатель на произвольные данные, нужные для реализации логики программы - для этого и предусматривалось свойство.



Можно поподробнее? Хотя бы с простеньким примером.

У меня сейчас так:

Код:
(*Определяю наименование активной (выбранной оператором) подсистемы
 Прогоняю массив со структурой-описателем т.н. подсистемы,
 чтобы понять, что выделил пользователь (поле sName)
*)
   for i := 0 to Length(ocUser.arrtSubSystemNodes) - 1 do begin
      if(ocUser.arrtSubSystemNodes.sTitle = TreeView_SectionTreeMain.Selected.Text) then begin
//Процедура откроет редактор для данной подсистемы
         OpenViewerForSubSystem(ocUser.arrtSubSystemNodes.sName, enNewRec);
         break;
      end;
   end;

//Далее...
procedure OpenViewerForSubSystem(sSubSystemName :String; nFormMode :TFormMode);
var
  ...
begin
if(sSubSystemName = {Идентификатор подсистемы})then begin
      case nFormMode of //Смотрим, в каком режиме следует открыть редактор
         enNewRec:
         begin
         //Новая запись: создаем экземпляр соответствующей
формы (редактор для каждой подсистемы свой) в
нужном режиме. Иногда для каждого из режимов - своя форма
         end;
//и т.д.
end;

Вот, что я имел ввиду. Как видите все не очень эффективно:(
Подсистем (в данном случае узлов) много. В зависимости от того, где мы находимся определенное действие должно отработать определенным образом (например как в примере вызов редактора). Таких процедур предостаточно и в каждой приходится организовывать проверку. В некоторых узлах для каждого из режимов (например, "новая запись", редактирование и т.д.) своя специфическая форма - редактор.
Как все это оптимизировать до более-менее приемлимого уровня? Программа растет, и малейшее изменение (как уже упоминалось, добавление нового узла) довольно болезненно. Хотелось бы "вылечить" код, пока это не стало слишком трудоемко.
1.9K
22 июня 2007 года
Borland_prog
149 / / 25.01.2006
а не проше ли будет если не строки сравнивать а номера
присвоить каждой подсистеме свой номер, который будет соответствовать свойству TTreeNode.Index и тогда вот этот перебор не нужен
 
Код:
for i := 0 to Length(ocUser.arrtSubSystemNodes) - 1 do begin
      if(ocUser.arrtSubSystemNodes.sTitle = TreeView_SectionTreeMain.Selected.Text) then begin
//Процедура откроет редактор для данной подсистемы
         OpenViewerForSubSystem(ocUser.arrtSubSystemNodes.sName, enNewRec);
         break;
      end;
   end;


а просто
 
Код:
OpenViewerForSubSystem(TreeView_SectionTreeMain.Selected.Index, enNewRec);


Тогда функция такая:
Код:
//Далее...
procedure OpenViewerForSubSystem(sSubSystemIndex :Integer; nFormMode :TFormMode);
var
  ...
begin
case sSubSystemName of {Идентификатор подсистемы}
     1: EditorOpen(nFormMode);
     2: ...
     ....
     N:...
//и т.д.
end;


И разбиваем все на мелкие функции:
 
Код:
procedure EditorOpen(nFormMode: TFormMode);
begin
         case nFormMode of //Смотрим, в каком режиме следует открыть редактор
         enNewRec: NewRecord; // вызываем функцию новой записи
         enDelRec: DelRecord; // к примеру
         end;
end;
375
22 июня 2007 года
dominator
199 / / 16.10.2003
Цитата: Borland_prog
а не проше ли будет если не строки сравнивать а номера
присвоить каждой подсистеме свой номер, который будет соответствовать свойству TTreeNode.Index и тогда вот этот перебор не нужен
 
Код:
for i := 0 to Length(ocUser.arrtSubSystemNodes) - 1 do begin
      if(ocUser.arrtSubSystemNodes.sTitle = TreeView_SectionTreeMain.Selected.Text) then begin
//Процедура откроет редактор для данной подсистемы
         OpenViewerForSubSystem(ocUser.arrtSubSystemNodes.sName, enNewRec);
         break;
      end;
   end;


а просто
 
Код:
OpenViewerForSubSystem(TreeView_SectionTreeMain.Selected.Index, enNewRec);



Конечно, так упрощается процедура определения узла.
Какое-то время делал так. С чем столкнулся.
Индекс может иногда меняться. Пример:
Подсистема А является дочерней для B. Ее индекс там с учетом присутствующих иных узлов, скажем, третий.
Изменилось что-то, указанная подсистема А переместилась, стала дочерней для С, где уже десяток узлов. Индекс стал другим.
К примеру, применительно к моей программе, какой-то определенный отчет относился к разделу "Бухгалтерские", затем чуть поменялся порядок расчета остатков - и вот он по логике уже Менеджерский, и предполагается что использовать его станут другие люди, имеющие доступ к другой ветке...
На первых порах узлы постоянно меняли родителей:) - особенности программирования без четко описанного тех.задания.
Таким образом, идентификатор, который к тому же выступает индексом узла, использовать (в моей программе, по крайней мере) оказалось не рационально...

375
22 июня 2007 года
dominator
199 / / 16.10.2003
Цитата: Freeman
Нужно пользоваться свойством TTreeView.Selected и TTreeNode.Data. В последнюю загоняешь указатель на произвольные данные, нужные для реализации логики программы - для этого и предусматривалось свойство.



Здорово, спасибо!
Вот, выбрал время, порылся в инете. Нашел страничку с примером:
http://www.az-design.ru/Support/SoftWare/Delphi/D3/SB19Data.shtml

Еще не успел попробовать.
Таким образом, можно каждому узлу в данном свойстве прописать его id (цифровой, или строковый). И можно будет убрать процедуру перебора элементов.

Но это не избавит о необходимости перебора в процедуре procedure OpenViewerForSubSystem(sSubSystemIndex :Integer; nFormMode :TFormMode);

Для каждого раздела - разные редакторы.
Первое, что приходит на ум, хранить в бд имя класса формы, которую нужно открывать.
Что -то типа:

 
Код:
--id----FromClass--
--1----TfrmJournalsEventsViewer--

Тогда можно будет вообще обходится без case. Разве что перебирать различные режимы (пожалуй, действительно удобно разбить эту большую функцию на более мелкие):
Цитата: Borland_prog
...
Тогда функция такая:
Код:
//Далее...
procedure OpenViewerForSubSystem(sSubSystemIndex :Integer; nFormMode :TFormMode);
var
  ...
begin
case sSubSystemName of {Идентификатор подсистемы}
     1: EditorOpen(nFormMode);
     2: ...
     ....
     N:...
//и т.д.
end;


И разбиваем все на мелкие функции:
 
Код:
procedure EditorOpen(nFormMode: TFormMode);
begin
         case nFormMode of //Смотрим, в каком режиме следует открыть редактор
         enNewRec: NewRecord; // вызываем функцию новой записи
         enDelRec: DelRecord; // к примеру
         end;
end;


Может еще как-то проще можно?

10
22 июня 2007 года
Freeman
3.2K / / 06.03.2004
Цитата: dominator
Может еще как-то проще можно?


Инкапсулировать нужную функциональность в классы и полностью отказаться от внешних case. В ООП-программах множественное ветвление допустимо только при обработке данных, поступающих извне, в частности, оконных сообщений. Если классам требуется установить начальные значения некоторых свойств, описать тип-запись, в которой указать все параметры, а в Data пихать указатель на неё.

В общем случае императивные методики подразумевают использование указателей (явных или неявных) в тех местах, где в реляционных моделях используется ID.

375
22 июня 2007 года
dominator
199 / / 16.10.2003
Цитата: Freeman
Инкапсулировать нужную функциональность в классы и полностью отказаться от внешних case. В ООП-программах множественное ветвление допустимо только при обработке данных, поступающих извне, в частности, оконных сообщений. Если классам требуется установить начальные значения некоторых свойств, описать тип-запись, в которой указать все параметры, а в Data пихать указатель на неё.

В общем случае императивные методики подразумевают использование указателей (явных или неявных) в тех местах, где в реляционных моделях используется ID.



Ясно. Есть над чем поработать.
Спасибо!

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог