Procedure TForm1.Edit3KeyPress

(Sender: TObject; var Key: Char);

begin

if Length(Edit3.Text) = 0 then begin

if not (key in ['+','-','*','/']) then key:=#0;

end else key:=#0;

end;

procedure TForm1.Edit1Exit(Sender: TObject);

begin

a:=StrToInt(Edit1.Text);

end;

procedure TForm1.Edit2Exit(Sender: TObject);

begin

b:=StrToInt(Edit2.Text);

end;

procedure TForm1.Edit3Exit(Sender: TObject);

var С:Char;

begin

if Length(Edit3.Text) > 0 then begin

С:=Edit3.Text[1];

case С of

'+': Operat:=Plus;

'-': Operat:=Minus;

'*': Operat:=Mult;

'/': Operat:=Divide;

end;

end else Operat:=None;

end;

procedure TForm1.Button1Click(Sender: TObject);

var Z:Real;

begin

Z := 0.0;

case Operat of

Plus: Z:=a+b;

Minus: Z:=a-b;

Mult: Z:=a*b;

Divide:

if b=0 then begin

Edit4.Text:='Деление на 0';

Exit;

end else

Z := a/b;

None: begin

Edit4.Text := 'Операции нет';

Exit;

end;

end;

Edit4.Text := FormatFloat('0.00',Z);

end;

End.

Необходимо отметить, что обработчик OnKeyPress для Edit3 содержит объявление переменной C символьного типа для записи вводимого знака арифметической операции, так как непосредственное использование строки Edit3.Text в качестве селектораоператора Case запрещено. Кроме того, в этом обработчике с помощью функции Length(S) (длина строки S) проверяется, был ли осуществлен ввод символа.

Обработчик событий OnKeyPress для Edit3 усложнён, – разрешается ввод только одного символа. Дополнительные ключевые слова begin и end (составной оператор) в этом обработчике необходимы, чтобы снять неоднозначность использования else – к какому ifданное ключевое слово else относится. Кроме указанного выше составного оператора, следует обратить внимание на другие составные операторы данной программы.

В обработчике Button1Click используется процедура Exit для непосредственного выхода из обработчика. Обработчик для Edit1 одновременно используется и для Edit2, как и в предыдущем примере 2. Кроме того, следует обратить внимание, что, кроме цифровых символов, этот обработчик разрешает ввод символа минус для отрицательных чисел.

ИСПОЛЬЗОВАНИЕ ENTER В ПРИМЕРЕ 3

Часто при окончании ввода в элементе редактирования и переходе к следующему управляющему элементу оказывается более удобным использование клавиши Enter вместо Tab. Рассмотрим этот вопрос на примере 3.

Стандартным подходом в данном случае при обнаружении нажатия клавиши Enter является подход с применением передачи фокуса c помощью метода SetFocus или свойства ActiveControl. Все, что нужно сделать в примере 3, - переписать обработчики OnKeyPress в следующем виде:

procedure TForm1.Edit1KeyPress(Sender: TObject;

var Key: Char);

begin

if key=#13 then

if Sender = Edit1 then Form1.ActiveControl:=Edit3

else Button1.SetFocus;

