Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
osnovy_programmirovanija_v_srede_lazarus.pdf
Скачиваний:
243
Добавлен:
18.03.2015
Размер:
6.53 Mб
Скачать

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

____________________________________________________________________

нию кода. Гораздо разумнее и эффективней при вводе данных просто не давать пользователю совершить ошибку. Например, если пользователь должен вво-

дить только целые числа, проще контролировать введенные пользователем символы и, если будет попытка ввести недопустимый для целых чисел символ,

просто этот символ игнорировать.

Для этого удобнее использовать другую разновидность компонента TEdit

TMaskEdit из страницы Additional.

6.3.7.1. Компонент TMaskEdit

В этом компоненте имеется свойство EditMask, с помощью которого можно задать маску ввода. Маска это некий шаблон, задающий какие символы может вводить пользователь в окне ввода. Недопустимые символы игнориру-

ются. Маска состоит из трех частей, между которыми ставится точка с запятой

(;). В первой части маски – шаблоне записываются символы (табл. 6.2), кото-

рые указывают какие символы можно вводить в каждой позиции.

Таблица 6.2

Символ

Шаблон ввода

Означает, что в EditText недостающие символы предваряются

!пробелами. В случае отсутствия символа пробелы размещаются в конце.

0 Означает, что в данной позиции должна быть цифра.

9 Означает, что в данной позиции может быть цифра или ничего.

#Означает, что в данной позиции может быть цифра, знак « + », знак «-» или ничего.

Далее через точку с запятой (;) записывается 1 или 0 в зависимости от того,

надо или нет, чтобы символы, добавляемые маской, включались в свойство

Text компонента. В третьей части маски указывается символ-заполнитель, ис-

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

тановить нужную маску можно прямо в свойстве EditMask, введя необходи-

мые символы маски или в редакторе масок, открыть который можно нажав

529

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

____________________________________________________________________

кнопку с троеточием, рис. 6.33.

Рис. 6.33. Окно редактора масок

Прочитать результат ввода можно или в свойстве Text, которое, в зависи-

мости от вида второй части маски, включает или не включает в себя символы маски, или в свойстве EditText, содержащем введенный текст вместе с сим-

волами маски.

Итак, давайте применим для нашего примера компонент TMaskEdit.

Удалите из формы LabeledEdit1 и LabeledEdit2. Перенесите на их ме-

сто два компонента TMaskEdit. Также вставьте в форму два компонента

TLabel. В общем, восстановите внешний вид формы как на рисунке 6.30.

Установите следующие свойства MaskEdit1:

AutoSelect = true

EditMask = #9999;0;

TabOrder = 0

свойство Text оставьте пустым.

В качестве символа заполнителя в окошке "Символы для пробелов" в ре-

дакторе масок введите пробел вместо знака подчеркивания.

Установите свойства MaskEdit2:

530

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

____________________________________________________________________

AutoSelect = true

EditMask = #9999;0;

TabOrder = 1

свойство Text оставьте пустым.

Установите символ заполнитель такой же, что и для MaskEdit1.

В LabeledEdit3 и BitBtn1 свойству TabStop присвойте значение

false.

Обработчики событий запишите в виде:

procedure TForm1.FormShow(Sender: TObject); begin

MaskEdit1.SetFocus;

end;

procedure TForm1.SpeedButton1Click(Sender: TObject); begin

LabeledEdit3.Text:= IntToStr(StrToInt(MaskEdit1.Text)

+ StrToInt(MaskEdit2.Text));

StatusBar1.SimpleText:= 'Сложение';

MaskEdit1.SetFocus;

MaskEdit1.SelectAll;

end;

procedure TForm1.SpeedButton2Click(Sender: TObject); begin

LabeledEdit3.Text:= IntToStr(StrToInt(MaskEdit1.Text)

- StrToInt(MaskEdit2.Text));

StatusBar1.SimpleText:= 'Вычитание';

MaskEdit1.SetFocus;

MaskEdit1.SelectAll;

end;

531

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

____________________________________________________________________

procedure TForm1.SpeedButton3Click(Sender: TObject); begin

LabeledEdit3.Text:= IntToStr(StrToInt(MaskEdit1.Text)

* StrToInt(MaskEdit2.Text));

StatusBar1.SimpleText:= 'Умножение';

MaskEdit1.SetFocus;

MaskEdit1.SelectAll;

end;

procedure TForm1.SpeedButton4Click(Sender: TObject); begin

try

LabeledEdit3.Text:= IntToStr(StrToInt(MaskEdit1.Text)

div StrToInt(MaskEdit2.Text));

