BSGrid – Создаём собственный DBgrid. Часть 2.

2010-06-23 papirosnik Delphi

Итак, в первой части цикла статей, посвящённому написанию собственных компонентов в Delphi и C++ Builder мы создали и зарегистрировали в палитре новый компонент BSGrid — наследник стандартного DBGrid (http://papirosnik.info/2010/06/bsgrid-sozdayom-sobstvennyj-dbgrid-chast-1/).

Теперь будем расширять функционал, приближая его к функционалу платного компонента DBgridEh из библиотеки EhLib. Первое, что я хочу сделать — это подсветку всей активной строки (в той, которой находится ячейка с фокусом). Подсветку будем делать каким-либо цветом, отличным от цвета фона активной ячейки (По умолчанию в стандартной теме  тёмно-синий).

Т.е. мы будем делать что-то вроде этого: 

Как видно на рисунке, подсвечена не только сфокусированная ячейка, но и остальные ячейки принадлежащие той же строке. Я нахожу это более удобным для восприятия, особенно в том случае, когда в таблице содержится много строк со схожим по начертанию текстом в ячейках и/или они выведены маленьким шрифтом с небольшим расстоянием между строками.

Чтобы добиться такого функционала давайте сначала создадим простейшее тестовое приложение. Если ещё не скомпилировали и не установили на палитру компонент BSGrid — обратитесь к части первой этого цикла статей (ссылка вверху). Мы же создаём VCL Form Application. Переименовываем форму в frmMain (согласно нашему соглашению), кладём на неё наш компонент BSGrid и кнопку (назовём ей btnOpen). Чтобы наш BSGrid отображал данные, покладём на форму также компоненты ClienDataSet и DataSource из вкладки Data Access. ClientDataSet назовём cdsMain и щёлкнем по нему два раза мышкой. В открывшемся редакторе полей правым кликом добавляем новые поля (New Fileld): ID (тип Integer), NAME (тип String, длина 20), ADDRESS (тип String, длина 40), REMARK (тип string, длина 20). Конечно вы вольны тестировать компоненту как угодно, но если вы новичок в деле их написания, можете слепо повторять мои действия. DataSource переименуем в dsMain и в инспекторе свойств для него в поле DataSet выбираем из выпадающего списка наш cdsMain. И наконец в BSGrid1 в инспекторе свойств для поля DataSource выбираем dsMain. Таким образом цепочка связей между ClientDataSet, DataSource и BSGrid выглядит следующим образом: BSGrid1.DataSource = dsMain; dsMain.DataSet = cdsMain.

Осталось написать обработчик для btnOpen. Не мудрствуя лукаво предлагаю такой:

1
2
3
4
5
6
7
procedure TfrmMain.btnOpenClick(Sender: TObject);
var i: integer;
begin
 cdsMain.CreateDataSet;
 for I := 0 to 7 do
  cdsMain.AppendRecord([i]);
end;

Здесь мы открыли пустой ClienDataSet И добавили в него восемь записей с номерами 0-7. Но пока мы видим стандартное поведение DBGrid. Выделена только сфокусированная ячейка, а ячейки справа и слева от неё имеют стандартный цвет (по умолчанию белый). Теперь вернёмся к модификации нашего компонента. Закроем (сохранив) тестовый проект и откроем проект, в котором сохранён модуль BSGrid

Итак, первое: нам надо хранить цвет подсветки в свойстве, чтобы мы могли менять её в инспекторе свойств или на этапе выполнения. Для этого в добавим в секцию private следующую строку: FRowHighlightColor: TColor; А в секцию published строку, описывающую наше свойство: property RowHighlightColor: TColor   read FRowHighlightColor write FRowHighlightColor default clHighlight; Теперь у нашего компонента появилось новое свойство RowHighlightColor. Это свойство доступно в инспекторе объектов  и по умолчанию его цвет будет clHighlight.

Осталось заставить это свойство работать должным образом. Но ещё было бы полезно иметь возможность отключать его или включать при необходимости. Т.е. не всем может оно понадобится или понравиться, тогда как какие-то другие свойства нашего расчудесного рукотворного DBGrid'a будут нужны. Предоставим пользователю выбор. Поэтому BSGrid будет иметь ещё одно свойство, содержащее набор дополнительных флагов, которые будут указывать — включена какая-либо фича или нет.

Заведём новый тип — множество флагов:

1
2
3
4
5
6
7
8
9
10
11
type
 
  TOptionBG = (bgoRowHighlight,
 
               bgoLastColumnAutoWidth, bgoPropColWidths,
 
               bgoShowLargeTextAsHint
 
              );
 
  TOptionsBG = set of TOptionBG;

Здесь нас интересует свойство bgoRowHighlight, которое будучи включенным в набор дополнительных свойств разрешает расширенную подсветку строк таблицы. Вышеуказанный текст надо набирать перед описанием класса TBSGrid. В самом же классе реализуем свойство дополнительных свойств. В секцию private (там где мы уже добавили FRowHighlightColor: TColor;) допишем FOptionsBG: TOptionsBG; Таким образом мы создали переменную для хранения дополнительных свойств. В секцию published пропишем это свойство: 

1
2
3
4
5
6
7
{ Published declarations }
    property OptionsBG: TOptionsBG
      read    FOptionsBG
      write   FOptionsBG
      default [bgoRowHighlight,bgoLastColumnAutoWidth,bgoPropColWidths,
               bgoShowLargeTextAsHint
              ];

Теперь у нас есть свойство дополнительных возможностей для BSGrid, посредством которого можно включать/или выключать ту или иную фичу. Об остальных опциях, которые мы обьявили в типе, пока не беспокойтесь. Они зарезервированы для будущих расширений 🙂 в дальнейших статьях.

Теперь собственно сама реализация подсветки. Кода немало, поэтому здесь его пояснять не буду. Но если Вы что-то не понимаете, оставляйте комментарии — всегда отвечу. Главное, что надо для себя прояснить — это то, что мы перепишем процедуру DrawCell, отвечающую за прорисовку каждой ячейки. И, в зависимости от состояния очередной ячейки (активна/неактивна, сфокусирована/несфокусирована, принадлежит активной строке и т.п.) будем её рисовать разными стилями и цветами. В секцию Protected добавьте такое описание нашей перекрываемой процедуры: 

1
2
3
4
procedure DrawCell(
           ACol, ARow: Longint;
           ARect: TRect;
           AState: TGridDrawState); override;

и нажмите Ctrl+Shift+C. Это магическое сочетание клавиш создаст в секции реализации (implementation) заготовку для написания тела нашей процедуры. Заполните её кодом, представленным ниже и Вы получите первый рабочий дополнительный функционал в своей собственной компоненте:

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
procedure TDBGridBS.DrawCell(ACol, ARow: Longint; ARect: TRect;
  AState: TGridDrawState);
var DrawColumn: TColumn;
    Value: string;
    OldActive: Integer;
    pass: boolean;
begin
 if (ARow=Row) and (ACol>0) then
  begin
   pass := (bgoRowHighlight in OptionsBG)
            and not (dgRowSelect in Options);
   if Focused then
    pass := pass and (ACol<>Col)
   else
    pass := pass and (dgAlwaysShowSelection in Options);
  if not pass then inherited DrawCell(ACol, ARow,ARect,AState) else
  with Canvas do
   begin
   DrawColumn := Columns[ACol-1];
   Font := DrawColumn.Font;
   Brush.Color :=  iif(bgoRowHighlight in FOptionsBG,
      ColorScale(FRowHighlightColor,4.5,235),
      DrawColumn.Color);
   if (DataLink = nil) or not DataLink.Active then FillRect(ARect)
   else
    begin
      Value := &#39;&#39;;
      OldActive := DataLink.ActiveRecord;
      try
        DataLink.ActiveRecord := ARow-1;
        if Assigned(DrawColumn.Field) then Value:=DrawColumn.Field.DisplayText;
        if not Enabled then Font.Color := clGrayText;
        if DefaultDrawing then
          WriteText(Canvas, ARect, 2, 2, Value, DrawColumn.Alignment,
            UseRightToLeftAlignmentForField(
              DrawColumn.Field, DrawColumn.Alignment));
        if Columns.State = csDefault then
          DrawDataCell(ARect, DrawColumn.Field, AState);
        DrawColumnCell(ARect, ACol, DrawColumn, AState);
      finally
        DataLink.ActiveRecord := OldActive;
      end; //try
    end; //else
   end //if not pass then ... else with Canvas do
  end  //if (ARow=Row) and (ACol>0) then
  else inherited DrawCell(ACol, ARow,ARect,AState);
end;

Теперь перекомпилируйте проект с новой компонентой, закройте его и откройте наш тестовый. Заново скомпилируйте и его и убедитесь, что всё работает и теперь наш BSGrid подсвечивает все ячейки активной строки так, как представлено на рисунке в начале статьи.

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

BSGrid, Bumper soft, DBGrid, Delphi, Embarcadero,

2 комментария to “BSGrid – Создаём собственный DBgrid. Часть 2.”


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Powered by WordPress. Designed by elogi.