
Листинг 2. Процедура обработки события OnKeyPress
procedure TForm1.StringGrid1KeyPress(Sender: TObject; var Key: Char);
begin
case Key of
#8,'0'..'9' : ; // цифры и <Back Space>
#13: // <Enter>
if StringGrid1.Col < StringGrid1.ColCount – 1 then
StringGrid1.Col := StringGrid1.Col + 1
else
if StringGrid1.Row < StringGrid1.RowCount – 1 then
begin
StringGrid1.Row:= StringGrid1.Row+1 ;
StringGrid1.Col := StringGrid1.FixedCols;
end;
else Key:=Chr(0);
end;
end;
Этот обработчик позволяет вводить целые положительные числа в компонент StringGrid и при нажатии клавиши <Enter> осуществляет перход в следующую ячейку. Обратите внимание, что обработчик может быть использован для двумерного массива. В этом случае если пользователь нажал клавишу <Enter>, находясь в последней ячейке строки, осуществляется переход в первую ячейку рабочей области на следующей строке. Если же вы планируете работать с одномерным массивом, то ветку else оператора if следует опустить.
Задание. Ввод массива из компонента StringGrid оформите в виде отдельной процедуры. Внесите
необходимые изменения в обработчик нажатия кнопки.
Если нужно ввести массив дробных чисел (a: array [1. .5] of real), то процедура обработки события OnKeyPress несколько усложнится, т. к. помимо цифр допустимыми символами являются символ-разделитель (запятая или точка — зависит от настройки Windows) и минус. С целью обеспечения некоторой дружественности программы по отношению к пользователю можно применить трюк: подменить вводимый пользователем неверный разделитель верным. Определить, какой символ-разделитель допустим в текущей настройке Windows, можно, обратившись к глобальной переменной Decimaiseparator.
В листинге 3 приведен текст модуля приложения ввода и обработки массива дробных чисел. Процедура обработки события OnKeyPress обеспечивает ввод в ячейку таблицы только допустимых при записи дробного числа символов.
Листинг 3. Ввод и обработка массива дробных чисел
unit getar_1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grids, StdCtrls;
const n=5;
type
TIntArr = array[1..n] of integer;
TForm1 = class(TForm)
Label1: TLabel;
StringGrid1: TStringGrid;
Button1: TButton;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
procedure StringGrid1KeyPress(Sender: TObject; var Key: Char);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
A : TIntArr;
implementation
{$R *.dfm}
// Процедура обработки массива
procedure CalcArr(A: array of real; var s, sr : real);
var
i : integer;
begin
s:=0;
for i:=low(A) to high(A) do
s := s + A[i];
sr := s / length(A);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
summ: real; // сумма элементов
sr: real; // среднее арифметическое
i: integer; // индекс
begin
// ввод массива
// считаем, что если ячейка пустая, то соответствующий
// ей элемент массива равен нулю
for i:= 1 to StringGrid1.ColCount do
begin
if StringGrid1.Cells[i-1,0] = ''
then
StringGrid1.Cells[i-1,0]:='0';
A[i] := StrToFloat(StringGrid1.Cells[i-1,0])
end;
CalcArr(A,summ,sr);
// вывод результата
Label2.Caption :=
'Сумма элементов: ' + FloatToStr(summ) + #13+
'Среднее арифметическое: ' + FloatToStr(sr);
end;
// Функция обеспечивает ввод в ячейку только допустимых символов
procedure TForm1.StringGrid1KeyPress(Sender: TObject; var Key: Char);
begin
case Key of
#8,'0'..'9' : ; // цифры и <Back Space>
#13: // клавиша <Enter>
if StringGrid1.Col < StringGrid1.ColCount – 1 then
StringGrid1.Col := StringGrid1.Col + 1
else
if StringGrid1.Row < StringGrid1.RowCount – 1 then
begin
StringGrid1.Row:= StringGrid1.Row+1 ;
StringGrid1.Col := StringGrid1.FixedCols;
end;
'.',',': // разделитель целой и дробной частей числа
begin
Key := DecimalSeparator; // заменим разделитель на допустимый
if Pos(DecimalSeparator , StringGrid1.Cells[StringGrid1.Col,0]) <> 0
then Key := Chr(0); // запрет ввода второго разделителя
end;
'-': // минус можно ввести только первым символом,
// т.е. когда ячейка пустая
if Length(StringGrid1.Cells[StringGrid1.Col,0]) <> 0
then Key := Chr(0);
else // остальные символы запрещены
key := Chr(0);
end;
end;
end.
В приведенных примерах размерность массива была известна заранее. Часто размерность массива на этапе проектирования неизвестна и/или может меняться в процессе работы. В этих случаях целесообразно использовать не статические, а динамические массивы.
Пусть, например, в рассмотренной задаче размерность обрабатываемого массива задается при помощи компонента SpinEdit. На форме дополнительно расположим компоненты SpinEdit и кнопку (рис. 2)
Рис.2
Установим у SpinEdit значения свойств MinValue=1 и MaxValue=100. Для кнопки зададим Name=btnSetDim. В разделе implementation опишем тип TRealVector для работы с динамическим массивом вещественных чисел и глобальную переменную VectCount для хранения количества элементов в массиве. В обработчике создания формы зададим начальное значение для переменной VectCount =5.
В листинге 4 приведен фрагмент модуля обработки массива вещественных чисел с заданием его размерности. Обработчик OnKeyPress для StringGrid в этом примере такой же как в предыдущем, и в листинге не приводится. Жирным шрифтом выделены фрагменты кода в которых листинги 3 и 4 отличаются.
Листинг 4. Ввод и обработка массива изменяемой размерности
type
TRealVector=array of real;
var
Form1: TForm1;
VectCount : integer;
A : TRealVector;
implementation
{$R *.dfm}
// Процедура обработки массива
procedure CalcArr(A:TRealVector ; var s, sr : real);
var
i : integer;
begin
s:=0;
for i:=low(A) to high(A) do
s := s + A[i];
sr := s / length(A);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
summ: real; // сумма элементов
sr: real; // среднее арифметическое
i: integer; // индекс
begin
// ввод массива
// считаем, что если ячейка пустая, то соответствующий
// ей элемент массива равен нулю
SetLength(a,VectCount);
for i:= 0 to StringGrid1.ColCount -1 do
begin
if StringGrid1.Cells[i,0]=''
then
StringGrid1.Cells[i,0]:='0';
A[i] := StrToFloat(StringGrid1.Cells[i,0])
end;
CalcArr(A,summ,sr);
// вывод результата
Label2.Caption :=
'Сумма элементов: ' + FloatToStr(summ) + #13+
'Среднее арифметическое: ' + FloatToStr(sr);
end;
procedure TForm1.btnSetDimClick(Sender: TObject);
var
i: integer;
begin
StringGrid1.ColCount:=SpinEdit1.Value;
VectCount:= SpinEdit1.Value;
if StringGrid1.ColCount>5 then StringGrid1.Height:=48 // для полосы прокрутки
else StringGrid1.Height:=24;
for i:=0 to StringGrid1.ColCount do StringGrid1.Cells[i,0]:='';
Label2.Caption := '';
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
VectCount:=5;
end;
end.
Задание. Ввод массива из компонента StringGrid оформите в виде отдельной процедуры. Внесите
необходимые изменения в обработчик нажатия кнопки.