except

on EDivByZero do

ShowMessage('Ошибка! Произошло деление на ноль.' + ' Вероятно Вы ошиблись при вводе второго числа');

end;

StatusBar1.SimpleText:= 'Деление нацело';

MaskEdit1.SetFocus;

MaskEdit1.SelectAll;

end;

Как видите, обработку исключений на возможные ошибки преобразования типов мы убрали, поскольку MaskEdit не позволит пользователю ввести не-

допустимые символы. Но в обработчике операции деления исключение, возни-

кающее при попытке деления на ноль мы, естественно, оставили.

Переход от MaskEdit1 к MaskEdit2 и обратно осуществляйте кла-

вишей Tab. Впрочем, можете добавить обработчик OnKeyPress для MaskE-

532

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

____________________________________________________________________

dit1:

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

begin

if Key = #13 then begin

MaskEdit2.SetFocus; SpeedButton1.Down:= false; SpeedButton2.Down:= false; SpeedButton3.Down:= false; SpeedButton4.Down:= false; exit;

end;

end;

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

нента TLabeledEdit. Реализуем полный контроль ввода целых чисел с уче-

том знака. Для этого создадим простое приложение. Поместите на форму два компонента TLabeledEdit и одну кнопку TButton, рис. 6.34.

Рис. 6.34. Форма приложения

Установите свойство TabOrder=0 и TabStop=true

для

533

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

____________________________________________________________________

LabeledEdit1, и TabOrder=1, TabStop=true для TButton1, а для

LabeledEdit2 свойство TabStop=false. Это для того, чтобы при нажатии клавиши Tab фокус автоматически перемещался с LabeledEdit1 на кнопку

иобратно. Кроме того, установите свойство AutoSelect для

LabeledEdit1 равным true.

Будем вводить числа в окне LabeledEdit1, затем введенное число про-

сто выведем в LabeledEdit2, но не "сразу"! Сначала преобразуем его во внутреннее представление целого числа для того, чтобы "выловить" ошибки.

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

EConvertError в список игнора через меню

Окружение->Параметры>Отладчик->Исключения языка, чтобы удоб-

нее было запускать наше приложение из среды Lazarus.

Итак, с чего начнем? Задача вполне ясная. Необходимо обеспечить ввод пользователем только цифр от 0 до 9 и знака минус (-) (знак плюс (+) перед числом обычно не ставится). Для этого проще всего воспользоваться опреде-

ленным в Паскаль типом – множество и оператором in для определения при-

надлежности символа к допустимым.

В LabeledEdit1 для события OnKeyPress напишите следующий об-

работчик:

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

begin

