Функция
Функция — это подпрограмма, т. е. последовательность инструкций, имеющая имя.
Процесс перехода к инструкциям функции называется вызовом функции или обращением к функции. Процесс перехода от инструкций функции к инструкциям программы, вызвавшей функцию, называется возвратом из функции.
В общем виде инструкция обращения к функции выглядит так:
Переменная := Функция (Параметры) ;
где:
переменная — имя переменной, которой надо присвоить значение, вычисляемое функцией;
Функция — имя функции, значение которой надо присвоить переменной;
Параметры — список формальных параметров, которые применяются для вычисления значения функции. В качестве параметров обычно используют переменные или константы.
Следует обратить внимание на то, что:
каждая функция возвращает значение определенного типа, поэтому тип переменной, которой присваивается значение функции, должен соответствовать типу функции;
тип и количество параметров для каждой конкретной функции строго определены.
Объявление функции
Объявление функции в общем виде выглядит так:
function Имя (параметр1 : тип1, ..., параметрК : типК) : Тип; var// здесь объявления локальных переменных begin
// здесь инструкции функции
Имя := Выражение; end;
где:
function — зарезервированное слово языка Delphi, обозначающее, что далее следуют инструкции, реализующие функцию программиста;
имя — имя функции. Используется для перехода из программы к инструкциям функции;
параметр — это переменная, значение которой используется для вычисления значения функции. Отличие параметра от обычной переменной состоит в том, что он объявляется не в разделе объявления переменных, который начинается словом var, а в заголовке функции. Конкретное значение параметр получает во время работы программы в результате вызова функции из основной программы;
тип — тип значения, которое функция возвращает в вызвавшую ее программу.
Следует обратить внимание, что последовательность инструкций, реализующих функцию, завершается инструкцией, которая присваивает значение имени функции. Тип выражения, определяющего значение функции, должен совпадать с типом функции, указанным в ее объявлении.
В качестве примера в листинге 6.3 приведены функции isint и isFioat. Функция isint проверяет, является ли символ, соответствующий клавише, нажатой во время ввода целого числа в поле редактирования, допустимым. Предполагается, что допустимыми являются цифры, клавиши <Enter> и <Backspace>. Функция IsFloat решает аналогичную задачу, но для дробного числа. У функции IsFloat два параметра: код нажатой клавиши и строка символов, которая уже введена в поле редактирования.
Листинг 6.3. Примеры
функций
// во время ввода целого числа
function Islnt(ch : char) : Boolean;
begin
if (ch >= '0'} and (ch <= '9') // цифры
or (ch = 113) // клавиша <Enter>
or (ch = #8) // клавиша <Backspace>
then Islnt := True // символ допустим else Islnt := False; // недопустимый символ
end;
// проверяет, является ли символ допустимым
// во время ввода дробного числа
function IsFloat(ch : char; st: string) : Boolean;
begin
if (ch >= '0') and (ch <= '9') // цифры
or (ch = #13) // клавиша <Enter>
or (ch = #8) // клавиша <Backspace>
then
begin
IsFloat := True; // символ верный Exit; // выход из функции
end; case ch of
'-': if Length(st) = 0 then IsFloat := True; ',': if (Pos(',',st) = 0)
and (st[Length(st)]'>= '0') and (st[Length(st)] <= '9')
then // разделитель можно ввести только после цифры // и если он еще не введен
IsFloat := True; else // остальные символы запрещены
IsFloat := False; end; end;
Использование функции
Если вы собираетесь использовать в программе свою функцию, то в простейшем случае ее объявление следует поместить в текст программы, перед подпрограммой, которая применяет эту функцию.
Рис. 6.1. Окно
программы Поездка на дачу
используют функцию IsFioat для фильтрации вводимых в эти поля символов, во время работы программы в полях ввода отображаются только допустимые символы.
Листинг 6.4. Пример
использования функций программиста
interface
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit; // расстояние
Edit2: TEdit; // цена литра бензина
Edit3: TEdit; // потребление бензина на 100 км
CheckBox1: TCheckBox; // True - поездка туда и обратно
Button1: TButton; // кнопка Вычислить
Label4: TLabel; // поле вывода результата расчета
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure EditlKeyPress(Sender: TObject; var Key: Char);
procedure Edit2KeyPress(Sender: TObject; var Key: Char);
procedure Edit3KeyPress(Sender: TObject; var Key: Char);
procedure Button1Click(Sender: TObject); private
{ Private declarations } public
{ Public declarations } end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// проверяет, является ли символ допустимым
// во время ввода дробного числа
function IsFloat(ch : char; st: string) : Boolean;
begin
if (ch >= '0') and (ch <= '9') // цифры
or (ch = #13) // клавиша <Enter>
or (ch = #8) // клавиша <Backspace>
then
begin
IsFloat := True; // символ верный Exit; // выход из функции
end; case ch of
'-': if Length(st) = 0 then IsFloat := True; ', ': if (Pos(',',st) = 0)
and (st[Length(st)] >= '0') and (st[Length(st)] <= '9')
then // разделитель можно ввести только после цифры // и если он еще не введен
IsFloat := True/else // остальные символы запрещены
IsFloat := False; end; end;
// нажатие клавиши в поле Расстояние
procedure TForm1.EditlKeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then Edit2.SetFocus // переместить курсор в поле Цена else If not IsFloat(Key,Edit2.Text) then Key := Chr(O);
end;
// нажатие клавиши в поле Цена
procedure TForml.Edit2KeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then Edit3.SetFocus // переместить курсор в поле Потребление else If not IsFloat(Key,Edit2.Text) then Key := Chr (0);
end;
// нажатие клавиши в поле Потребление
procedure TForml.Edit3KeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then Buttonl.SetFocus // // сделать активной кнопку Вычислить else If not IsFloat(Key,Edit2.Text) then Key := Chr (0);
end;
// щелчок на кнопке Вычислить
procedure TForm1.ButtonlClick(Sender: TObject);
var
rast : real; // расстояние
cena : real; // цена
potr : real; // потребление на 100 км
summ : real; // сумма
mes: string; begin
rast := StrToFloat(Edit1.Text);
cena := StrToFloat(Edit2.Text);
potr := StrToFloat(Edit3.Text);
summ := rast / 100 * potr * cena;
if CheckBoxl.Checked then summ := summ * 2;
mes := 'Поездка на дачу';
if CheckBoxl.Checked then mes := mes + ' и обратно';
mes := mes + 'обойдется в ' + FloatToStrF(summ,ffGeneral,4,2) + ' руб.';
Label4.Caption := mes; end; end.
Процедура
Процедура — это разновидность подпрограммы. Обычно подпрограмма реализуется как процедура в двух случаях:
когда подпрограмма не возвращает в основную программу никаких данных. Например, вычерчивает график в диалоговом окне;
когда подпрограмма возвращает в вызвавшую ее программу больше чем одно значение. Например, подпрограмма, которая решает квадратное уравнение, должна вернуть в вызвавшую ее программу два дробных числа — корни уравнения.
Объявление процедуры
В общем виде объявление процедуры выглядит так: procedure Имя (var параметр1: тип1; ... var параметрК: типК) ; var
// здесь объявление локальных переменных begin
// здесь инструкции процедуры end;
где:
procedure — зарезервированное слово языка Delphi, обозначающее, что далее следует объявление процедуры;
имя — имя процедуры, которое используется для вызова процедуры;
параметр K — формальный параметр, переменная, которая используется в инструкциях процедуры. Слово var перед именем параметра не является обязательным. Однако если оно стоит, то это означает, что в инструкции вызова процедуры фактическим параметром обязательно должна быть переменная.
Параметры процедуры используются для передачи данных в процедуру, а также для возврата данных из процедуры в вызвавшую ее программу.
В качестве примера в листинге 6.5 приведена процедура решения квадратного уравнения (которое в общем виде записывается так: ах2 + Ьх+ с = 0). У процедуры шесть параметров: первые три предназначены для передачи в процедуру исходных данных — коэффициентов уравнения; параметры xi и х2 используются для возврата результата — корней уравнения; параметр ok служит для передачи информации о том, что решение существует.
Листинг 6.5.
Процедура SgRoot
procedure SqRoot(a,b,c : real; var xl,x2 : real; var ok : boolean); { a,b,c — коэффициенты уравнения x1,x2 — корни уравнения ok = True — решение есть ok = False — решения нет } var
d : real; // дискриминант begin
d:= Sqr(b) - 4*a*c; if d < 0 then
ok := False // уравнение не имеет решения else
begin
ok := True;
x1 := (-b + Sqrt(d)) / (2*a) ; x2 := (b + Sqrt(d)) / (2*a); end; end;
Использование процедуры
Разработанную процедуру нужно поместить в раздел implementation, перед подпрограммой, которая использует эту процедуру.
Инструкция вызова процедуры в общем виде выглядит так:
Имя(СписокПараметров);
где:
П имя — имя вызываемой процедуры;
списокПараметров — разделенные запятыми фактические параметры.
Фактическим параметром, в зависимости от описания формального параметра в объявлении процедуры, может быть переменная, выражение или константа соответствующего типа.
Например, инструкция вызова приведенной выше процедуры решения квадратного уравнения может выглядеть следующим образом:
SqRoot(StrToFloat(Edit1.Text), StrToFloat(Edit2.Text), StrToFloat(Edit3.Text), k1,k2,rez);
Если в описании процедуры перед именем параметра стоит слово var, то при вызове процедуры на месте соответствующего параметра должна стоять переменная основной программы. Использование константы или выражения считается ошибкой, и компилятор в этом случае выведет сообщение: Types of actual and formal var parameters must be identical (ТИП фактического параметра должен соответствовать типу формального параметра).
В листинге 6.6 приведена программа решения квадратного уравнения, в которой используется процедура SqRoot. Окно программы представлено на рис. 6.2.
Рис. 6.2.
Окно программы Квадратное уравнение
Листинг 6.6.
Решение квадратного уравнения (использование процедуры)
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForml = class(TForm)
Editl: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Label1: TLabe1;
Label2: TLabe1;
Label3: TLabe1;
Label4: TLabe1;
Button1: TButton;
Label5: TLabel;
procedure ButtonlClick(Sender: TObject); private
{ Private declarations } public
{ Public declarations } end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// решает квадратное уравнение
procedure SqRoot(a,b,c : real; var xl, x2 : real; var ok : boolean); { a,b,c — коэффициенты уравнения x1,x2 — корни уравнения
ok = True — решение есть ok = False — решения нет } var
d : real; // дискриминант begin
d:= Sqr(b) - 4*a*c; if d < 0 then
ok := False // уравнение не имеет решения else
begin
ok := True;
xl := (-b + Sqrt(d)) / (2*a); x2 := (b + Sqrt(d)) / (2*a) ; end; end;
procedure TForml.ButtonlClick(Sender: TObject); var
k1,k2: real; // корни уравнения
rez: boolean; // True —решение есть, False —решения нет mes: string; // сообщение begin
SqRoot(StrToFloat(Editl.Text), StrToFloat(Edit2.Text) ,
StrToFloat(Edit3.Text) , k1,k2,rez); if rez then
mes := 'Корни уравнения' + #13 +
'x1='+FloatToStrF(kl,ffGeneral, 4,2)+#13+ 'x2='+FloatToStrF(k2,ffGeneral,4,2)+#13 else
mes := 'Уравнение не имеет решения'; labels.Caption := mes; end;
end.
Повторное использование функций и процедур
Разработав некоторую функцию, программист может использовать ее в другой программе, поместив текст этой функции в раздел implementation. Однако этот способ неудобен, т. к. приходится набирать текст функции заново или копировать его из текста другой программы.
Создание модуля
Delphi позволяет программисту поместить свои функции и процедуры в отдельный модуль, а затем использовать процедуры и функции модуля в своих программах, указав имя модуля в списке модулей, необходимых программе (инструкция uses).
Чтобы приступить к созданию модуля, нужно сначала закрыть окно формы и окно модуля формы (в ответ на вопрос о необходимости сохранения модуля следует выбрать No, т. е. модуль, соответствующий закрытой форме, сохранять не надо). Затем из меню File нужно выбрать команду New | Unit. В результате открывается окно редактора кода, в котором находится сформированный Delphi шаблон модуля. Его текст приведен в листинге 6.7.
Листинг 6.7.
Шаблон модуля
interface implementation end.
Начинается модуль заголовком — инструкцией unit, в которой указано имя модуля. Во время сохранения модуля это имя будет автоматически заменено на имя, указанное программистом.
Слово interface отмечает раздел интерфейса модуля. В этот раздел программист должен поместить объявления находящихся в модуле процедур и функций, которые могут быть вызваны из других модулей, использующих данный.
В раздел implementation (реализация) нужно поместить процедуры и функции, объявленные в разделе interface.
В качестве примера в листинге 6.8 приведен модуль программиста, который содержит рассмотренные ранее функции IsInt и isFioat.
Листинг 6.8.
Модуль программиста
interface // объявления процедур и функций,
// доступных программам,
// использующим этот модуль
function IsInt(ch : char) : Boolean; // функция Islnt проверяет, является ли символ // допустимым во время ввода целого числа
function IsFloat(ch : char; st: string) : Boolean;
// Функция IsFloat проверяет, является ли символ допустимым
// во время ввода дробного числа
// ch — очередной символ
// st — уже введенные символы
implementation // реализация
// проверяет, является ли символ допустимым // во время ввода целого числа function Islnt(ch : char) : Boolean; begin
if (ch >= '0') and (ch <= '9') // цифры
or (ch = #13) // клавиша <Enter>
or (ch = #8) // клавиша <Backspace>
then Islnt := True // символ допустим else Islnt := False; // недопустимый символ end;
// проверяет, является ли символ допустимым // во время ввода дробного числа
function IsFloat(ch : char; st: string) : Boolean; // ch — очередной символ // st — уже введенные символы begin
if (ch >= '0') and (ch <= '9') // цифры
or (ch = #13) // клавиша <Enter>
or (ch = #8) // клавиша <Backspace>
then
begin
IsFloat := True; // символ верный Exit; // выход из функции
end; case ch of
'-': if Length(st) = 0 then IsFloat := True; ',': if (Pos(',',st) = 0)
and (st[Length(st)] >= '0') and (st[Length(st)] <= '9')
then // разделитель можно ввести только после цифры // и если он еще не введен
IsFloat := True; else // остальные символы запрещены
IsFloat := False; end
// это раздел инициализации // он в данном случае не содержит инструкция end.
Сохраняется модуль обычным образом, т. е. выбором из меню File команды Save. Вместе с тем, для модулей повторно используемых процедур и функций лучше создать отдельную папку, назвав ее, например, Units.
Использование модуля
Для того чтобы в программе могли применяться функции и процедуры модуля, программист должен добавить этот модуль к проекту и указать имя модуля в списке используемых модулей (обычно имя модуля программиста помещают в конец сформированного Delphi списка используемых модулей).
В листинге 6.9 приведен вариант программы Поездка на дачу. Процедура обработки события onKeyPress в полях ввода исходных данных обращается к функции IsFloat, которая находится в модуле my_unit.pas, поэтому в списке используемых модулей указано имя модуля my_unit.
Листинг 6.9.
Использование функции из модуля программиста
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, my_unit; // модуль программиста
type
TForm1 = class(TForm)
Edit1: TEdit; // расстояние
Edit2: TEdit; // цена литра бензина
Edit3: TEdit; // потребление бензина на 100 км
CheckBoxl: TCheckBox; // True — поездка туда и обратно
Button1: TButton; // кнопка Вычислить
Label4: TLabel; // поле вывода результата расчета
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure EditlKeyPress(Sender: TObject; var Key: Char);
procedure Edit2KeyPress(Sender: TObject; var Key: Char);
procedure Edit3KeyPress(Sender: TObject; var Key: Char);
procedure Button1Click(Sender: TObject); private
{ Private declarations} public
{ Public declarations } end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// нажатие клавиши в поле Расстояние
procedure TForml.EditlKeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then Edit2.SetFocus // переместить курсор в поле Цена else If not IsFloat(Key,Edit2.Text) then Key := Chr(O);
end;
// нажатие клавиши в поле Цена
procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then Edit3.SetFocus // переместить курсор в поле Потребление . else If not IsFloat(Key,Edit2.Text) then Key := Chr(0); end;
// нажатие клавиши в поле Потребление
procedure TForm1.EditSKeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then Button1.SetFocus // // сделать активной кнопку Вычислить else If not IsFloat(Key,Edit2.Text) then Key := Chr(0);
end;
// щелчок на кнопке Вычислить
procedure TForml.ButtonlClick(Sender: TObject);
var
rast : real; // расстояние
cena : real; // цена
potr : real; // потребление на 100 км
summ : real; // сумма
mes: string; begin
rast := StrToFloat(Editl.Text) ;
cena := StrToFloat(Edit2.Text);
potr := StrToFloat(Edit3.Text);
summ := rast / 100 * potr * cena;
if CheckBoxl.Checked then summ := summ * 2;
mes := 'Поездка на дачу';
if CheckBox1.Checked then
mes : = mes + ' и обратно' ;
mes := mes + 'обойдется в ' + FloatToStrF(summ,ffGeneral, 4,2) + ' руб.';
Label4.Caption := mes; end;
end.
После добавления имени модуля в список модулей, используемых приложением, сам модуль нужно добавить в проект. Для этого из меню Project надо выбрать команду Add to Project и в открывшемся диалоговом окне — имя файла модуля. В результате добавления модуля к проекту в окне редактора появится вкладка с текстом добавленного к проекту модуля.
Увидеть структуру проекта можно в окне Project Manager, которое появляется в результате выбора соответствующей команды из меню View. В качестве примера на рис. 6.3 приведена структура проекта Поездка на дачу.
Рис. 6.3.
Структура проекта отражается в окне Project Manager