Лекция № 4
Тема: «Обработка массивов данных с помощью сеток»
План
1. Обращение к ячейкам сетки как к элементам матрицы
2. Заполнение сетки
3. Пример обработки матрицы в сетке
1. Обращение к ячейкам сетки как к элементам матрицы
Компонент StringGrid можно использовать для отображения и работы с двумерными массивами (матрицами). При этом можно использовать следующие свойства сетки:
- ColCount - число колонок в сетке (столбцов в матрице);
- RowCount - число строк в сетке (строк в матрице)
- Cell[j,i] - ячейка сетки (элемент матрицы)
- DefaultHeigth, DefaultWidth - высота и ширина ячейки сетки в пикселях.
Замечания: при обработке матрицы через сетку необходимо учитывать следующие особенности данного компонента:
- содержимое ячеек в сетке всегда хранится в текстовом формате, что требует конвертирования этих данных в числовой формат;
- если в сетке отображаются фиксированные строки или колонки (обычно они серого цвета), то размер сетки нужно увеличивать на число таких строк и колонок;
- в отличии от обычных матриц нумерация элемента сетки "перевернута": вначале указывается номер колонки, а затем - номер строки.
Для изучения особенностей обработки матриц с помощью сетки рассмотрим пример конкретной формы вида:

На рисунке отображается сетка размером 6х6 элементов (ColCount=RowCount=6). так как 1 строка и 1 колонка отводится под фиксированные элементы (серого цвета), то фактический размер нашей матрицы составляет 5х5 элементов. Этот исходный размер отображается по умолчанию в двух текстовых полях справа.
Пользователь может задать любой размер своей матрицы и с помощью кнопки задать новый размер. Код кнопки может иметь вид:
procedure TForm1.Button1Click(Sender: TObject);
begin
//задаем число строк в сетке + 1 фиксированная строка (серая)
StringGrid1.RowCount:=StrToInt(Edit1.Text)+1;
//задаем число колонок в сетке + 1 фиксированная колонка (серая)
StringGrid1.colCount:=StrToInt(Edit2.Text)+1;
end;
2. Заполнение сетки
При создании программ по работе с матрицами обычно разработчик реализует два способа ввода исходных данных: автоматическое заполнение матрицы случайными числами и заполнение матрицы с клавиатуры. Первый способ ускоряет отладку программы, так как освобождает разработчика от необходимости каждый раз заново вводить данные вручную. Второй способ используется пользователем для ввода конкретных исходных данных в уже отлаженную программу.
По умолчанию сетка не поддерживает ввод с клавиатуры, так как у нее отключено соответствующее свойство. Для включения возможности заполнения сетки вручную установите для нее свойство Options - goEditing = true.
Что же касается автоматического заполнения сетки случайными числами, то пользователь должен будет указать концы отрезка для генерации случайного числа. Для этого на форме размещены два текстовых поля. Кнопка выполняет заполнение матрицы. Ее код может быть следующим:
procedure TForm1.Button2Click(Sender: TObject);
var
//переменные-счетчики цикла
i,j:integer;
//переменные для начала и конца отрезка
a,b:real;
begin
//включаем генератор случайных чисел
randomize;
//в переменные записываем начало и конец отрезка
a:=StrToFloat(Edit3.Text);
b:=StrToFloat(Edit4.Text);
//цикл по колонкам сетки
for i := 1 to StringGrid1.ColCount-1 do
//цикл по строкам сетки
for j := 1 to StringGrid1.RowCount - 1 do
//в ячейку записываем случайное число на отрезка a..b
//с округлением до 2 знаков
StringGrid1.Cells[i,j]:=FloatToStr(RoundTo((b-a)*Random+a,-2));
end;
Если пользователь планирует заполнять сетку вручную, то для ее очистки можно предусмотреть отдельную функцию. На форме для этого создана кнопка, код которой следующий:
procedure TForm1.Button3Click(Sender: TObject);
var
//переменные-счетчики цикла
i,j:integer;
begin
//цикл по колонкам сетки
for i := 0 to StringGrid1.ColCount-1 do
//цикл по строкам сетки
for j := 0 to StringGrid1.RowCount - 1 do
//каждую ячейку очищаем
StringGrid1.Cells[i,j]:='';
end;
3. Пример обработки матрицы в сетке
Над матрицами можно выполнять большое число всевозможных операций. Естественно, что любые операции с элементами матрицы выполняются внутри вложенных циклов. Для демонстрации рассмотрим 3 простые задачи, которые могут дать понимание принципов обработки матрицы целиком, отдельно по колонкам и отдельно по строкам.
На нашей форме реализованы функции расчета суммы элементов матрицы. Выбор типа расчета выполняется с помощью группы переключателей.
Первый расчет считает сумму элементов по всей матрице и отображает результат в надписи, расположенной под кнопкой.
Второй расчет считаем сумму по каждой колонке и отображает найденные результаты в фиксированной сроке над соответствующей колонкой.
Третий расчет считаем сумму по каждой строке и отображает найденные результаты в фиксированной колонке слева от соответствующей строки. Пример работы программы приведен на рисунке.

