По следам "полосатого DBGrid"

Источник: delphikingdom
Сергей Деев

Автор: Сергей Деев, Королевство Delphi

В повседневной практике программисту очень часто необходимо каким-либо способом обратить внимание пользователя на некоторые значения DataSet, высвечиваемые с помощью DBGrid. Сделать это можно, обрабатывая событие TDBGrid.OnDrawColumnCell в коде для каждого компонента TDBGrid проекта.

Представленный материал - это попытка решить данную проблему в design time путем расширения возможностей стандартного TDBGrid.

Проект составлен исключительно из учебных целей для публикации на сервере "Королевство Дельфи" и самостоятельной ценности не несет.

Класс TDBGrid и его свойства

Как уже отмечалось для "раскраски" какой-либо колонки или всей строки в целом программисту следует обработать событие TDBGrid.OnDrawColumnCell в коде для каждого компонента TDBGrid проекта.

Теперь посмотрим на реализацию данного события в VCL. Из кода становится ясно, что все мы должны сделать - это перекрыть стандартную процедуру по перерисовке ячейки DrawColumnCell.

Для хранения настроек, имен полей, условия закраски и других необходимых параметров, по "раскраске" создадим коллекцию этих настроек

 

Создание наследника класса TDBGrid

С помощью мастера создания компонентов создадим наследника TDBGrid и назовем его, например, TDBStripedGrid.

В результате работы мастера получим следующий код

unit DBStripedGrid;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, DBGrids, Db;

type
  TDBStripedGrid = class(TDBGrid)
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
  end;
procedure Register;
implementation

procedure Register;
begin
  RegisterComponents('Samples', [TDBStripedGrid]);
end;
end.

Теперь займемся коллекцией для хранения настроек по "раскраске".

Класс-коллекция TStripedCollection и ее элементы TStripedItem

Прежде разберем, что нам необходимо сделать.

  1. Необходимо поменять шрифт какой-либо колонки в зависимости от значения поля в этой колонке.
  2. Необходимо поменять шрифт для всей строки в зависимости от значения поля в какой-либо колонке.
  3. Необходимо поменять цвет фона какой-либо колонки в зависимости от значения поля в этой колонке.
  4. Необходимо поменять цвет фона всей строки в зависимости от значения поля в какой-либо колонке.
  5. Необходимо поменять шрифт какой-либо колонке в зависимости от значений двух других полей.
  6. Необходимо поменять цвет фона какой-либо колонке в зависимости от значений двух других полей.
  7. Необходимо поменять шрифт всей строки в зависимости от значений двух других полей.
  8. Необходимо поменять цвет всей строки колонке в зависимости от значений двух других полей.
  9. Необходимо поменять шрифт каких-либо 2-х колонок одновременно в зависимости от значения третьего поля.
  10. Необходимо поменять цвет фона каких-либо 2-х колонок одновременно в зависимости от значения третьего поля.
  11. Необходимо подменить текст какой-либо колонки в зависимости от значения поля этой колонки. Как пример можно рассмотреть поле типа TBooleanField при значении поля True необходимо написать "Да", а при значении поля False - "Нет".
  12. Необходимо подменить текст какой-либо колонки на другое значение в зависимости от значения поля в этой колонке.

И все это необходимо сделать независимо друг от друга. Кроме того, необходимо, чтобы все эти свойства можно было менять в design time. Наиболее подходящим инструментов для хранения настроек являются свойства-коллекции.

Создадим "родительский" класс - коллекцию TStripedCollection на основе класса TOwnedCollection и ее "родительские" элементы TStripedItem на основе класса TCollectionItem. А затем, для реализации тех или иных свойств - наследников от "родителей". Как видим из выше описанного, нам понадобятся 12 свойств-коллекций и 12 элементов-коллекций.

Создавая классы-"родители" будем иметь в виду, что почти все свойства можно помещать в protected, а в наследуемых коллекциях их следует перенести в в public и published для того, чтобы эти свойства были доступны в design time.

Очевидно, что для коллекции TStripedCollection нам понадобятся следующие свойства:

свойство - элемент коллекции

property Items[Index: Integer]: TStripedItem read GetStripedItem
                                write SetStripedItem; default;

ссылка на владельца (Owner) коллекции

property Grid: TDBStripedGrid read FGrid;

