Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Мансуров. Основы программирования в среде Lazarus. 2010

.pdf
Скачиваний:
45
Добавлен:
27.04.2021
Размер:
6.3 Mб
Скачать

Глава 6 Программирование приложений с графическим интерфейсом

____________________________________________________________________

LabeledEdit2.Text:= IntToStr(n);

end;

Между прочим, компонент TMaskEdit при установленной маске на ввод только чисел тоже не "ловит" одиночный минус и "молча, проглатывает" пус-

тую строку!

Почему такие ситуации надо контролировать? Представьте себе, что поль-

зователь должен вводить большое количество числовых данных. Спустя неко-

торое время после начала ввода пользователь начинает уставать и, чисто маши-

нально, вводит пустую строку или одиночный минус. Ваша программа аварий-

но завершается из-за ошибки преобразования (EConvertError)! Вся проде-

ланная пользователем работа пошла "коту под хвост". Как же он будет вас про-

клинать! Именно вас – разработчика программы!

Этот пример еще раз демонстрирует, как надо последовательно улучшать и

"доводить" алгоритм и программу до достижения требуемой функционально-

сти. Пусть сам алгоритм, быть может, не является оптимальным. Не в этом суть! Это конкретный (хотя и простой) пример того, как надо разрабатывать ре-

альные программы. Уже неоднократно отмечал, что с первого раза невозможно написать полностью правильно работающую программу. Если можно так выра-

зиться, этот пример показывает метод "последовательных приближений" разра-

ботки программ.

А теперь попробуем реализовать контроль ввода вещественных чисел. Яс-

но, что надо добавить проверку на символы точки (.) и запятой (,). Использова-

ние точки или запятой для отделения целой части числа от дробной зависит от настроек операционной системы Windows. Хотя Lazarus спокойно преобра-

зует строку в число и с точкой, и с запятой. А вот Delphi "ругается", если раз-

делитель не совпадает с настройками Windows. Так что будем учитывать оба разделителя. Для определения какой разделитель используется системой, слу-

жит глобальная переменная DecimalSeparator, значением которой и явля-

541

6.3 Визуальное программирование в среде Lazarus

____________________________________________________________________

ется символ разделителя. При этом поступим следующим образом, если поль-

зователь ввел "не тот" разделитель, то просто заменим его на нужный. Так что,

наша программа будет "обладать" уже кое-каким интеллектом! При реализации применим, для разнообразия, несколько другой способ, нежели в предыдущей программе. Будем использовать оператор выбора сase .. of. Основываясь на опыте разработки предыдущей программы, будем учитывать не только оди-

ночный минус, но и одиночный разделитель, и комбинацию "-" и разделитель.

Опять же для разнообразия используем компонент TEdit. Код программы:

unit Unit1;

{$mode objfpc}{$H+}

interface uses

Classes, SysUtils, FileUtil, LResources, Forms,

Controls, Graphics, Dialogs, StdCtrls;

type

{ TForm1 }

TForm1 = class(TForm)

Button1: TButton;

Edit1: TEdit;

Edit2: TEdit;

Label1: TLabel;

Label2: TLabel;

procedure Button1Click(Sender: TObject); procedure Edit1KeyPress(Sender: TObject; var Key: char);

private

{ private declarations }

542

Глава 6 Программирование приложений с графическим интерфейсом

____________________________________________________________________

public

{ public declarations } end;

var

Form1: TForm1;

implementation { TForm1 }

procedure TForm1.Button1Click(Sender: TObject); begin

Edit1.SetFocus;

if (Edit1.Text

<> '') and // если пустая строка

(Edit1.Text

<> '-') and // если одиночный минус

(Edit1.Text

<> DecimalSeparator) and {если одиночный

разделитель}

(Edit1.Text <> '-' + DecimalSeparator) {если "-" и разде-

литель}

then Edit2.Text:= FloatToStr(StrToFloat(Edit1.Text)); Edit1.Clear;

end;

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: char);

begin

case Key of

'0'..'9', #8:; // если цифры и кл. BackSpace, ввод разрешен

#13: // если нажата клавиша <Enter> begin

if (Edit1.Text <> '') and

543

6.3 Визуальное программирование в среде Lazarus

____________________________________________________________________

(Edit1.Text <> '-') and

(Edit1.Text <> DecimalSeparator) and (Edit1.Text <> '-' + DecimalSeparator)

then Edit2.Text:=FloatToStr(StrToFloat(Edit1.Text));

Edit1.SetFocus;

Edit1.Clear;

end;

'.',',': // если разделители begin