Вначале напишем отдельные фрагменты кода для каждой задачи, а затем "соберем" фрагменты в общий обработчик для кнопки.
Фрагмент кода расчета суммы по всей матрице
var
//переменные-счетчики цикла
i,j:integer;
//переменная для расчета суммы
sum:real;
begin
//вначале сумму обнуляем
sum:=0;
//цикл по колонкам сетки
for i := 1 to StringGrid1.ColCount-1 do
//цикл по строкам сетки
for j := 1 to StringGrid1.RowCount - 1 do
//если ячейка сетки не пустая
if StringGrid1.Cells[i,j]<>'' then
//суммируем ее значение к переменной
sum:=sum+StrToFloat(StringGrid1.Cells[i,j]);
//в надписи на форме показываем ответ
Label5.Caption:='Общая сумма = '+FloatToStr(RoundTo(sum,-2));
end;
Фрагмент кода расчета суммы по каждой колонке матрицы
Для расчета суммы по каждой колонке мы будем обнулять переменную sum на в начале цикла, а для каждой колонки. Полученный результат будем показывать в фиксированной строке (в сетке ее номер 0) в соответствующей колонке.
var
//переменные-счетчики цикла
i,j:integer;
//переменная для расчета суммы
sum:real;
begin
//цикл по колонкам сетки
for i := 1 to StringGrid1.ColCount-1 do
begin
//для очередной колонки сумму обнуляем
sum:=0;
//цикл по строкам сетки
for j := 1 to StringGrid1.RowCount - 1 do
//если ячейка сетки не пустая
if StringGrid1.Cells[i,j]<>'' then
//суммируем ее значение к переменной
sum:=sum+StrToFloat(StringGrid1.Cells[i,j]);
//на 0 строке в очередной колонке отображаем найденную сумму
StringGrid1.Cells[i,0]:=FloatToStr(RoundTo(sum,-2));
end;
end;
Фрагмент кода расчета суммы по каждой строке матрицы
Для расчета суммы по каждой строке будем использовать такой же код, что и для расчета суммы по колонке. Отличие в том, что циклы и нумерацию ячеек нужно "перевернуть". Полученный результат будем показывать в фиксированной колонке (в сетке ее номер 0) в соответствующей строке.
var
//переменные-счетчики цикла
i,j:integer;
//переменная для расчета суммы
sum:real;
begin
//берем цикл для колонок и "переворачиваем"
//цикл по строкам сетки
for i := 1 to StringGrid1.RowCount-1 do
begin
//для очередной строки сумму обнуляем
sum:=0;
//цикл по колонкам сетки
for j := 1 to StringGrid1.ColCount - 1 do
//если ячейка сетки не пустая
if StringGrid1.Cells[j,i]<>'' then
//суммируем ее значение к переменной
sum:=sum+StrToFloat(StringGrid1.Cells[j,i]);
//в 0 колонке на очередной строке отображаем найденную сумму
StringGrid1.Cells[0,i]:=FloatToStr(RoundTo(sum,-2));
end;
end;
Полный код для кнопки на форме
Теперь на основе фрагментов приведем полный код обработки матрицы с использованием группы переключателей.
procedure TForm1.Button4Click(Sender: TObject);
var
//переменные-счетчики цикла
i,j:integer;
//переменная для расчета суммы
sum:real;
begin
//проверяем, какой из переключателей выбран
case radiogroup1.itemindex of
//если выбран первый
//(фрагмент расчета по всей матрице)
0: begin
//вначале сумму обнуляем
sum:=0;
//цикл по колонкам сетки
for i := 1 to StringGrid1.ColCount-1 do
//цикл по строкам сетки
for j := 1 to StringGrid1.RowCount - 1 do
//если ячейка сетки не пустая
if StringGrid1.Cells[i,j]<>'' then
//суммируем ее значение к переменной
sum:=sum+StrToFloat(StringGrid1.Cells[i,j]);
//в надписи на форме показываем ответ
Label5.Caption:='Общая сумма = '+FloatToStr(RoundTo(sum,-2));
end;
//если выбран второй переключатель
//(фрагмент расчета суммы по колонкам)
1: begin
//цикл по колонкам сетки
for i := 1 to StringGrid1.ColCount-1 do
begin
//для очередной колонки сумму обнуляем
sum:=0;
//цикл по строкам сетки
for j := 1 to StringGrid1.RowCount - 1 do
//если ячейка сетки не пустая
if StringGrid1.Cells[i,j]<>'' then
//суммируем ее значение к переменной
sum:=sum+StrToFloat(StringGrid1.Cells[i,j]);
//на 0 строке в очередной колонке отображаем найденную сумму
StringGrid1.Cells[i,0]:=FloatToStr(RoundTo(sum,-2));
end;
end;
//если выбран третий переключатель
//(фрагмент расчета суммы по строкам)
2: begin
//берем цикл для колонок и "переворачиваем"
//цикл по строкам сетки
for i := 1 to StringGrid1.RowCount-1 do
begin
//для очередной строки сумму обнуляем
sum:=0;
//цикл по колонкам сетки
for j := 1 to StringGrid1.ColCount - 1 do
//если ячейка сетки не пустая
if StringGrid1.Cells[j,i]<>'' then
//суммируем ее значение к переменной
sum:=sum+StrToFloat(StringGrid1.Cells[j,i]);
//в 0 колонке на очередной строке отображаем найденную сумму
StringGrid1.Cells[0,i]:=FloatToStr(RoundTo(sum,-2));
end;
end;
end; //конец оператора case
end; //конец процедуры обработчика