18.2.4. TStringGrid - таблица строк

Компонент TStringGrid предназначен для создания таблиц, в ячейках которых располагаются произвольные текстовые строки. Он является прямым потомком TDrawGrid (см. ниже п. 18.2.5), от которого им унаследовано большинство свойств и методов.

Таблица делится на две части - фиксированную и рабочую. Фиксированная служит для показа заголовков столбцов/рядов и для ручного управления их размерами. Обычно фиксированная часть занимает крайний левый столбец и самый верхний ряд таблицы, однако с помощью свойств FixedCols и FixedRows можно задать другое количество фиксированных столбцов и рядов (если эти свойства имеют 0, таблица не содержит фиксированной зоны). Рабочая часть - это остальная часть таблицы. Она может содержать произвольное количество столбцов и рядов, более того, эти величины могут изменяться программно. Рабочая часть может не умещаться целиком в пределах окна компонента, в этом случае в него автоматически помещаются нужные полосы прокрутки. При прокрутке рабочей области фиксированная область не исчезает, но меняется ее содержимое - заголовки строк и рядов.

Центральным свойством компонента является Cells - двухмерный массив ячеек, каждая из которых может содержать произвольный текст. Конкретная ячейка определяется парой чисел - номером столбца и номером ряда, на пересечении которых она находится (нумерация начинается с нуля). Свойство cells имеет тип String, поэтому программа может легко прочитать или записать содержимое нужной ячейки. Например:

Cells [1,1] := 'Левая верхняя ячейка рабочей зоны';

Количество ячеек по каждому измерению хранит пара свойств Colcount (количество столбцов) и RowCount (количество рядов). Значения-этих свойств и, следовательно, размеры таблицы могут меняться как на этапе разработки программы, так и в ходе ее работы, однако их значения должны быть как минимум на единицу больше соответственно значений в свойства FixedCois и FixedRows, определяющих размеры фиксированной зоны.

Содержимое ячеек можно редактировать. Для этого в таблице используется специализированный потомок редактора TMaskEdit.

Свойства компонента:

property BorderStyle: TBorderStyle; | Определяет рамку компонента: bsNone нет рамки; bsSingle - рамка толщиной 1 пиксель
property Cells[ACol, ARow: Integer] :String; | Определяет содержимое ячейки с табличными координатами (ACol, ARow)
property Col: Longint; | Содержит номер столбца сфокусированной ячейки
property ColCount: Longing- | Содержит количество столбцов таблицы
property Cols[Index: Integer]: TStrings; | Содержит все строки колонки с индексом Index
property ColWidths[Index: Longint] : Integer; | Содержит ширину столбца с индексом Index
property DefaultColWidth: Integers; | Содержит умалчиваемое значение ширины столбца
property DefaultDrawing: Boolean; | Разрешает/запрещает автоматическую прорисовку служебных элементов таблицы - фиксированной зоны, фона и прямоугольника сфокусированной ячейки и т. п.
property DefaultRowHeight: Integers; | Содержит умалчиваемую высоту рядов
property EditorMode: Boolean; | Разрешает/запрещает редактирование ячеек. гнорируется, если свойство Options включает goAlwayseShowEditor или не включает goEditing
property FixedColor: TColor; | Определяет цвет фиксированной зоны
property FixedCois: Integers; | Определяет количество столбцов фиксированной зоны
property FixedRows: Integers; | Определяет количество рядов фиксированной зоны
property GridHeight: Integers; | Содержит высоту таблицы
property GridLineWidth: Integers; | Определяет толщину линий, расчерчивающих таблицу
property GridWidth: Integers; | Содержит ширину таблицы
property LeftCol: Longint; | Содержит номер самого левого столбца, видимого в зоне прокрутки
property Objects [ACols ARow: Integer] : TObject; | Обеспечивает доступ к объекту, связанному с ячейкой (ACol, ARow)
property Options: TGridOptions; | Содержит параметры таблицы (см. ниже)
property Row: Longing; | Содержит номер ряда сфокусированной ячейки
property RowCount: Longint; | Содержит количество рядов таблицы
property RowHeights[Index: Long int] : Integer; | Содержит высоту ряда с индексом index
property Rows[Index: Integer]: TStrings; | Содержит все строки ряда с индексом Index
type TScrollStyle = (ssNone, ssHorizontal, ssVertical, ssBoth) ; | Определяет полосы прокрутки: ssNone -нет полос; ssHorizontal - в таблицу вставляется горизонтальная полоса;
property ScrollBars: TScroll Style; | ssVertical - вставляется вертикальная полоса; ssBoth - вставляются обе полосы
TGridRect = record case Integer of 0: (Left,Top,Right,Bottom: Long int) ; 1: (TopLeft, BottomRight: TGridCoord) ; end; | Определяет группу выделенных ячеек в координатах левая верхняя и правая нижняя ячейки(нумерация столбцов и рядов идет от нуля, включая столбцы и ряды фиксированной зоны). После выделения сфокусированной окажется правая нижняя ячейка
property Selection: TGridRect; property TabStops[Index: Long int] : Boolean; | Разрешает/запрещает выбирать столбец с индексом index при обходе ячеек клавишей Tab. Игнорируется, если Options не содержит goTabs
property TopRow: Longint; | Содержит номер самого верхнего ряда, видимого в прокручиваемой зоне ячеек
property VisibleColCount: Integer; | Содержит количество столбцов, полностью видимых в зоне прокрутки
property VisibleRowCount: Integer; | Содержит количество рядов, полностью видимых в зоне прокрутки