if Key <> DecimalSeparator then

Key := DecimalSeparator; // замена разделителя if Pos(DecimalSeparator, Edit1.Text) <> 0 then Key:= #0;

end;

'-' : // если знак минус begin

if (Edit1.SelStart <> 0) // если одиночный минус then

begin Key:= #0; exit;

end else

if (Pos('-', Edit1.Text) <> 0) // два минуса then Key:= #0;

end;

544

Глава 6 Программирование приложений с графическим интерфейсом

____________________________________________________________________

else

Key := #0;

end;

end;

initialization

{$I unit1.lrs}

end.

И, наконец, самый простой способ контроля ввода числовых данных это

использование функции val(). Функция была рассмотрена нами в 3.3.1.4.

unit Unit1;

{$mode objfpc}{$H+} interface

uses

Classes, SysUtils, FileUtil, LResources, Forms,

Controls, Graphics, Dialogs, StdCtrls;

type

{ TForm1 }

TForm1 = class(TForm)

Button1: TButton;

Edit1: TEdit;

Edit2: TEdit;

Label1: TLabel;

Label2: TLabel;

procedure Button1Click(Sender: TObject); procedure Edit1KeyPress(Sender: TObject; var Key: char);

private

545

6.3 Визуальное программирование в среде Lazarus

____________________________________________________________________

{private declarations } public

{public declarations } end;

var

Form1: TForm1; code: integer; value: real;

implementation { TForm1 }

procedure TForm1.Button1Click(Sender: TObject); begin

Edit1.SetFocus; val(Edit1.Text, value, code); if code <> 0 then exit; Edit2.Text:= FloatToStr(value);

end;

procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: char);

begin

if Key = #13 then begin

Edit1.SetFocus; val(Edit1.Text, value, code); if code <> 0 then exit; Edit2.Text:= FloatToStr(value);

end;

end;

546

Глава 6 Программирование приложений с графическим интерфейсом

____________________________________________________________________

initialization

{$I unit1.lrs}

end.

6.3.8 Специальные компоненты для ввода чисел

Если необходимо вводить последовательность чисел с заранее определен-

ным шагом изменения значений, то бывает удобнее использовать специальные компоненты TSpinEdit и TFloatSpinEdit, расположенные на вкладке

Misc. Основные свойства этих компонентов:

Increment – шаг приращения числа. Разумеется, для TSpinEdit шаг мо-

жет быть только целым, а для TFloatSpinEdit может быть и дробным.

MaxValue – максимально возможное значение числа.

MinValue – минимально возможное значение числа.

ReadOnly – изменить значение пользователь не может, правда программно изменить значение можно.

Value – указывает текущее значение. Во время проектирования можно за-

дать начальное значение числа, с которого будет начинаться ввод.

DecimalPlaces – только для TFloatSpinEdit, указывает количество разрядов после запятой.

Вводить числа можно не только с помощью кнопок прокрутки, но и с кла-

виатуры. При этом обеспечивается контроль на ввод недопустимых символов.

В компоненте TSpinEdit нельзя ввести число вне установленного диапа-

зона как с помощью кнопок прокрутки, так и с клавиатуры. В компоненте

TFloatSpinEdit если ввод производится с помощью кнопок, то переход за пределы указанного при проектировании диапазона блокируется, т.е. например,

нажимая на кнопку увеличения нельзя ввести число больше MaxValue или нажимая на кнопку уменьшения, нельзя ввести число меньше MinValue. Но

547

6.3 Визуальное программирование в среде Lazarus

____________________________________________________________________

можно ввести числа вне этого диапазона с клавиатуры. Однако если после этого нажать на любую из кнопок прокрутки, то в окне ввода появится число, первое из возможных в установленном диапазоне! Например, вы установили MaxValue = 10.0, с клавиатуры ввели число 24.5. После этого нажали кнопку увели-

чения, в окне компонента появится число 10.0. Если нажать на кнопку умень-

шения, то появится число 9.5.

Упомяну еще об одном компоненте TUpDown из вкладки Common Controls, который позволяет вводить целые числа. Основные свойства у него практически такие же, как и у TSpinEdit, только по-другому названные. На-

пример, свойство MaxValue в TUpDown называется Max, MinValue в TUpDown называется Min, свойство Value называется Position. Если его ис-

пользовать "в одиночку", то текущее значение (Position) будет не видно пользователю. Поэтому его чаще всего используют совместно с TEdit. Для этого имеется свойство Associate. Используя раскрывающийся список, мож-