А для элементов коллекции TstripedItem: свойства типа оператора сравнения

property Compare: TStripedCompare read FCompare write SetCompare;
property LeftCompare: TStripedCompare read FLeftCompare write SetLeftCompare;
property RightCompare: TStripedCompare read FRightCompare write SetRightCompare;

свойство показа

property Showing: Boolean read FShowing write SetShowing default False;

свойства - поля DataSource.DataSet

property Field: TField read GetField write SetField;
property FirstField: TField read GetFirstField write SetFirstField;
property SecondField: TField read GetSecondField write SetSecondField;
property LeftField: TField read GetLeftField write SetLeftField;
property RightField: TField read GetRightField write SetRightField;

свойства - наименования полей DataSource.DataSet

property LeftFieldName: String read FLeftFieldName write SetLeftFieldName;
property RightFieldName: String read FRightFieldName write SetRightFieldName;
property FirstFieldName: String read FFirstFieldName write SetFirstFieldName;
property SecondFieldName: String read FSecondFieldName write SetSecondFieldName;
property FieldName: String read FFieldName write SetFieldName;

свойства - значения полей DataSource.DataSet для сравнения

property FieldValue: Variant read FFieldValue write SetFieldValue;
property LeftFieldValue: Variant read FLeftFieldValue write SetLeftFieldValue;
property RightFieldValue: Variant read FRightFieldValue write SetRightFieldValue;

свойства - изменяемые значения

property ReplaceValue: Variant read FReplaceValue write SetReplaceValue;
property StrIsTrue: String read FStrIsTrue write SetStrIsTrue;
property StrIsFalse: String read FStrIsFalse write SetStrIsFalse;
property Font: TFont read FFont write SetFont;
property Color: TColor read FColor write SetColor;

А для удобства работы перечислимый тип операторов сравнения:

…
type
…

  TStripedCompare = (ccEqual, ccMoreEqual, ccMore, ccLessEgual,
                     ccLess, ccUnEqual);

Итак, ссылки на наши классы будут выглядеть следующим образом:

type

 //ссылки на "родительские" классы
  TStripedItem = class;

  TStripedCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //шрифта у всей строки
  TStripedRowsFontItem = class;

  TStripedRowsFontCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //шрифта у ячейки
  TStripedRowFontItem = class;
  TStripedRowFontCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //цвета фона у всей строки
  TStripedRowsBrushColorItem = class;
  TStripedRowsBrushColorCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //цвета фона у ячейки
  TStripedRowBrushColorItem = class;
  TStripedRowBrushColorCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //шрифта у всей строки по левой и правой границе
  TStripedLeftRightRowsFontItem = class;
  TStripedLeftRightRowsFontCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //шрифта у ячейки по левой и правой границе
  TStripedLeftRightRowFontItem = class;
  TStripedLeftRightRowFontCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //цвета фона у всей строки по левой и правой границе
  TStripedLeftRightRowsBrushColorItem = class;
  TStripedLeftRightRowsBrushColorCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //цвета фона у ячейки по левой и правой границе
  TStripedLeftRightRowBrushColorItem = class;
  TStripedLeftRightRowBrushColorCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //текста у ячейки
  TStripedBooleanItem = class;
  TStripedBooleanCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //текста у ячейки
  TStripedReplaceItem =  class;
  TStripedReplaceCollection =  class;

  //ссылки на коллекцию и ее элементы по изменению
  //шрифта у ячеек
  TStripedMasterFontItem = class;
  TStripedMasterFontCollection = class;

  //ссылки на коллекцию и ее элементы по изменению
  //цвета фона у ячеек
  TStripedMasterBrushColorItem = class;
  TStripedMasterBrushColorCollection = class;
  TDBStripedGrid = class;

  //перечислимый тип операторов сравнения
  TStripedCompare = (ccEqual, ccMoreEqual, ccMore, ccLessEgual,
                     ccLess, ccUnEqual);

Более подробно код представлен в прилагающемся файле.

Создание свойств коллекций в TDBStripedGrid

В наш наследник TDBStripedGrid добавим published свойства-коллекции для хранения настроек. Имеем:

type
…
  TDBStripedGrid = class(TDBGrid)