{разрешаем только цифры, знак минус и кл. BackSpace } if not (Key in ['0' .. '9', '-' , #8])

534

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

____________________________________________________________________

then Key:= #0;

end;

В операторе if если пользователь нажимает на клавиши отличные от цифр, клавиши BackSpace и знака (-) параметру Key присваивается нулевой символ.

Для события OnClick кнопки напишите следующий обработчик:

procedure TForm1.Button1Click(Sender: TObject);

begin

LabeledEdit1.SetFocus;

n:= StrToInt(LabeledEdit1.Text);

LabeledEdit2.Text:= IntToStr(n);

end;

Не забудьте объявить переменную n целого типа:

var

Form1: TForm1;

n: integer;

Запустите приложение. Попробуйте ввести символы, отличные от цифр и знака минус. Вы видите, что недопустимые символы просто не появляются в окне ввода. И что? Задача решена? К сожалению, нет!

Введите несколько цифр, а затем знак минус. Например, "2010-". Если нажать на кнопку, получите сообщение об ошибке. Потому что знак числа ста-

вится перед первой значащей цифрой. Или введите сначала два или более знака

(-), затем цифры, например, "--2010". Опять получите ошибку.

Вы скажете, ну не может быть, чтобы пользователь допускал такие ошиб-

ки! Не настолько же пользователь глуп и туп! И вы правы! Речь может идти о случайных ошибках. Мы на протяжении этой книги не раз говорили об этом.

Программа должна быть защищена от любых случайных и непреднамеренных

535

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

____________________________________________________________________

ошибок пользователя!

Значит после ввода цифр, знак (-) тоже должен быть запрещен. Кроме того,

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

ла! Для этого введем логическую переменную, назовем ее sign. Первоначаль-

но ее значение будет равно false. Как только пользователь нажал на хотя бы один допустимый символ, включая знак числа, переменной sign присваиваем значение true.

Обработчик для LabeledEdit1 переписываем в следующем виде, заод-

но разрешим пользователю заканчивать ввод нажатием клавиши Enter:

procedure TForm1.LabeledEdit1KeyPress(Sender: TObject;

var Key: char);

begin

if Key = #13 then

begin

sign:= false;

n:= StrToInt(LabeledEdit1.Text);

LabeledEdit2.Text:= IntToStr(n);

end;

{разрешаем только цифры, знак минус и кл. BackSpace } if not (Key in ['0' .. '9', '-' , #8]) then

begin Key:= #0; exit;

end;

if (Key = '-') and (sign) then Key:= #0;

sign:= true;

536

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

____________________________________________________________________

end;

Оператор

if (Key = '-') and (sign)

then Key:= #0;

не позволит пользователю ввести знак числа после значащих цифр и, кроме то-

го, дважды ввести знак (-).

Теперь, кажется все. Но нет, еще не все! Представьте ситуацию – пользо-

ватель хотел ввести отрицательное число, но забыл ввести знак минус, а цифры уже ввел. Попробуйте ввести несколько цифр, затем вернуть курсор на начало строки и попытайтесь ввести (-). У вас не получится! Даже если вы удалите введенные цифры клавишей Delete или BackSpace. Потому что sign имеет значение true. Ситуация не столь проста, как кажется. Чтобы ввести отрица-

тельное число нужно сначала нажать на кнопку "Ввод" или на клавишу Enter,

т.е. пользователь будет вынужден ввести число, которое не хотел вводить!

Придется контролировать положение курсора. У компонента есть свойство

SelStart, которое указывает на текущее положение курсора. Используя это свойство и функцию Pos, перепишем обработчик следующим образом:

procedure TForm1.LabeledEdit1KeyPress(Sender: TObject;

var Key: char);

begin

if Key = #13 then

begin

sign:= false;

n:= StrToInt(LabeledEdit1.Text);

LabeledEdit2.Text:= IntToStr(n);

exit;

537

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

____________________________________________________________________

end;

{разрешаем только цифры, знак минус и кл. BackSpace } if not (Key in ['0' .. '9', '-' , #8]) then

begin Key:= #0; exit;

end;

if (Key = '-') and (sign) then

begin

if (LabeledEdit1.SelStart <> 0) then

begin Key:= #0; exit;

end else

if (Pos('-', LabeledEdit1.Text) <> 0) then Key:= #0;

end;

sign:= true; end;

Обработчик работает следующим образом – если текущий символ знак (-)

и цифры введены, то проверяем позицию курсора. Если курсор установлен на начало и минуса нет, то разрешаем ввод знака.

Уф! Наконец-то должно все заработать как надо. Но есть нюанс!

Попробуйте ввести только один знак (-) и больше ничего. Опять получите

538

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

____________________________________________________________________

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

Enter? И еще. А что если, пользователь ничего не введя, опять же случайно,

нажмет кнопку или Enter, т.е. будет введена пустая строка?

У вас не возникает ощущения, что мы пишем программу для американцев? (Как говорил М. Задорнов – "Ну, тупые…!).

Сделаем так, если длина строки равна единице и это знак (-), то запрещаем ввод.

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

begin

if Key = #13 then begin

sign:= false;

if Length(LabeledEdit1.Text) = 0 // если пустая строка then exit;

if (Length(LabeledEdit1.Text) = 1) and (LabeledEdit1.Text = '-')

then exit;

n:= StrToInt(LabeledEdit1.Text); LabeledEdit2.Text:= IntToStr(n); exit;

end;

{разрешаем только цифры, знак минус и кл. BackSpace } if not (Key in ['0' .. '9', '-' , #8]) then

begin Key:= #0;

539

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

____________________________________________________________________

exit;

end;

if (Key = '-') and (sign) then

begin

if (LabeledEdit1.SelStart <> 0) then

begin Key:= #0; exit;

end else

if (Pos('-', LabeledEdit1.Text) <> 0) then Key:= #0;

end;

sign:= true; end;

procedure TForm1.Button1Click(Sender: TObject); begin

LabeledEdit1.SetFocus; sign:= false;

if Length(LabeledEdit1.Text) = 0 // если пустая строка then exit;

if (Length(LabeledEdit1.Text) = 1)and (LabeledEdit1.Text = '-')

then exit else

n:= StrToInt(LabeledEdit1.Text);

540

Глава 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;

545

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

____________________________________________________________________

var Key: char);

private

{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);

546

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]