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; |
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; |
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 ]; |
{ 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; |
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 := ''; 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; |
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 := ''; 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 автоматически управлять шириной колонок, показывать текст, невмещающийся полностью в границу ячейки, реализовывать поиск значений по символьному вводу или по значениям полей и многое, многое другое.
2 комментария to “BSGrid – Создаём собственный DBgrid. Часть 2.”
Добавить комментарий Отменить ответ
-
Свежие записи
- JavaScript: Сохранение векторной графики (svg) в растр
- Структура и формат файла Photoshop. Часть 5: Image Data
- Структура и формат файла Photoshop. Часть 4: Layer and Mask Information Section
- Структура и формат файла Photoshop. Часть 3: Image Resources Section
- С++ Как сделать класс ненаследуемым. Паттерн проектирования «Ненаследуемый класс».
Свежие комментарии
- Михаил к записи C#: Расширенная обработка элементов перечислений (enum) с помощю атрибутов
- Структура и формат файла Photoshop. Часть 5: Image Data | Papirosnik.info к записи Psd Splitter
- Структура и формат файла Photoshop. Часть 2: Color Mode Data. | Papirosnik.info к записи Структура и формат файла Photoshop. Часть 3: Image Resources Section
- Структура и формат файла Photoshop. Часть 3: Image Resources Section | Papirosnik.info к записи Структура и формат файла Photoshop. Часть 4: Layer and Mask Information Section
- O/A к записи About
Архивы
Рубрики
Мета
Я попровал! Получилось!!! И не так уж это трудно оказалось.
Опля… спасибо за статью. Позновательно!