if not (key in ['0'..'9','-', #8]) then key:=#0;

end;

Procedure TForm1.Edit3KeyPress

(Sender: TObject; var Key: Char);

begin

if key=#13 then Form1.ActiveControl:=Edit2;

if Length(Edit3.Text) = 0 then begin

if not (key in ['+','-','*','/']) then key:=#0;

end else key:=#0;

end;

Другим подходом является применение процедуры SelectNext, которая может передавать фокус следующему или предыдущему управляющему элементу. Рассматриваемая процедура имеет следующее описание: SelectNext(CurControl:

TwinControl; GoForward, CheckTabStop: Boolean),где CurControlуказывает на оконный управляющий элемент, относительно которого выполняется передача фокуса; параметр GoForward определяет направление передачи фокуса: следующий элемент (True) или предыдущий (False); параметр CheckTabStop определяет, нужно ли учитывать значение свойства TabStop управляющего элемента, который должен получить фокус. Применение данной процедуры может оказаться проще, чем предыдущий подход. Например, перепишем первый оператор в обработчике Edit1KeyPress примера 3:

if key=#13 then SelectNext(Sender as TWinControl,

true,true);

В данном случае Sender имеет тип Tobject, а необходим тип TWinControl, поэтому выполнено явное преобразование типов с помощью операции as. В заключение одно замечание. Чтобы был осуществлен правильный переход от Edit2 к Button1 (а не к Edit4), необходимо установить для Edit4 свойство TabStop=true.

Возможен еще один подход обработки нажатия клавиши Enter с помощью SelectNext – можно использовать обработчик OnKeyPress самой формы. Для этого необходимо установить свойство формы KeyPreview=true, чтобы обработчик формы получил сообщение о нажатии клавиш первым.

ОПЕРАТОРЫ ЦИКЛА

Операторы цикла используются для программирования циклических вычислительныз процессов. Циклический вычислительный процесс представляет собой неоднократно повторяющиеся вычисления при различных значениях исходных данных. Однократное выполнение расчета внутри цикла называется итерацией. Например, пусть требуется построить график Y = f(X) на отрезке [a;b] с шагом H. Для этого необходимо провести циклические, повторяющиеся вычисления в соответствии с табл. 10.

Таблица 10

Пример циклических вычислений

X f(X) Число итераций Procedure TForm1.Edit3KeyPress - student2.ru Procedure TForm1.Edit3KeyPress - student2.ru
a Y = f(a)
a+h Y = f(a+h)
. . . . . . . . . . . . .
b Y = f(b)


Существуют три оператора цикла: операторы For, While и Repeat.

ОПЕРАТОР ЦИКЛА FOR

Оператор For позволяет организовать выполнение какого-либо другого оператора заранее заданное число раз. Существуют 2 варианта этого оператора:

A. For <управляющая переменная> := <Start> to <Finish> do <оператор>;

B. For <управляющая переменная> := <Start> downto <Finish> do <оператор>;

Управляющая переменная позволяет ограничить количество расчетов заданного оператора, которое зависит от значений выражений <Start>и <Finish>. Выражение <Start> определяет начальное значение управляющей переменной, выражение <Finish> – конечное значение. При каждой итерации управляющая переменная увеличивается на единицу в операторе А и уменьшает своё значение на единицу в операторе B. Как только значение управляющей переменной превзойдет значение <Finish> в операторе A (станет меньше в операторе B), цикл прекращается. Выражения <Start> и <Finish> должны возвращать значения порядкового типа - соответственно <управляющая переменная> должна также иметь порядковый тип. Например,

FOR I:= 1 TO 10 DO Y:=sin(X);

FOR I:= 10 DOWNTO 1 DO Y:=sin(X);

Если в самом начале цикла значение <Finish>будет больше, чем значение <Start> для оператора А или значение <Finish>меньше, чем <Start> для оператора B, то не будет выполнено ни одной итерации.

В Delphi скорость выполнения циклических вычислений оптимизирована, поэтому имеют место ограничения на управляющую переменную:

· должна иметь порядковый тип;

· должна быть объявлена в том же блоке, в котором помещен цикл, т. е. должна быть локальной.

ПРИМЕР 4

Пусть требуется рассчитать табл. 10 и построить на экране дисплея график y = f(x) = sin(x). Шаг изменения координат x и y графика зададим в пикселах и пусть, h = 1. В данном случае имеют место два типа графиков: физический и дисплейный. Пусть X, Y, Н - координаты и шаг физического графика, x, y, h - координаты и шаг дисплейного графика. Прежде, чем рисовать график, необходимо выполнить преобразование физических координат в дисплейные (или масштабирование) так, чтобы дисплейный график верно отражал процесс, смоделированный физическим графиком. Физический график начинается в точке x = a и заканчивается в точке x = b. Пусть дисплейный график начинается в точке X = xn и продолжается до точки X = xk (рис. 16). Выберем следующую схему построения дисплейного графика:

1) Используя заданное h, находим текущее значение x;

2) Рассчитываем H и находим значение физической переменной X;

3) Определяем Y;

4) Преобразуем Y в y;

5) На экране дисплея отображаем полученную точку x и y.

 
 
Procedure TForm1.Edit3KeyPress - student2.ru Рис. 16. Физический и дисплейный графики.

Введем масштаб my. и запишем соотношение y = my×Y. Так как данное соотношение справедливо для любой точки графика, необходимо, чтобы оно выполнялось и при значении ymax = my× Ymax(все значения y будут воспроизводиться на экране). Из этого соотношения можно определить масштаб my, т.е. Procedure TForm1.Edit3KeyPress - student2.ru . Максимальное значение Ymax в данном случае для функции sin(X) равно 1, а для дисплейного графика ymax задаётся, в общем случае, произвольно.