Для компонента определен тип TGridOptions:

type

TGridOption = (goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goRowSizing, goColSizing, goRowMoving, goColMoving, goEditing, goTabs, goRowSelect, goAlwaysShowEditor, goThumbTracking);

TGridOptions = set of TGridOptions;

Элементы множества TGridOptions имеют следующий смысл:

goFixedVertLine | Столбцы фиксированной зоны разделяются вертикальными линиями
goFixedHorzLine | Ряды фиксированной зоны разделяются горизонтальными линиями
goVertLine | Столбцы рабочей зоны разделяются вертикальными линиями
goHorzLine | Ряды рабочей зоны разделяются горизонтальными линиями
goRangeSelect | Разрешено выделение нескольких ячеек. Игнорируется, если включен элемент goEdit
goDrawFocus Selected | Разрешено выделять сфокусированную ячейку так же, как выделенные
goRowSizing goColSizing goRowMoviog | Разрешено ручное (мышью) изменение высоты строк Разрешено ручное изменение ширины рядов Разрешено ручное перемещение рядов (нажать левую кнопку мыши на фиксированной ячейке перемещаемого ряда и, удерживая кнопку нажатой, переместить ряд на новое место)
goColMoving goEditing | Разрешено ручное перемещение столбца Разрешено редактирование ячейки. Игнорируется, если включен элемент goRowSelect. Редактирование начинается после щелчка мыши или нажатия клавиши F2 и завершается при щелчке по другой ячейке или нажатии клавиши Enter
goTabs goRowSelect | Разрешено обходить ячейки клавишей Tab (Shift+Tab) Обязывает выделять сразу все ячейки ряда и запрещает редактирование ячеек Разрешено редактировать сфокусированную ячейку: редактирование возможно после выбора ячейки клавишей Tab (Shift+Tab). Игнорируется, если не включен элемент goEditing
goAlwaysShowEditorgoThumbTracking | Разрешено обновление при прокрутке. Если этот элемент отсутствует, обновление ячеек произойдет только после окончания прокрутки

Два метода класса могут оказаться полезными для процедуры прорисовки:

function CellRect(ACol, ARow: TRect; Longint): | Возвращает прямоугольник ячейки по номерам столбца ACol и ряда Arow
procedure MouseToCell(X, Y: Integer; var ACol, ARow: Longint); | Возвращает табличные координаты ячейки ACol и arow по экранным координатам(X,У)точки

Остальные методы рассчитаны на перекрытие в потомках и представляют интерес для разработчиков новых компонентов. Для программистов-пользователей важны следующие доступные компоненту события:

TMovedEvent = procedure (Sender: TObject; Fromlndex, Tolndex: Longint) of object; property OnColumnMoved: TMovedEvent; TDrawCellEvent; | Возникает при перемещении столбца с индексом Fromlndex в положение, определяемое индексом ToIndex
TGridDrawState = set of (gdSelected, gdFocused, gdFixed) ; TDrawCellEvent = procedure (Sender: TObject; Col, Row: Longint; Rect: TRect; State: TGridDrawState) of object-property OnDrawCell: | Возникает при необходимости перерисовать ячейку с табличными координатами (Col, Row): Rect - прямоугольник прорисовки; State - состояние ячейки (gdSelected -ячейка выделена; gdFocused - ячейка сфокусирована; gdFixed - ячейка принадлежит фиксированной зоне таблицы). Для прорисовки используется табличное свойство Canvas
GetEditEvent = procedure (Sender: TObject; ACol, ARow: | Возникает при редактировании текста в ячейке с табличными координатами
Longint; var Value: String) ofobject; property OnGetEditMask: TGetE ditEvent; | (ACol.ARow). В параметре value обработчик должен вернуть шаблон для редактора TeditMask
property OnGetEditText: TGetE ditEvent; | Возникает при редактировании текста в ячейке с табличными координатами (ACol.ARow). В параметре value обработчик должен вернуть текст для редактора TEditMask (см. событие OmGetEditMask)
property OnRowMoved: TMovedEvent; | Возникает при перемещении ряда с индексом Fromindex в положение, определяемое индексом ToIndex (см. событие onColMoved)
SelectCellEvent = procedure (Sender: TObject; Col, Row: Long int; var CanSelect: Boolean) of object; property OnSelectCell: TSe lectCellEvent; | Возникает при попытке выделить ячейку с табличными координатами (col.Row). В параметре CanSelect обработчик сообщает о возможности выделения ячейки
TSetEditEvent = procedure (Sender: TObject; ACol, ARow: Longint; const Value: String) of object; property OnSetEditText: TSetEditEvent; | Возникает при завершении редактирования ячейки (ACol.ARow). В параметре value обработчик получает результат ввода или редактирования текста
property OnTopLeftChanged: TNotifyEvent; | Возникает после изменения значения ТоpRow или LeftCol в результате прокрутки рабочей зоны

