TArrayGrid v1.3
(September 1999). Delphi4 Component.
ã 1999 Alex Konshin
Очень кратко о том, что такое ArrayGrid.
Во-первых, это наследник TCustomControl (согласись, это уже
необычно для грида),
поэтому он не тянет за собой тяжелое наследие TCustomGrid.
Во-вторых, он в отличии от TStringGrid привязывается к
данным, но в отличии от TDBGrid источник данных абстрактный, то есть вовсе
необязательно чтобы данные были в базе, более того, данные вполне могут
вычисляться на лету (при этом соответствующая клетка все-таки может быть
редактируемой).
В-третьих, в нем нет ненужных в большинстве случаев
наворотов вроде разной высоты строк, толщины разделяющей линии и т.п., за счет
чего существенно упрощена и ускорена отрисовка. При этом очень просто делается
выбор цвета ячейки (метод OnGetCellColor).
Реализован multiselect для строк (отметка прямоугольных
регионов IMHO вообще мало когда нужна), логика отметки позволяет раз/отмечать
несколько участков (в отличии от логики explorer,
где нельзя это сделать с помощью Shift, только через Ctrl, что иногда бывает
очень утомительно).
Совсем по-другому сделан скроллинг по горизонтали - он
плавный, хотя с помощью Ctrl+стрелка можно скакать по колонкам почти как в
обычном гриде.
Пока есть только пять типов ячеек: выровненная влево строка,
выровненная вправо строка, целое число, деньги и дата/время (кстати, числа редактируются довольно забавно - они не
прыгают влево при редактировании и грамотно реагируют на десятичную точку). При
большом желании можно сделать собственную отрисовку ячеек, про собственное
редактирование, pickuplist и т.п. думаем, может сделаю.
Пока есть только два варианта подключения данных, но оба
требуют написания наследников от абстрактных классов.
Первый способ - наиболее общий: написать наследника от
TAbstractDataConnector. Для этого достаточно переопределить методы GetAs*/SetAs* и, если
необходим multiselect, то и Get/SetSelected. Есть также возможность перекрытия
других методов для оптимизации.
Второй способ - упрощение для наиболее частой ситуации:
обычно есть какой-то массив данных, которые хочется смотреть/редактировать в
гриде. Для этого реализуем соответствующий динамический массив объектов на
основе абстрактных классов TGridDataArray и TGridDataArrayItem.
Далее либо перекрываем GetAs/SetAs (перекрывать Get/SetSelected не надо - уже
реализовано), либо объявляем published
свойства
и в дизайнере для соответствующих колонок грида прописываем имена этих свойств.
В обработчике события OnCreate формы создаем этот массив и, когда приходит
время загрузить и отрисовать данные (например, в обработчике события OnShow
формы), присваиваем его свойству грида DataObject. Простейшие примеры,
находящиеся в директории ArrayGridSample и ArrayGridRTTI,
демонстрирует, как это должно выглядеть.
Естественно, использование published более просто, но это несколько медленнее.
Рекомендуется также перекрыть методы RowHandle и RowByHandle – это позволит
гриду более правильно позиционировать текущую строку при обновлении данных
(например, пользователь изменил условия отбора данных из базы) и изменении
порядка сортировки. Метод RowHandle должен
выдавать некое уникальное LongInt значение для
каждой строки (например, идентификатор записи в соответствующей таблице базы
данных). Если Вы собираетесь использовать динамические массивы объектов и вы
можете предоставить уникальный идентификатор для каждой записи, то посмотрите
на классы TGridDataIdArray и TGridDataIdArrayItem, они специально для этого случая и Вам не
потребуется самостоятельно переопределять упомянутые методы – это уже сделано.
Register-процедура находится в файле ArrayGrids.pas
Классы из модуля Arrays.pas используются в ArrayGrids,
кстати, сам этот модуль тоже достаточно интересный.
property Options: TArrayGridOptions;
TArrayGridOption = (goMultiSelect, goFocusSelected, goAlwaysShowFocus, goRowFocus, goColSizing, goEditing, goAlwaysShowEditor, goAutoHideEditor, goVertThumbTracking,
goHorzThumbTracking, goTabs, goSmoothScroll,
goTrackMouse, goTrackEditorChanging,
goSortOnTitleClick);
goMultiSelect -
Разрешение множественной отметки строк. Пользователь может ставить/снимать
отметку при помощи клавиатуры и мыши. Из приложения отметка устанавливается
методом DataConnector.SetSelected, получить значение можно с помощью
DataConnector.GetSelected, а если класс присоединенного объекта данных является
наследником от класса TGridDataArray, то к отметке можно обращаться через
свойство Selected. Цвет ячеек, принадлежащих отмеченным
строкам, задается через
SelColor, SelTextColor, SelFocusColor, SelFocusTextColor.
goFocusSelected -
Если True, то цвета *Focus*Color относятся к ячейке, на которую указывает Row и Col, иначе они описывают цвета
строки Row(есть у меня подозрение, что здесь что-то не так).
goAlwaysShowFocus - Если True, то текущая ячейка/строка
всегда будет выделяться даже если грид не в фокусе.
goRowFocus - В фокусе
вся строка, а не отдельная ячейка. Режим не рекомендуется, если отдельные
колонки доступны для редактирования и Вы используете встроенные редакторы ячеек
– считается, что в этом режиме должна редактироваться строка целиком.
goColSizing -
Если True, то разрешено менять ширину колонок.
goEditing -
Если True, разрешено редактирование ячеек в колонках, для которых property
ReadOnly = False.
goAlwaysShowEditor -
Если разрешено редактирование ячейки, находящейся в фокусе, то она будет в
режиме редактирования.
goAutoHideEditor – Если True, то
при выходе из редактирования ячейки редактор будет отключаться. В противном
случае, если редактирование новой текущей ячейки разрешено, то она сразу будет
переведена в режим редактирования.
goVertThumbTracking, goHorzThumbTracking -
Если тащить за бегунок полосы прокрутки, то синхронно будет изменяться
положение ячейки в фокусе. При отключенных этих режимах оно изменяется только
при отпускании бегунка.
goSmoothScroll -
(Win2K only) гладкая прокрутка (я не уверен, что она работает так, как об этом пишет MS).
goTabs -
Если True, то клавиша Tab будет изменять фокус.
goTrackMouse -
Если в этом режиме нажать на левую кнопку мыши и двигать за пределы грида, то автоматически будет
производится прокрутка. Если же при этом
еще и нажата клавиша Shift, то попутно будет ставиться/сниматься отметка строк.
goTrackEditorChanging - В
этом режиме при редактировании ячейки на каждое изменение будет вызываться
метод DataConnector.SetAs...(т.е. сохранять), иначе это действие будет происходить только при выходе из
редактирования.
goSortOnTitleClick -
Пока этот режим имеет смысл, только если
класс присоединенного объекта с данными является наследником от TGridDataArray. В этом случае при клике на заголовок
колонки будет переключаться направление сортировки записей (три состояния: по
возрастанию, по убыванию и в
первоначальном порядке).
property DefaultColWidth: Integer;
Задает
ширину колонки по умолчанию.
property TitleHeight : Integer;
Задает
высоту заголовка колонки.
property RowHeight: Integer;
Задает
высоту строк. Все строки данных имеют одинаковую высоту.
property LeftCol: LongInt;
Номер (от
нуля) левой отображаемой колонки.
property MaxLeftCol: LongInt;
Максимальный
номер левой отображаемой (хотя бы частично) колонки. Грид стремится не оставлять пустое место справа.
property RightCol: LongInt;
Номер правой
отображаемой колонки.
property TopRow: LongInt;
Номер
(от нуля) верхней строки.
property MaxTopRow: LongInt;
Максимальный
номер верхней строки (от нуля). Грид стремится не оставлять пустое место снизу.
property BottomRow: LongInt;
Номер
(от нуля) последней отображаемой (хотя бы частично) строки.
property Col: LongInt;
Номер
колонки для ячейки в фокусе.
property Row: LongInt;
Номер
текущей строки - номер строки, которой находится ячейка в фокусе.
property VisibleRowCount: Integer;
Количество
отображаемых строк.
property GridWidth: LongInt;
Ширина области
данных грида без учета пустого пространства справа.
property GridHeight: LongInt;
Высота области
данных и заголовка.
property Offset: LongInt;
Смещение
левого края левой видимой колонки от левого края клиентской части окна.
property Color: TColor default clWindow;
Цвет фона.
property SelColor: TColor;
Цвет фона
ячейки из отмеченной строки.
property SelTextColor: TColor;
Цвет текса
ячейки из отмеченной строки.
property SelFocusColor: TColor;
Цвет фона
ячейки из отмеченной строки, если она в фокусе.
property SelFocusTextColor: TColor;
Цвет текста
ячейки из отмеченной строки, если она в фокусе.
property FocusColor: TColor;
Цвет фона
ячейки в фокусе.
property FocusTextColor: TColor;
Цвет текста
ячейки в фокусе.
property ScrollBars: TArrayGridScrollBars default [sbHorz,sbVert];
TArrayGridScrollBars = set of (sbHorz,sbVert);
Разрешение на
отображение полос прокрутки. Если необходимости в прокрутке нет, то они не
будут отображаться независимо от значения этого свойства.
property DefaultDrawing: Boolean default True;
Если False, то
закрашивание фона и отрисовка линий не будет производиться.
property EditorMode: Boolean;
Если True, то
ячейка в фокусе сейчас редактируется.
property DataConnector: TAbstractDataConnector;
Объект для
доступа к данным. Если данные в объекте класса-наследника от TGridDataArray, то
проще воспользоваться свойством DataObject, в противном случае нужно написать наследника от TAbstractDataConnector,
создать объект и присвоить
его описываемому свойству грида.
property ColCount: LongInt;
Количество
колонок. Всегда больше нуля.
property Columns: TArrayGridCols;
Массив
описателей колонок.
property RowCount: LongInt;
Количество
строк.
property DataObject: TObject;
Присоединенный
объект данных. То же, что и DataConnector.DataObject.
Если присвоить
объект класса-наследника TGridDataArray, то автоматически будет создан объект
TGridDataArrayConnector и проставлены необходимые связи, что приведет к
отрисовке данных в гриде.
property OnDrawTitle: TArrayGridDrawTitleEvent;
TArrayGridDrawTitleEvent = procedure(Sender: TObject; ARect:
TRect) of object;
В обработчике
этого события нужно полностью отрисовывать строку заголовков. Стандартная
отрисовка может быть выполнена методом DrawTitle.
property OnDrawRow: TArrayGridDrawRowEvent;
TArrayGridDrawRowEvent = function(Sender:
TObject; const ARow, ALeftCol: LongInt; ARect: TRect; State: TArrayGridDrawState): Boolean of object;
Обработчик
этого события вызывается для отрисовки строки. Если он возвратит False, то должен полностью отрисовать указанную строку данных.
property OnDrawCell: TArrayGridDrawCellEvent;
TArrayGridDrawCellEvent = function(Sender: TObject; const ACol, ARow: LongInt; ARect: TRect; AState:
TarrayGridDrawState): Boolean of object;
Обработчик
этого события должен либо полностью отрисовать указанную ячейку, либо возвратить False.для
стандартной отрисовки. Стандартная отрисовка может быть выполнена с помощью
метода DrawCell (см.также
DrawStringCell, DrawRightStrCell, DrawIntegerCell, DrawCurrencyCell ).
property OnGetCellColor: TArrayGridGetCellColorEvent;
TArrayGridGetCellColorEvent = procedure (Sender: TObject; сonst ACol, ARow: LongInt; var AColor, ATextColor: TColor; AState:
TArrayGridDrawState) of object;
Обработчик
этого события может изменить цвет фона и текста ячеек.
property OnFocusMoved: TArrayGridDataChangedEvent;
TArrayGridDataChangedEvent = procedure(Sender: TObject; const ACol, ARow: LongInt) of object;
Обработчик
этого события вызывается при изменении индекса текущей строки или текущей ячейки. Параметры ACol и ARow задают
координаты фокуса до перемещения.
property OnDataChanged: TArrayGridDataChangedEvent;
TArrayGridDataChangedEvent = procedure(Sender: TObject; const ACol, ARow: LongInt) of object;
Вызывается при
изменении данных. Параметры ACol и/или ARow могут равняться -1, что означает,
что изменены данные всех ячеек строки и/или колонки соответственно. Этот метод
также будет вызван при изменении отметки, если OnSelectionChanged или
OnRowsChanged не заданы.
property OnRowsChanged: TArrayGridRowsChangedEvent;
TArrayGridRowsChangedEvent = procedure(Sender: TObject; const AFrom, ATo: LongInt) of object;
Изменилось
состояние или данные строки, либо вызван метод DataConnector.RowsChanged. Если изменилась только состояние
отметки и задан OnSelectionChanged, то описываемый метод вызван не будет. Если этот обработчик не задан, то будет
вызван OnDataChanged с параметром ACol=-1.
property OnRowsDeleted: TArrayGridRowsChangedEvent;
TArrayGridRowsChangedEvent = procedure(Sender: TObject; const AFrom, ATo: LongInt) of object;
Обработчик
вызывается при удалении строк. Если в одной операции удаляется много строк, то обработчик может быть
вызван несколько раз (но для разных групп строк).
property OnSelectionChanged: TArrayGridRowsChangedEvent;
TArrayGridRowsChangedEvent = procedure(Sender: TObject; const AFrom, ATo: LongInt) of
object;
Обработчик
вызывается при смене отметки. Если этот обработчик не задан, то будет вызван обработчик
OnRowsChanged, если и он не задан, то OnDataChanged с параметром ACol=-1.
property OnTitleClick : TArrayGridTitleClickEvent;
TArrayGridTitleClickEvent = procedure(Sender: TObject; const ACol : LongInt) of object;
Обработчик
вызывается при левом щелчке на заголовке колонки.
property OnShowHint:
TArrayGridShowHintEvent;
TArrayGridShowHintEvent = procedure (AArray: TCustomArrayGrid;
AHintInfo: PHintInfo; AColumn: TArrayGridCol; const ACol, ARow: Integer
) of object;
PHintInfo = ^THintInfo;
THintInfo = record
HintControl: TControl;
HintWindowClass: THintWindowClass;
HintPos: TPoint;
HintMaxWidth: Integer;
HintColor: TColor;
CursorRect: TRect;
CursorPos: TPoint;
ReshowTimeout: Integer;
HideTimeout: Integer;
HintStr: string;
HintData: Pointer;
end;
Обработчик
этого события вызывается перед выводом окна подсказки (Hint) в случае, если указатель
мыши находится на областью данных или над заголовком колонки. Если ARow=iTitle, то это значит, что указатель мыши находится над заголовком
колонки ACol. Вы можете изменить текст подсказки,
для этого впишите желаемое значение в поле AHintInfo^.HintStr, а
для подавления присвойте этому полю пустую строку.
function AddColumn(const ACaption: String; const AWidth: Integer): ArrayGridCol; virtual;
Добавляет
новую колонку. Параметр AWidth может быть отрицательным, тогда ширина колонки будет
автоматически изменяться с изменением размера грида, абсолютное значение будет
задавать минимальную ширину колонки и весовой коэффициент при расчете ширины.
function InsertColumn(const APosition: Integer; const ACaption: String; const AWidth: Integer): ArrayGridCol; virtual;
Вставляет
новую колонку перед указанной (APosition). Параметр AWidth может
быть отрицательным, тогда ширина колонки будет автоматически изменяться с
изменением размера грида, абсолютное значение будет задавать минимальную ширину
колонки и весовой коэффициент при расчете ширины.
procedure DeleteColumn(const ACol: LongInt); virtual;
Удаляет
колонку. Последняя колонка не может быть удалена.
procedure InvalidateCell(const ACol, ARow: LongInt);
Указывает
гриду, что указанная ячейка должна быть перерисована. Параметр ARow может
равняться константе iTitle, тогда будет перерисован заголовок соответствующей
колонки.
procedure InvalidateCol(const ACol: LongInt);
Указывает
гриду, что указанная колонка должна быть перерисована.
procedure InvalidateRow(const ARow: LongInt);
Указывает
гриду, что указанная строка должна быть перерисована. Параметр ARow может
равняться константе iTitle, тогда будет перерисована строка заголовков.
procedure InvalidateRows(const AFrom, ATo: LongInt);
Указывает
гриду, что указанный диапазон строк должен быть перерисован. Параметры также
могут равнятся iTitle (заголовок) и iBlank (пустая область).
procedure InvalidateRect(ARect : TArrayGridRect);
Указывает
гриду, что указанный прямоугольник ячеек должен быть перерисован.
procedure DrawTitle; virtual;
Стандартная
отрисовка заголовка.
procedure
DrawColumnTitle(const ACol: Integer; const APushed: Boolean);
virtual;
Стандартная
отрисовка заголовка указанной колонки.
procedure DrawCell(const ACol, ARow: LongInt; ARect: TRect; AState: TArrayGridDrawState);
Стандартная
отрисовка ячейки.
procedure DrawStringCell(const AValue: String; AColumn: TArrayGridCol; const ARow: LongInt; ARect: TRect); virtual;
Рисует строку
в указанной области.
procedure DrawRightStrCell(const AValue: String; AColumn: TArrayGridCol; const ARow: LongInt; ARect: TRect); virtual;
Рисует в
указанной области строку, выровненную вправо.
procedure DrawIntegerCell(const AValue: LongInt; AColumn: TArrayGridCol; const ARow: LongInt; ARect: TRect); virtual;
Рисует целое
число в указанной области.
procedure DrawCurrencyCell(const AValue: Currency; AColumn: TArrayGridCol; const ARow: LongInt; ARect: TRect); virtual;
Рисует
денежное значение в указанной области.
procedure DrawDateTimeCell(const AValue: TDateTime; AColumn: TArrayGridCol; const ARow: LongInt; ARect: TRect); virtual;
Рисует дату и/или время в указанной области.
function BoxRect(ALeft, ATop, ARight, ABottom: LongInt): TRect;
Параметры -
номера колонок и строк, задающие область, координаты которой нужно получить.
function CellRect(ACol, ARow: LongInt): TRect;
Результат -
область, занимаемая указанной ячейкой.
procedure DeleteRow(const ARow: LongInt);
Удалить
указанную строку.
procedure DeleteRows(const AFrom, ATo: Integer);
Удалить
указанные строки.
procedure DeleteSelected;
Удалить
отмеченные строки.
procedure DeleteAll;
Удалить все
строки.
procedure ToggleSelection(const ARow: LongInt);
Инвертировать
отметку указанной строки.
procedure ChangeSelection(AFrom, ATo: LongInt);
Изменить
отметку указанной области.
procedure InvertSelection;
Инвертировать
все отметки.
procedure
SelectAll;
virtual;
Отметить все
строки.
procedure
UnselectAll;
virtual;
Снять все
отметки.
procedure
CopySelectedToClipboard(const AIndexes: Array of
Integer);
Скопировать
отмеченное в буфер обмена (clipboard). Параметр - массив номеров колонок, если
же он задан как [], то будут скопированы все колонки. Ячейки разделяются
символами табуляции, строки - CRLF. Под NT в буфер будет записана строка в
UNICODE, под Win9x записывается номер кодовой страницы, поэтому скопированное
прекрасно вставляется в MS Excel 97 и MS Word 97.
function LockLayout : LongInt;
Блокирует
обработку и отрисовку изменений, связанных с изменением количества строк,
количества колонок, ширины колонок и т.п.. Результат – уровень вложенности
блокировки.
procedure UnlockLayout;
Уменьшает
счетчик уровня блокировок и, если он обнулился, выполняет пересчет параметров
отрисовки, полос прокрутки и т.п..
procedure UpdateLayout;
Если не
заблокировано, то выполняется пересчет параметров отрисовки и полос прокрутки.
function LocateString(const AKey: String; const ACol, AFrom: Integer;
AOptions: TStringArrayLocateOptions):
Integer;
TStringArrayLocateOption =
(saloCaseInsensitive, saloPartialKey, saloBackward);
Поиск
подходящего значения в колонке строкового типа (ackString или ackRight). Параметр AFrom задает индекс строки, начиная с которой будет
производиться поиск, если AFrom=-1, то поиск стартует с начала (конца в случае saloBackward).