Теперь найдём соотношение между x и X (или между h и H, что одно и то же). Примем, чтобы количество точек по оси абсцисс для дисплейного и физического графиков было одинаковым. Чтобы это выполнялось, необходимо согласовать значение шага H для физического графика с выбранным h для дисплейного графика. Запишем

Procedure TForm1.Edit3KeyPress - student2.ru ,

откуда следует Procedure TForm1.Edit3KeyPress - student2.ru , обозначив Procedure TForm1.Edit3KeyPress - student2.ru ,

получим требуемое соотношение H = mx×h.

Для размещения графика понадобится компонент TImage (страница Additional). Форма примера 4 приводится на рис. 17. Какие объекты используются в данном примере, можно найти в тексте программы.

Procedure TForm1.Edit3KeyPress - student2.ru

Рис. 17. Форма к примеру 4.

Компонент TImage используется для рисования графических объектов и геометрических фигур. Полезным свойством компонента TImage является Canvas (холст), которое включает, в частности, свойства Pen, Brush. Канва имеет методы: MoveTo (используется для перемещения невидимого графического курсора в заданную точку) и LineTo(позволяет рисовать линии). Эти два метода используются для рисования графика на канве TImage. Координаты задаются в пикселах, горизонтальная ось направлена слева направо, вертикальная - сверху вниз. Вариант решения задачи приводится на рис. 18.

Procedure TForm1.Edit3KeyPress - student2.ru

Рис. 18. Результат решения примера 4.

Выбраны следующие размеры для Image1: Width = 305, Height = 154. Ось абсцисс проведена при значении y0 = 75. Текст программы приведен ниже.

unit prim4;

Interface

uses Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls, Buttons,

ExtCtrls;

Type TForm1 = class(TForm)

Panel1: TPanel;

Button1: TButton;

BitBtn1: TBitBtn;

Edit1: TEdit;

Label1: TLabel;

Edit2: TEdit;

Label2: TLabel;

Image1: TImage;

Label3: TLabel;

Bevel1: TBevel;

procedure Edit1KeyPress(Sender: TObject;

var Key: Char);

procedure Button1Click(Sender: TObject);

end;

var Form1: TForm1;

Implementation

{$R *.DFM}

procedure TForm1.Edit1KeyPress(Sender: TObject;

var Key: Char);

begin

