24 окт. 2015 г.

Изучайте используемый инструментарий!

   Вчера начал разбираться с чужим проектом на Delphi 7. Система весьма сложная – несколько взаимосвязанных АРМов по 20-50 форм (а может и больше, точно не считал). Усложняет все то, что она разрабатывается уже давно и пережила смену нескольких команд разработчиков. Каждая команда приносила в проект свои инновации. Например, одна из них перевела доступ к БД Oracle с BDE на ADO. При этом все старые объекты для работы с базами через BDE (TDatabase, TTable, TQuery и TStoredProc) продолжают лежать на формах рядом с их копиями для работы через ADO (TADOConnection, TADOTable, TADOQuery и TADOStoredProc). Они даже клонировали объекты TDataSource для ADODataSet'ов. Все замеченные беглым взглядом "интересные" моменты перечислять не буду, а вернусь к заголовку этой заметки. Одна из команд добавила в проект DBGridEh из EhLib 6.0 в компанию к стандартному DBGrid'у. Хороший выбор grid'а, одобряю ;-) Хочу поделится с вами их реализацией сортировки по клику на заготовке колонки. К каждому DBGridEh'у, подчеркиваю - к каждому DBGridEh'у, был написан обработчик OnSortMarkingChanged:
...
dsXYZ: TDataSource;
gridXYZ: TDBGridEh;
...
procedure TfmMain.gridXYZSortMarkingChanged(Sender: TObject);
var
  i: Integer;
  s: String;
  b: TBookmark;
begin
  Screen.Cursor := crHourGlass;
  b := dsXYZ.DataSet.GetBookmark;
  s := '';
  for i := 0 to gridXYZ.SortMarkedColumns.Count - 1 do
    begin
     s := s + gridXYZ.SortMarkedColumns[i].FieldName;
     if (gridXYZ.SortMarkedColumns[i].Title.SortMarker = smDownEh) then
        s := s + ' DESC';
     s := s + ';';
    end;
  TADODataSet(dsXYZ.DataSet).IndexFieldNames := s;
  dsXYZ.DataSet.GotoBookmark( b );
  Screen.Cursor := crDefault;
end;
   В одном из АРМ'ов только на главной форме больше 20 DBGridEh'ов лежащих на страницах TNotebook. И на каждый был написан свой обработчик! Если говорить о Delphi, или о объектно-ориентированном программировании в целом, то почему бы все эти десятки одинаковых обработчиков не заменить на один, где вместо gridXYZ использовать TDBGridEh(Sender) (или (Sender as TDBGridEh)), а вместо dsXYZ.DataSet использовать TDBGridEh(Sender).DataSet? Но самое интересное, что для сортировки в DBGridEh и такого обработчика писать не надо. EhLib для автоматической сортировки данных в DataSet'е имеет набор специальных объектов и от программиста требуется только добавить в раздел "uses" любого модуля в проекте один из модулей EhLibXXX (EhLibBDE, EhLibADO, EhLibCDS... в зависимости от подключенного к grid'у DataSet'а). Таким образом, вместо написания и копипаста десятков обработчиков OnSortMarkingChanged нужно было всего лишь подключить к проекту небольшую юниту EhLibADO.

   Еще, как зануда, отмечу, что вещи в стиле
Screen.Cursor := crHourGlass;
... 
Screen.Cursor := crDefault;
необходимо использовать совместно с конструкцией Try...Finally...End, т.к. если между этими строчками во время выполнения программы произойдет ошибка, то курсор не будет восстановлен. Т.е. нужно было написать так:
Screen.Cursor := crHourGlass;
Try
 ...
Finally
 Screen.Cursor := crDefault;
End
   А еще к восстановлению курсора в блок Finally...End было бы неплохо, для высвобождения памяти распределенной при вызове GetBookmark, добавить DataSet.FreeBookmark(b). Это же элементарно – для всех изменяемых или создаваемых ресурсов, на случай ошибки, нужно гарантировать возвращение их к исходному состоянию или высвобождению занимаемой ими памяти.

   Так, что господа, те кто считает себя программистом, дружите с Try...Finally...End и главное - ИЗУЧАЙТЕ ИСПОЛЬЗУЕМЫЙ ИНСТРУМЕНТАРИЙ!!!

2 комментария:

vsmihaylovsky комментирует...

Насчет восстановления курсора по выходу из функции, недавно была статья: http://www.tdelphiblog.com/2015/09/LazyCursorHelper.html

Я использую фибы у себя - там FreeBookmark ничего не делает, его можно не использовать.

У меня тоже есть подобный случай и тоже с EhLib связан. У меня в проекте оказался EhLib 3~, со своими правками в коде грида и еще каких то файлов. Правки были для черезстрочной раскраски и для сортировки (оба вопроса решаются и без таких правок конечно же :) ). Причем для сортировки использовались прямые ссылки на модули (формы справочников например).
В итоге при переходе на ХЕ2, самым сложным оказался не какой то там юникод, а перевод программы на новый EhLib.

Чорны кашак комментирует...

TLazyCursorHelper :) у меня подобный класс называется TScreenCursor :)

В Delphi 7 FreeBookmark не пустой, о его пустоте в следующих версиях я писал в заметке "Delphi 2010: TDataSet.FreeBookmark – рудимент" http://it-blackcat.blogspot.com.by/2010/03/delphi-2010-tdatasetfreebookmark.html