но указать нужный компонент. В этом случае TUpDown "прижимается" к вы-

бранному компоненту и оба компонента превращаются в один, но только визу-

ально! В программе обращаться к ним надо отдельно по своим именам. Свой-

ством AlignButton можно управлять расположением TUpDown вокруг ком-

понента (слева, справа, сверху, снизу). Также имеется свойство Orientation,

позволяющее управлять положением кнопок TUpDown (вертикально или гори-

зонтально). И, наконец, свойство Wrap определяет, что будет происходить, ес-

ли пользователь попытается ввести значение больше максимального или мень-

ше минимального. При Wrap=false ввод числа с помощью кнопок вне ука-

занного диапазона (Min..Max) блокируется, а при Wrap=true происходит автоматический переход с Min на Max при нажатии кнопки на уменьшение и с Max на Min при нажатии кнопки на увеличение. При вводе с клавиатуры сле-

дует помнить, что этот компонент абсолютно не защищен от ввода недопусти-

мых символов.

548

Глава 6 Программирование приложений с графическим интерфейсом

____________________________________________________________________

В целом можно сказать, что рассмотренные компоненты удобны лишь в случае, если вводимые числа имеют постоянный шаг приращения и известен диапазон допустимых значений. При вводе случайных чисел, особенно, если они достаточно далеко "отстоят" друг от друга по значению, их применение может причинить пользователю лишь неудобства.

Итак, мы с вами рассмотрели способы организации ввода и контроля чи-

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

6.3.9 Тестирование и отладка программы

Какие бывают виды ошибок?

Ошибки можно разделить на три группы. К первой относятся так называе-

мые синтаксические ошибки. Это ошибки, допущенные непосредственно в мо-

мент кодирования, т.е. записи (набора в редакторе исходного кода) текста про-

граммы. Такие ошибки легче всего находить и исправлять, так как компилятор сам укажет на такие ошибки.

Ко второй группе ошибок относятся так называемые логические ошибки или их еще называют ошибками времени исполнения. Иностранные програм-

мисты их называют bugs – жучки. Логические ошибки проявляются во время запуска приложения. В большинстве случаев, логические ошибки приводят к получению неверных результатов. Очень часто приложение завершается ава-

рийно. Программист получает только сообщение об ошибке. Если логическая ошибка тривиальная, то уже по сообщению можно определить, где именно кро-

ется ошибка. Однако бывают ошибки, которые находятся с большим трудом.

Третья группа ошибок – это алгоритмические ошибки. Это такие ошибки,

при которых внешне правильно и без ошибок работающая программа выдает в

549

6.3 Визуальное программирование в среде Lazarus

____________________________________________________________________

корне неверные результаты или решает совсем не ту задачу.

На практике довольно трудно сразу определить, к какой группе относится та или иная ошибка – к логической или алгоритмической. Если программа вы-

дает неправильные результаты (но работает!), то следует, прежде всего, прове-

рить сам алгоритм решения задачи. И если обнаруживается ошибка в алгорит-

ме, то эта ошибка алгоритмическая. Если же алгоритм правильный, то ошибку следует признать логической.

Процесс обнаружения алгоритмических ошибок называется тестировани-

ем. При тестировании задается некоторый ряд входных данных, называемых модельными данными, для которых заранее известен результат (вспомните за-

дачу вычисления значений синуса, разд. 2.1.26) или для которых можно "вруч-

ную" вычислить требуемый результат. Например, если это программа начисле-

ния заработной платы, то очень часто, на этапе внедрения, расчет заработной платы производится параллельно с помощью программы и бухгалтерии. Или,

если программа сортирует какие-то данные, можно просто посмотреть на полу-

ченные результаты и определить, правильно программа работает или нет.

Процесс поиска, обнаружения и исправления логических ошибок называ-

ется отладкой. В основном процесс отладки сводится к определению в коде программы того места, где "сидит" ошибка (жучок!). Для отладки программы в

Lazarus имеются несколько полезных инструментов.

Точки останова (Breakpoints). Выполнение программы приостанавливает-

ся по достижению некоторого места (строки кода). Точку останова задает сам программист. Для этого надо в редакторе исходного кода просто щелкнуть мышью по полю, где показаны номера строк кода напротив нужной строки.

Точка останова будет выделена красным цветом и помечена галочкой, рис. 6.35.

При запуске программы отладчик выполнит все операторы до точки останова и остановит выполнение программы. Далее вы можете продолжить выполнение программы пошагово.

Пошаговое выполнение с входом. При нажатии клавиши F7 будут выпол-

550