if not (key in ['0'..'9','-','.',#8]) then key:=#0;

end;

procedure TForm1.Button1Click(Sender: TObject);

var a,b:real;

xn,xk,y0,yk:integer;

mx,my:real;

x,y,ymax:real;

i:integer;

Begin

xn:=15;

xk:=280;

y0:=75;

yk:=70;

a:=StrToFloat(Edit1.Text);

b:=StrToFloat(Edit2.Text);

ymax:=1.0;

{Зададим цвет и толщину пера}

Image1.Canvas.Pen.Color:=clBlack;

Image1.Canvas.Pen.Width:=1;

{Закрасим цветом фона предыдущий график}

Image1.Canvas.Brush.Color:=clWhite;

Image1.Canvas.Rectangle(0,0,Image1.Width,

Image1.Height);

{Рисуем оси координат}

Image1.Canvas.MoveTo(xn,y0);

Image1.Canvas.LineTo(xk,y0);

Image1.Canvas.MoveTo(xn,y0+yk);

Image1.Canvas.LineTo(xn,y0-yk);

{Проверяем, введено ли b < a}

if b>=a then begin

Label3.Caption:= 'Графика нет';

Exit;

end else Label3.Caption:= '';

{Устанавливаем цвет и толщину карандаша для графика}

Image1.Canvas.Pen.Color:=clRed;

Image1.Canvas.Pen.Width:=2;

mx:=(b-a)/(xk-xn);

my:=yk/ymax;

{Устанавливаем начальную точку графика}

Image1.Canvas.MoveTo(xn,y0-round(my*sin(a)));

{Строим график в цикле for}

for i:=1 to xk-xn do begin

x:=a+i*mx;

y:=my*sin(x);

Image1.Canvas.LineTo(xn+i,y0-round(y));

end;

end;

End.

В обработчике событий OnKeyPress учтено, что вводятся вещественные числа. Используемая функция Round(Z) преобразует вещественное число Z в целое с предварительным округлением. Для того чтобы возможно было неоднократное построение графика, необходимо стирать предыдущий график.

ОПЕРАТОР ЦИКЛА WHILE

В отличие от оператора For, оператор цикла While используется, когда заранее неизвестно количество выполняемых итераций. Этот оператор записывается так:

While <логическое выражение> do <оператор>;

Итерации выполняются до тех пор, пока логическое выражение остается истинным. Если с самого начала значение логического выражения ложно, то оператор While будет пропущен.

ПРИМЕР 5

Найти все делители целого числа X, кроме единицы и самого числа. Воспользуемся простейшим алгоритмом. Будем перебирать все делители, начиная с числа 2, и проверять, делится ли нацело заданное число X. Очевидно, последний делитель, который следует проверять, равен половине числа X. Если ни одного делителя не найдено, то число - простое. Будем исследовать только положительные числа. Воспользуемся в этом примере компонентом TListBox. Форма с вариантом решения задачи приведена на рис. 19.

Procedure TForm1.Edit3KeyPress - student2.ru

Рис. 19 Форма с вариантом решения примера 5.

Интерфейсный элемент TListBox позволяет представить список объектов (свойство Items), чаще всего строк (класс TStrings), из которых можно выбрать один элемент. Если список не умещается на экране, то возможнна его прокрутка по вертикали. Список можно представлять не только в один столбец - количество столбцов задаётся свойством Columns. Если Columns > 1, то разрешается и горизонтальная прокрутка элементов. Элементы списка могут, например, динамически добавляться. При этом используется свойство Items с соответствующим методом Add(Items.Add) – добавить. Какой элемент выбран, запоминается в свойстве ItemIndex. Можно задать одновременный выбор нескольких элементов в списке с помощью свойства MultiSelect. Компонент имеет много других разнообразных свойств, что делает его удобным для отображения данных (например, свойство Sorted позволяет представлять список в алфавитном порядке и др.).

Ниже приводится программа для примера 5.

unit prim5;

Interface

uses Windows, Messages, SysUtils,

Classes,Graphics, Controls, Forms, Dialogs,

StdCtrls, Buttons, ExtCtrls;

Type

TForm1 = class(TForm)

Panel1: TPanel;

Button1: TButton;

BitBtn1: TBitBtn;

Bevel1: TBevel;

Label1: TLabel;

Edit1: TEdit;

ListBox1: TListBox;

Label2: TLabel;

Label3: TLabel;

procedure Edit1KeyPress(Sender: TObject;

var Key: Char);

procedure Button1Click(Sender: TObject);

end;

var Form1: TForm1;

Implementation

{$R *.DFM}

procedure TForm1.Edit1KeyPress(Sender: TObject;

var Key: Char);

begin

if not (key in ['0'..'9',#8]) then key:=#0;

end;

procedure TForm1.Button1Click(Sender: TObject);

var x,half,divider:word;

i:byte;

begin

Label3.Caption:='';

ListBox1.Items.Clear;

x:=StrToInt(Edit1.Text);

half:=x div 2;

divider:=2;

i:=0;

While divider <= half do begin

if x mod divider = 0 then begin

inc(i);

ListBox1.Items.Add(IntToStr(i)+'-й делитель='

+ IntToStr(divider));

end;

inc(divider);

end;

if i=0 then Label3.Caption:='Число простое';

end;

End.

В отличие от оператора цикла For, который автоматически изменяет управляющую переменную и управляет циклом, в операторе While программист должен сам организовать управление, заключающееся в следующем:

ü выбрать какую-либо управляющую переменную, в данном случае i – счётчик циклов;

ü присвоить ей начальное значение, например i:= 0;

ü в операторе While записать условие продолжения выполнения цикла, например divider <= half;.(Как только это условие станет равным false, цикл закроется);

ü внутри цикла осуществлять изменение управляющей переменной на каждой итерации, например inc(i) – увеличить значение i на единицу.

ОПЕРАТОР ЦИКЛА REPEAT

Оператор цикла Repeat записывается следующим образом: Repeat

<Оператор1>;

. . . . . . . . . . .

<ОператорN>;

Until <логическое выражение>;

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

ПРИМЕР 6

Рассчитать с точностью e сумму следующего ряда:

Procedure TForm1.Edit3KeyPress - student2.ru ,

где X – какое-либо число из диапазона –1 <= X <= 1.

Точность e означает следующее. Обозначим Procedure TForm1.Edit3KeyPress - student2.ru член ряда; суммирование (вычисление Y) продолжать до тех пор, пока значение а не станет меньше e.

Procedure TForm1.Edit3KeyPress - student2.ru Вывести на экран историю расчета, т.е. какое значение на каждой итерации имели величины a и Y, в следующем виде: итерация 1 а = y = итерация 2 а = y = и т.д.

На рис. 20 построен алгоритм расчета суммы ряда. В этом алгоритме введена дополнительная переменная b для отслеживания знака очередного члена ряда.

На рис. 21 приводится форма с вариантом расчета. Расположенные на форме компоненты можно определить, исходя из текста программы, который приводится ниже.

Для решения данной задачи был использован компонент TMemo. Этот элемент управления служит для получения какого-либо текста пользователя и его отображения на экране. TMemo называют многострочным редактором (однострочным редактором является компонент TEdit.).

Доступ ко всему тексту может быть получен через свойство Text. Свойство Linesпредставляет весь текст в виде совокупности строк. Все строки в TMemo пронумерованы, начиная от нуля. Если на экране строки полностью не отображаются (задана маленькая ширина Width), то с помощью свойства WordWrap можно управлять переносом строк. TMemo имеет свойство ScrollBars – можно устанавливать полосы прокрутки. По умолчанию: ScrollBars установлено равным ssNone. Можно задать центрирование строк с помощью свойства Alignment. Свойство Lines содержит методы Add(добавить), Delete(удалить), Insert(вставить).

Procedure TForm1.Edit3KeyPress - student2.ru

Рис. 21 Форма с вариантом решения примера 6.

Для Memo1 в инспекторе объектов установлено свойство WordWrap равным true, а свойство ScrollBars – ssVertical. Далее приводится программа.

unit prim6;

Interface

uses Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs,

StdCtrls, Buttons, ExtCtrls;

Type

TForm1 = class(TForm)

Panel1: TPanel;

Button1: TButton;

BitBtn1: TBitBtn;

Bevel1: TBevel;

Memo1: TMemo;

Label1: TLabel;

Label2: TLabel;

Edit1: TEdit;

Edit2: TEdit;

Label3: TLabel;

procedure Edit1KeyPress(Sender: TObject;

var Key: Char);

procedure Button1Click(Sender: TObject);

procedure Edit1Exit(Sender: TObject);

end;

var Form1: TForm1;

Implementation

{$R *.DFM}

procedure TForm1.Edit1KeyPress(Sender: TObject;

var Key: Char);

begin

if not (key in ['0'..'9','-','.',#8]) then key:=#0;

end;

procedure TForm1.Button1Click(Sender: TObject);

var x,y,a,b,eps:real;

n:byte;

begin

Memo1.Lines.Clear;

y:=0.0;

n:=0;

b:=-1.0;

x:=StrToFloat(Edit1.Text);

eps:=StrToFloat(Edit2.Text);

Repeat

b:=-b*x;

inc(n);

a:=b/n;

y:=y+a;

Memo1.Lines.Add('Итерация'+IntToStr(n)+' a=' +

FormatFloat('0.00000',a)+' y='+

FormatFloat('0.0000',y));

Until abs(a) < eps;

end;

procedure TForm1.Edit1Exit(Sender: TObject);

begin

if Abs(StrToFloat(Edit1.Text))>1.0 then

if Application.MessageBox('Введите число X',

'Число /X/<=1', MB_OK)=IDOK then Edit1.SetFocus;

end;

End.

В приведенной программе обработчик события Button1Click написан по алгоритму рис. 20, кроме одного дополнения – внутрь цикла добавлена процедура формирования истории расчета с помощью объекта Memo1. Обработчик Edit1Exit отслеживает условие: X по модулю должно быть не больше 1. В случае невыполнения этого условия вызывается стандартное диалоговое окно объекта Application MessageBox. Синтаксически подпрограмма MessageBoxоформлена в виде функции. При вызове функции MessageBox необходимо указать три параметра:

1) текст-подсказка, что надо делать;

2) заголовок диалогового окна;

3) вариант внешнего вида окна – константа MB_OK указывает, что окно с одной кнопкой.

Значение функции вызова диалогового окна сравнивается с константой IDOK. В данном случае любой вариант ответа пользователя приводит к возврату операции ввода числа X (Edit1.SetFocus – установить фокус на объект Edit1).

Наши рекомендации