…
  published
    //св-во коллекция по изменению шрифта у всей строки
    property StripedRowsFont: TStripedRowsFontCollection read FStripedRowsFont
               write SetStripedRowsFont;
    //св-во коллекция по изменению шрифта у ячейки
    property StripedRowFont: TStripedRowFontCollection read FStripedRowFont
               write SetStripedRowFont;
    //св-во коллекция по изменению цвета фона у всей строки
    property StripedRowsBrushColor: TStripedRowsBrushColorCollection
        read FStripedRowsBrushColor write SetStripedRowsBrushColor;
    //св-во коллекция по изменению цвета фона у ячейки
    property StripedRowBrushColor: TStripedRowBrushColorCollection
        read FStripedRowBrushColor write SetStripedRowBrushColor;
    //св-во коллекция по изменению шрифта у всей строки по левой и правой границе
    property StripedLeftRightRowsFont: TStripedLeftRightRowsFontCollection
        read FStripedLeftRightRowsFont write SetStripedLeftRightRowsFont;
    //св-во коллекция по изменению шрифта у ячейки по левой и правой границе
    property StripedLeftRightRowFont: TStripedLeftRightRowFontCollection
        read FStripedLeftRightRowFont write SetStripedLeftRightRowFont;
    //св-во коллекция по изменению цвета фона у всей строки по левой и правой границе
    property StripedLeftRightRowsBrushColor: TStripedLeftRightRowsBrushColorCollection
        read FStripedLeftRightRowsBrushColor write SetStripedLeftRightRowsBrushColor;
    //св-во коллекция по изменению цвета фона у ячейки по левой и правой границе
    property StripedLeftRightRowBrushColor: TStripedLeftRightRowBrushColorCollection
        read FStripedLeftRightRowBrushColor write SetStripedLeftRightRowBrushColor;
    //св-во коллекция по изменению текста у ячейки
    property StripedBoolean: TStripedBooleanCollection read FStripedBoolean
        write SetStripedBoolean;
    //св-во коллекция по изменению текста у ячейки
    property StripedReplace: TStripedReplaceCollection read FStripedReplace
        write SetStripedReplace;
    //св-во коллекция по изменению шрифта у ячеек
    property StripedMasterFont: TStripedMasterFontCollection
        read FStripedMasterFont write SetStripedMasterFont;
    //св-во коллекция по изменению цвета фона у ячеек
    property StripedMasterBrushColor: TStripedMasterBrushColorCollection
        read FStripedMasterBrushColor write SetStripedMasterBrushColor;
end;

Для автоматического создания коллекций в design time следует переопределить стандартные конструктор Create

constructor Create(AOwner: TComponent); override;

и деструктор Destroy класса

destructor Destroy; override;

с добавлением служебных функций типа:

function CreateStripedRowsFont: TStripedRowsFontCollection;

Добавим обработку сролирования колесиком мышки:

procedure WMWheel(var Msg: TWMMouseWheel); message WM_MOUSEWHEEL;

процедуру MouseToCell, как у TDrawGrid

procedure MouseToCell(X, Y: Integer; var ACol, ARow: Longint);

пару public свойств:

property ActiveRecord: Integer read GetActiveRecord;
property RecNo: Integer read GetRecNo;

Для сохранения коллекций-свойств переопределим стандартную процедуру:

procedure DefineProperties(Filer: TFiler); override;

с добавлением процедур по записи и чтению свойств-коллекций типа:

procedure ReadStripedRowsFont(Reader: TReader);
procedure WriteStripedRowsFont(Writer: TWriter);

И, наконец, переопределим стандартную процедуру DrawColumnCell в которой и будем проводить все изменения:

procedure DrawColumnCell(const Rect: TRect; DataCol: Integer;
    Column: TColumn; State: TGridDrawState); override;

Более подробно код представлен в прилагающемся файле.

Регистрация компонента TDBStripedGrid, классов элементов коллекций и коллекций, редакторов свойств.

Для удобства создадим новый Unit и назовем его DBStripedGridReg.

Перенесем туда процедуру регистрации:

procedure Register;

Добавим туда регистрацию классов элементов коллекций и коллекций и редактор свойств имен полей на основе редактора свойств TStringProperty, переопределив некоторые процедуры и функции.

Более подробно код представлен в прилагающемся файле.

Заключение

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

При написании статьи использовались следующие материалы:

  1. Разноцветный D B G R I D
  2. Grid с человеческим лицом
  3. НеОбычный TDBGrid

Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=19915