В следующем примере компонент TStringGrid используется для показа всех слов из произвольного текстового файла (рис. 18.10).

- Назовите пустую форму именем fmStGrid и положите на нее панель TPanel.
- Установите в свойство панели Align значение alBottom, чтобы панель всегда занимала самую нижнюю часть окна, и удалите текст в ее свойстве caption.
- Поместите на панель кнопку TBitBtn, установите в ее свойство

Caption строку Открыть файл..., загрузите в свойство Glyph файл images | buttons | FILE OPEN.BMP и растяните кнопку по горизонтали так, чтобы надпись и пиктограмма полностью умещались на ее поверхности.

Рис. 18.10. Пример использования TStringList

- Поместите на панель еще одну кнопку TBitBtn и установите в ее свойство Kind значение bkClose.
- Поместите на панель компонент OpenDialog из страницы компонентов Dialogs. Этот компонент создает и обсуживает стандартное для Windows окно открытия файла. С его помощью при прогоне программы вы сможете выбрать текстовый файл (например, файл с текстом программы), чтобы программа показала в таблице все слова из этого файла.
- На форму (а не на панель panel1) положите компонент TStringGrid.
- Поместите в его свойства ColCount и RowCount значения 2 (количество колонок и рядов таблицы должно быть больше, чем количество фиксированных колонок FixedCois и количество фиксированных рядов FixedRows). Установите в свойство Align компонента значение alClient, чтобы он занял все свободное место формы.

На этом закончим этап конструирования формы. Вся основная работа будет связана с нажатием кнопки BitBtn1: программа сначала предложит вам выбрать текстовый файл, затем прочитает его и создаст список отсортированных в алфавитном порядке слов из каждой строки файла, после чего наполнит словами таблицу. Наполнение будет происходить так, чтобы каждый столбец строки содержал все слова, начинающиеся на одну и ту же букву.

Создайте такой обработчик события OnClick для кнопки BitBtn1:

procedure TfmStGrid.BitBtnIClick(Sender: TObject) ;

Function GetWord(var S: String): String;

{ Вспомогательная функция для выделения очередного слова из

строки }

const // Множество символов слова:

Letters: set of Char = ['a'..'z', 'A'..'Z', 'A'..'я'];

begin

Result := '' ;

{ Уничтожаем в начале строки все символы, не относящиеся к слову }

while (S о '') and not (S[1] in Letters) do

Delete (S, 1, 1);

// Формируем очередное слово

while (S<> '') and (S[1] in Letters) do

begin

Result := Result + S[1];

Delete (S, 1, 1)

end;

end; //Get Word

var

F: TextFile; // Файл с текстом S,

Word: String; // Вспомогательные строки

NCol, NRow: Integer;// Номер текущей колонки и текущего ряда Words: TStringList; // Список отсортированных слов из файла

begin

// С помощью стандартного диалога получаем имя файла

if not OpenDialogI.Execute then

Exit; // Пользователь отказался выбрать файл

// Пытаемся открыть файл

AssignFile(F, OpenDialogI.FileName) ;

try

Reset(F) ;

except

// Файл нельзя открыть:

ShowMessage('Невозможно открыть файл ' +OpenDialogI.FileName) ;

Exit;

end;

// Готовим список Words:

Words := TStringList.Create;

Words.Sorted := True; // Сортируем строки Words.Duplicates := duplgnore; // Отвергаем дубликаты

// Изменяем курсор перед длительной работой

Screen.Cursor := crHourGlass;

// Читаем файл по строкам

while not EOF(F) do

begin

ReadLn(F, S); // Читаем очередную строку

// Выделяем из строки слова и заносим их в список Words

while S о '' do

begin

Word := GetWord(S) ;

if Word о '' then

Words.Add(Word) // He вставляем пустые строки

end

end;

Screen.Cursor := crDefault; // Восстанавливаем курсор

CloseFile(F); // Закрываем файл

if Words.Count=0 then

Exit; // Пустой файл - выходим

with sgWords do

begin

NCol := 1; // Номер первого столбца слов

// Цикл формирования таблицы

while Words.Count > 0 do

begin

{Формируем заголовок столбца и начальное значение номера ряда}

Cells [NCol, 0] := Words[0][1];

NRow := О

// Цикл заполнения очередного столбца

while (Words.Count > 0) and

(Words[0][1] = Cells[NCol, 0]) do

begin

inc(NRow); // Номер текущего ряда

if NRow = RowCount then

begin // Расширяем длину таблицы

RowCount := RowCount + 1;

{Для свойства RowCount нельзя, использовать функцию инкремента inc!} Cells [0, NRow] := IntToStr(NRow);

end;

Cells[NCol, NRow] :=Words[0];

Words.Delete(0) ;

end;

// Переходим к следующему столбцу

if Words.Count=0 then

Break; // Кончаем работу, если слов больше нет

inc(NCol); // Переходим к следующей колонке

ColCount := ColCount+1 // Расширяем таблицу справа

//на 1 колонку

end;

end;

end;