Как осуществляется вывод в окно сообщения Delphi? Окно сообщений применяется для того, чтобы привлечь внимание пользователей. Используя окно сообщений, программа может оповестить программиста об ошибке первичных данных или сделать запрос о подтверждении выполнения некоторой необратимой операции (удалить файл, очистить содержимое и др.).
В Delphi для вывода на экран окна сообщения зарезервирована процедура ShowMessage (либо выполняющая те же операции функция MessageDlg Delphi). Остановимся подробнее на них.
Процедура ShowMessage Delphi:
Применение процедуры ShowMessage позволяет вывести на экран окно с необходимым текстом и кнопкой подтверждения OK. Процедура ShowMessage Delphi организована следующим образом:
откуда Сообщение представляет собой текст, впоследствии выведенный в диалоговом окне.
Пример 1. Представим иллюстрацию окна сообщения, которое получено вследствие выполнения следующей инструкции:
Заметка. Заголовок окна сообщения, которое выводится при помощи процедуры ShowMessage, содержит название приложения, задающееся на специальной вкладке Application в окне Project Options. В случае, когда названия приложения не указано, заголовок будет включать в себя имя исполняемого файла.
Функция MessageDlg Delphi:
При помощи более универсальной процедуры MessageDlg возможно размещение в окне сообщения одного из стандартных значков, например, «Внимание», а также возможно задание количества и типа командных кнопок и обозначить, какую именно кнопку щелкнул программист. На рисунке ниже представлена иллюстрация окна, выведенного вследствие выполнения следующей инструкции:
В качестве значения функции MessageDlg выступает число, проверка значения которого может показать, какая командная кнопка завершила диалог. Общий вид обращения к данной функции представлен ниже:
откуда:
- Сообщение представляет собой некоторый текст;
- Тип определяет тип сообщения, которое включает в себя информационное, предупреждающее или сообщение о критической ошибке. Определенному типу ставится в соответствие некоторый значок. Именованная константа задает тип сообщения (табл. ниже).
- Кнопки выступают в качестве списка кнопок, которые отображаются в окне сообщения. В состав данного списка входят именованные константы, разделенные запятыми (табл. ниже), при этом весь список заключен в квадратных скобках. К примеру, для появления в окне сообщения кнопок OK и Cancel необходимо представить список Кнопки как [mbOk,mbCansel]. Помимо указанных в таблиц выше констант возможно применение и таких констант, как mbAbortRetryIgnore, а также mbYesNoCansel и др. Как правило, данные константы чаще используются в комбинациях командных кнопок диалоговых окон.
- КонтекстСправки означает параметр, обозначающий раздел справочной системы, который впоследствии выведется на экран при нажатии пользователем на клавишу F1. В случае отсутствия справочной системы, параметр КонтекстСправки должен быть приравнен нулю.
Значение функции MessageDlg определяет, на какую из командных кнопок щелкнул пользователь при работе с программой (табл. ниже).
Похожие записи:
- Ввод из файла Delphi
- Ошибки открытия файлов Delphi
- Операция присваивания Delphi
- Цикл for Delphi
- Типы данных Delphi
Окна
диалогов 5
Процедура
ShowMessage
Модуль
Dialogs
procedure
ShowMessage(const Msg: string);
Отображает
окно сообщения с кнопкой OK.
Вызов
ShowMessage отображает простое
окно сообщения с кнопкой OK.
Текст сообщения задается параметром
Msg. Заголовок окна
совпадает с именем выполняемого файла
приложения.
При
необходимости анализировать ответ
пользователя на сообщение пользуйтесь
функцией Delphi MessageDlg.
Примеры:
1.)
ShowMessage(‘Работа приложения
успешно завершена.’);
2. ) В
приведенном ниже примере предполагается,
что целые переменные N1 и
N2 содержат соответствующие
числа, которые переводятся в строки
функцией IntToStr. Сообщение,
приведенное в этом примере проще
реализовать процедурой ShowMessageFmt.
ShowMessage(‘Задано
‘ + IntToStr(N1) + ‘ параметров из ‘
+
IntToStr(N2));
ShowMessageFmt
процедура
Модуль
Dialogs
procedure
ShowMessageFmt(const Msg: string; Params: array of const);
Отображает
окно форматированного сообщения с
кнопкой OK.
Вызов
ShowMessageFmt отображает окно
сообщения с кнопкой OK.
Параметр Msg задает
строку описания формата, а параметр
Params задает массив
параметров, форматируемых строкой Msg.
Заголовок окна совпадает с именем
выполняемого файла приложения.
Пример
ShowMessageFmt(‘Задано
%d параметров из %d
‘, [N1, N2]);
Функция
TApplication.MessageBox
function
MessageBox(Text, Caption: PChar; Flags: Longint): Integer;
Функция
MessageBox является методом переменной
Application типа TApplication, доступной в любом
проекте Delphi. Это метод является наиболее
удачным способом отображения диалоговых
окон. Он отображает диалоговое окно с
заданными кнопками, сообщением и
заголовком и позволяет проанализировать
ответ пользователя. Во многих отношениях
это окно подобно окнам, создаваемым
функциями MessageDlg и CreateMessageDialog. Но имеются
и существенные отличия, связанные с
возможностью русификации окна. Заголовок
окна может быть написан по-русски, что
отличает эту функцию от функции MessageDlg
(впрочем, в окне, созданном CreateMessageDialog,
это тоже можно сделать). Другим приятным
отличием являются русские надписи на
кнопках (в русифицированных версиях
Windows).
Функция
MessageBox инкапсулирует функцию MessageBox API
Windows.
Параметр
Text представляет собой текст сообщения,
которое может превышать 255 символов.
Для длинных сообщений осуществляется
автоматический перенос текста. Параметр
Caption представляет собой текст
заголовка окна. Он тоже может превышать
255 символов, но не переносится. Так что
длинный заголовок приводит к появлению
длинного и не очень красивого диалогового
окна.
Параметр
Flags представляет собой множество
флагов, определяющих вид и поведение
диалогового окна. Этот параметр может
комбинироваться операцией сложения по
одному флагу из следующих групп.
Флаги
кнопок, отображаемых в диалоговом окне.
Флаг Значение
(в скобках даны надписи в русифицированных
версиях Windows)
MB_ABORTRETRYIGNORE Кнопки
Abort (Стоп), Retry (Повтор) и Ignore (Пропустить).
MB_OK Кнопка
OK. Этот флаг принят по умолчанию.
MB_OKCANCEL Кнопки
OK и Cancel (Отмена).
MB_RETRYCANCEL Кнопки
Retry (Повтор) и Cancel (Отмена).
MB_YESNO Кнопки
Yes (Да) и No (Нет).
MB_YESNOCANCEL Кнопки
Yes (Да), No (Нет) и Cancel (Отмена).
Флаги
пиктограмм в диалоговом окне
MB_ICONEXCLAMATION,
MB_ICONWARNING Восклицательный знак
(замечание, предупреждение).
MB_ICONINFORMATION,
MB_ICONASTERISK Буква i в круге (подтверждение).
MB_ICONQUESTION Знак
вопроса (ожидание ответа).
MB_ICONSTOP,
MB_ICONERROR, MB_ICONHAND Знак креста на красном
круге
(запрет, ошибка).
Флаги,
указывающие кнопку по умолчанию (которая
в первый момент находится в фокусе)
MB_DEFBUTTON1 Первая
кнопка. Это принято по умолчанию.
MB_DEFBUTTON2 Вторая
кнопка.
MB_DEFBUTTON3 Третья
кнопка.
MB_DEFBUTTON4 Четвертая
кнопка.
Флаги
модальности
MB_APPLMODAL Пользователь
должен ответить на запрос, прежде чем
сможет продолжить работу с приложением.
Но он может перейти в окна другого
приложения. Он может также работать со
всплывающими окнами данного приложения.
Этот флаг принят по умолчанию.
MB_SYSTEMMODAL То же самое, что MB_APPLMODAL, но окно
диалога отображается в стиле WS_EX_TOPMOST,
то есть всегда остается поверх других
окон, даже если пользователь перешел к
другим приложениям. Используется для
предупреждения о серьезных ошибках,
требующих немедленного вмешательства.
Некоторые
дополнительные флаги (могут задаваться
оба флага)
Флаг Пояснение
MB_HELP Добавляет
в окно кнопку Help (Справка), щелчок на
которой или нажатие клавиши F1 генерирует
событие Help.
MB_TOPMOST Помещает
окно всегда сверху (в стиле WS_EX_TOPMOST).
Возможны
еще некоторые флаги, определяющие
характер поведения окна при работе в
сети нескольких пользователей, позволяющие
отображать тексты справа налево (для
восточных языков) и т.п.
Функция
возвращает нуль, если не хватает памяти
для создания диалогового окна. Если же
функция выполнена успешно, то возвращаемая
величина свидетельствует о следующем:
Значение Численное
значение Пояснение
IDABORT 3 Выбрана
кнопка Abort (Стоп).
IDCANCEL 2 Выбрана
кнопка Cancel (Отмена) или нажата клавиша
Esc.
IDIGNORE 5 Выбрана
кнопка Ignore (Пропустить).
IDNO 7 Выбрана
кнопка No (Нет).
IDOK 1 Выбрана
кнопка OK.
IDRETRY 4 Выбрана
кнопка Retry (Повтор).
IDYES 6 Выбрана
кнопка Yes (Да).
Ниже
приведен текст, предусматривающий
проверку правильности ввода данных
перед пересылкой записи в базу данных.
if
(проверка введенных данных)
then
begin
if
(Application.MessageBox(
‘Хотите занести текущую запись в базу
данных?’,
‘Подтвердите занесение в базу данных’,
MB_YESNOCANCEL + MB_ICONQUESTION) <> IDYES)
then begin
DataSet.Cancel;
Abort;
end
end
else begin
Application.MessageBox(‘Ошибочные данные’,’Ошибка’,
MB_ICONSTOP);
Abort;
end;
MessageDlg
– функция
Модуль Dialogs
function
MessageDlg(const Msg: string; AType: TMsgDlgType;
AButtons: TMsgDlgButtons;
HelpCtx: Longint):
Word;
Отображает
диалоговое окно сообщений в центре
экрана.
Вызов
MessageDlg отображает диалоговое окно и
ожидает ответа пользователя. Сообщение
в окне задается параметром функции Msg.
Вид
отображаемого окна задается параметром
AType. Возможные значения этого
параметра:
Значение Описание
mtWarning Окно
замечаний, содержащее желтый восклицательный
знак.
mtError Окно
ошибок, содержащее красный стоп-сигнал.
mtInformation Информационное
окно, содержащее голубой символ «i».
mtConfirmation Окно
подтверждения, содержащее зеленый
вопросительный знак.
mtCustom Заказное
окно без рисунка. Заголовок соответствует
имени выполняемого файла приложения.
Параметр
AButtons определяет, какие кнопки будут
присутствовать в окне. Тип TMsgDlgBtns
параметра AButtons является множеством,
которое включает различные кнопки.
Возможные значения видов кнопок:
Значение Описание
mbYes Кнопка
с надписью ‘Yes’
mbNo Кнопка
с надписью ‘No’
mbOK Кнопка
с надписью ‘OK’
mbCancel Кнопка
с надписью ‘Cancel’
mbHelp Кнопка
с надписью ‘Help’
mbAbort Кнопка
с надписью ‘Abort’
mbRetry Кнопка
с надписью ‘Retry’
mbIgnore Кнопка
с надписью ‘Ignore’
mbAll Кнопка
с надписью ‘All’
Список
необходимых кнопок заключается в
квадратные скобки [ ], поскольку параметр
AButtons является множеством. Если внутри
скобок список отсутствует, в окне не
будет ни одной кнопки и пользователю
придется закрывать окно системными
кнопками Windows.
Кроме
множества значений, соответствующих
отдельным кнопкам, в Delphi определены три
константы, соответствующие часто
используемым сочетаниям кнопок:
Значение Описание
mbYesNoCancel
Включает в окно кнопки Yes, No и Cancel
mbOkCancel Включает
в окно кнопки OK и Cancel
mbAbortRetryIgnore Включает
в окно кнопки Abort, Retry и Ignore
Эти
константы являются предопределенными
множествами. Поэтому при их использовании
их не надо заключать в квадратные скобки
[ ].
Параметр
HelpCtx определяет экран контекстной
справки, соответствующий данному
диалоговому окну. Этот экран справки
будет появляться при нажатии пользователем
клавиши F1. Если вы справку не планируете,
при вызове MessageDlg надо задать нулевое
значение параметра HelpCtx..
Функция
MessageDlg возвращает значение, соответствующее
выбранной пользователем кнопке. Возможные
возвращаемые значения:
mrNone
mrAbort mrYes
mrOk
mrRetry mrNo
mrCancel
mrIgnore mrAll
Функция
MessageDlg очень полезна для быстрого создания
прототипа приложения и проверки
диалогового взаимодействия с пользователем.
Но у нее есть заметный недостаток: в
заголовках и надписях на кнопках тексты
английские, так что при использовании
русских сообщений получается смесь
русского с английским.
Имеется
также функция MessageDlgPos, во всем аналогичная
функции MessageDlg, но отображающее окно в
заданном месте экрана.
При
выводе простых сообщений без необходимости
анализировать ответ пользователя удобно
использовать другие процедуры Delphi —
ShowMessage и ShowMessageFmt.
Примеры:
1.
Заключительный диалог при окончании
работы приложения.
if
MessageDlg(‘Действительно хотите закончить
приложение?’,
mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
MessageDlg(‘Работа приложение закончена’,
mtInformation,
[mbOk], 0);
Close;
end;
Первый
вызов MessageDlg приводит к отображению окна
типа mtConfirmation с вопросом о завершении
приложения. Если пользователь нажимает
кнопку Yes, то выводится второе окно типа
mtInformation с сообщением о завершении.
1.
Сообщение об ошибке и замечание.
on Exception do
begin
MessageDlg(‘Произошла
ошибка.’, mtError,
[mbOk], 0);
MessageDlg(‘Будьте
внимательнее.
‘, mtWarning,
[mbOk], 0);
end;
3. В
каком-то диалоге, после редактирования
пользователем записи ему предлагается
вопрос о сохранении ее в базе данных.
Если пользователь выбирает кнопку Yes,
запись сохраняется методом Post; если
пользователь выбирает кнопку No, результаты
редактирования уничтожаются методом
Cancel; если же пользователь выбирает
кнопку Cancel, диалог закрывается.
case
MessageDlg(‘Занести запись
в БД?’,
mtCustom,
mbYesNoCancel, 0) of
mrYes: DataSet1.Post;
mrNo: DataSet1.Cancel;
mrCancel:
Close;
end;
В вызове
MessageDlg использован тип mtCustom, в результате
чего в заголовке окна указано имя
приложения. Для задания кнопок использована
константа mbYesNoCancel
Соседние файлы в папке _Delphi_1курс лекции
- #
23.03.20151.13 Mб23~WRL3549.tmp
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
Типов сообщений компилятора — более двухсот. Рассмотрим перечень наиболее встречающихся сообщений класса Error
- 0. <Что-то1> expected but <Что-то2> found. Обычно это сообщение возникает при синтаксической ошибке.Например,в случае небаланса скобок,компилятор сообщит: ‘)’ expected but ‘;’ found (вместо ожидавшейся скобки найдена запятая).
Компилятор часто сообщает, что ‘end’ ожидается,например:x:= 5,7; здесь неуместен разделитель-запятая, а сообщается про end. (‘END’ expected but ‘,’ found)
- 1. <Имя> is not a type identifier. Данное <Имя> не является именем типа.
- 2. ‘;’ not allowed before ‘Else’. Перед else нельзя ставить точку с запятой
- 3. Abstract method must be virtual or dynamic. Абстрактный метод должен быть виртуальным или динамическим.
- 4. Ambiguous overloaded call to <Имя блока>. Компилятор не может однозначно выбрать перегружаемый блок. Измените параметр.
- 5. Array type required. Ошибка возникает в случаях, когда в индексе элемента массива указано больше уровней, чем предусмотрено описанием, и если массив не описан. Например, после объявления двумерного массива х или простой переменной х ошибочно записывают элемент х[2,1,1] (в нем показано три измерения).
- 6. Assignment to FOR-loop variable <Имя>. Присваивание значения параметру FOR-цикла в теле цикла.
Например, вследствие описки дважды используется имя i в кратном цикле:
For i:= 1 to n do For i:= 1 to m do ...
- 7. Break or Continue outside of loop. Break или Continue — не в цикле.
- 8. Cannot initialize local variables. Локальные переменные запрещено инициализировать (задавать им значения при описании).
- 9. Cannot assign to/read a read-only/write-only property. Присвоение значения свойству read/only и чтение свойства write/only запрещены.
- 10. Constant expression expected.В этом месте должна стоять константа или константное выражение, например константа выбора в структуре Case.
- 11. Constant expression violates subrange bounds. Выход значения константы из диапазона. Контроль не полон. Например, «сойдет с рук» присваивание x:=3000000000, где х имеет тип integer, но начение х будет искажено.
- 12. Constant or type identifier expected. Требуется имя типа или тип-диапазон.
- 13. Could not compile used unit <Имя>. Компиляция присоединенного модуля <Имя> невозможна.
- 14. Data type too large. Тип определяет структуру размером более 2 Гбайт; это слишком много.
- 15. Declaration expected but <Что-то> found. Пропущено описание или оператор.
- 16. Declaration of <Имя> differs from previous declarations… Данный заголовок блока не соответствует упреждающему объявлению блока.
- 17. Default parameter <Имя> must be by-value or constant. Необязательный параметр (со значением по умолчанию) не должен вызываться по ссылке.
- 18. Expression expected. В этом месте программы должно стоять выражение.
- 19. Expression too complicated. Выражение излишне сложно для компиляции.
- 20. File type not allowed here. В этом месте или в этой роли файловую переменную нельзя использовать. Например, она не может быть формальным параметром-значением.
- 21. For loop control variable must be simple local variable. Параметр цикла должен быть простой локальной (описанной в этом же блоке) переменной.
- 22. For loop control variable must have ordinal type. Параметр цикла должен иметь порядковый тип.Вещественный тип запрещен.
- 23. Function needs result type. В заголовке функции надо указывать тип ее результата.
- 24. Identifier expected but <Что-то> found. В этом месте должно стоять имя. Например, пропущено имя функции после Function.
- 25. Identifier redeclared <Имя>.<Имя> описано повторно, но в пределах блока имя можно описать лишь раз. Проверьте, не обозначена ли локальная переменная тем же именем, что и формальный параметр блока.
- 26. Illegal character in input file <знак>. Запретный знак, например «русская» буква, либо вы оставили скобку }, убрав открывающую скобку {.
- 27. Illegal type in Read/Readln (Write/Writeln) statement. Элемент запрещенного типа в списке ввода/вывода.
- 28. Incompatible types <указание типов>. Несоответствие типов по присваиванию или типов операндов одной операции. Сообщение выдается и при неверном использовании структур. Например, z — запись, ошибочно записано присваивание z:= 0 (работать надо с полями записи).
- 29. Invalid function result type. Недопустимый тип результата функции.
- 30. Label already defined: <Метка>. <Метка> уже помечает другой оператор.
- 31. Left side cannot be assigned to. He может быть такой левой части в присваивании. Примеры: попытка присвоить значение файловой переменной, присвоение значения формальному параметру-константе.
- 32. Line too long. В строке программного текста больше 255 знаков.
- 33. Low bound exceeds high bound. Нижняя граница превышает верхнюю.
- 34. Missing operator or semicolon.Пропуск операции (например перед скобкой) или пропуск точки с запятой. При пропуске ‘;’ маркер ошибки стоит на очередном предложении (объявлении или операторе).
- 35. Missing parameter type. He указан тип формального параметра-значения или параметра процедурного типа.
- 36. Not enough actual parameters. He хватает фактических параметров.
- 37. Need to specify at least one dimension … Нужно задавать в операторе SetLength хотя бы один размер динамического массива.
- 38. Number of elements differs from declaration. Число элементов в структурной константе не соответствует ее описанию.
- 39. Operator not applicable to this operand type. Операция не применима к операндам данного типа. Например: ‘А’ or ‘В’; ‘Text1’* ‘Text2’.
- 40. Order of fields in record constant differs from declaration. Порядок полей в записи-константе не соответствует описанию записи.
- 41. Ordinal type required. Требуется порядковый тип (например, в индексе).
- 42. Out of memory. Компилятору не хватает памяти.
- 43. Statement expected but <Что-то> found. В этом месте должен стоять оператор. Сообщение выдается во всех случаях, когда в тело блока или секцию инициализации ошибочно помещают описание (<Что-то>). Ошибочная форма обращения к процедуре Procedure <Имя> или к функции Function <Имя> также вызывает сообщение.
- 44. Sets may have at most 256 elements. Множество (тип Set) не может содержать более 256 элементов.
- 45. Slice standard function only allowed as open array argument. Функцию Slice можно использовать лишь как фактический параметр
- 46. Statement not allowed in interface part. Предложения в секции интерфейса программного модуля недопустимы.
- 47. Syntax error in real number. Синтаксическая ошибка в записи числа вещственного типа.
- 48. There is no overload version of <Имя> that can be called with these arguments.Не предусмотрен перегружаемый блок <Имя>, который мог бы вызываться с таким аргументом. Пример: IntToStr(x), где х – выражение вещественного типа.
- 49. Too many actual parameters. Фактических параметров больше, чем формальных.
- 50. Type actual and formal var parameters must be identical. Тип фактического параметра должен быть идентичен типу формального параметра-переменной.
- 51. Type of expression must be <Тип>. Выражение должно быть указанного типа. Например,после While и Until должно стоять логическое выражение.
- 52. Undeclared identifier: <Имя>.Не описано <Имя>. Проверьте есть ли описание в нужном месте,нет ли описок в имени. Если указано имя компонента формы, проверьте,поместили ли компонент на данную форму.
- 53. Unexpected end of file in comment started on line <N>. Неожиданный конец файла при незавершенном комментарии, начало комментария — в строке N.
- 54. Unit name mismatch: <Имя>. Имя модуля ошибочно.
- 55. Unsatisfied forward or external declaration <Имя>. Отсутствует описание блока, объявление которого было дано (заголовок в интерфейсе или в описании объектного типа, либо упреждающее описание).
- 56. Unterminate string. He закрыта апострофом строка-константа типа string.
Рассмотрим также некоторые сообщения классов warning и hint.
- Return value of function <Имя> might be undefined. В теле функции нет присваивания ее результата.
- Variable <Имя> might not have been initialized. Указывает имя переменой, которой не задали значения.
- For-Loop variable <Имя> may be undefined after loop. Попытка использования значения параметра For-цикла после завершения этого цикла.
- Text after final ‘END.’ ignored by compiler. Текст, идущий за конечной строкой модуля, игнорируется компилятором.
- Variable <Имя> is declared but never used in <Имя блока>. Обращает внимание на переменную <Имя>, описанную,но не нашедшую применения.
- Value assigned to <Имя> never used. Хотя бы одно значение переменной <Имя> никак не использовано.
Несколько рекомендаций
Сосредотачивайтесь на первом сообщении компилятора. Исправление хотя бы одной ошибки и повторная компиляция может значительно уменьшить число сообщений об ошибках,поэтому не упорствуйте, стремясь понять сразу причину каждого сообщения.
Не удаляйте прежний вариант кода,пока не убедитесь,что ошибка устранена. Лучше на время закомментировать код,заключив его в скобки: { код }
Компилятор не анализирует, как будет выполняться программа, поэтому выход значения индекса из диапазона выявляет только если индекс задан константным выражением. Деление на ноль вообще пропускается, кроме оператора div, в случае если делитель — константное выражение.
В этом уроке мы с вами рассмотрим организацию некоторых сообщений в программе.
Сообщения присутствуют повсюду: когда вы пытаетесь закрыть не сохраненный проект, при появлении ошибки, когда программа сообщает о некотором событии.
Сообщения, «вылетающие» при работе программы, можно разделить на те, которые программист предусмотрел, и системные сообщения.
В большинстве случаев второй тип сообщений имеет непонятный для обычного пользователя вид. Как правило, сообщается англоязычный термин, иногда имеется и шестнадцатеричный адрес ошибки. Например, сообщение «I/O Error» говорит программисту или пользователю об ошибке ввода-вывода. Это может быть попытка записи данных в неоткрытый файл, попытка открыть несуществующий файл и т.п. Если такая ошибка в вашей русскоязычной версии программы имеет место, то, скорее всего данной ситуации программист просто не предусмотрел. В таких случаях, программа может себя повести совершенно непредсказуемо. Ведь вы помните из прошлых уроков, что не проконтролированный кусок программы на присутствие ошибки ведет к моментальному выходу из обрабатываемой процедуры, со всеми вытекающими из этого последствиями.
Но это маленькое отклонение от темы. Идея такова, надо самостоятельно просчитывать все возможные случаи и самостоятельно обрабатывать эти ситуации. Иногда, если надо, предупреждать пользователя об ошибках, может даже сообщать об окончании обработки данных. Вот о таких сообщениях мы и поговорим в этом уроке.
Можно разделить все программные сообщения на: информационные сообщения («Загрузка данных с дискеты завершена») , предупреждающие сообщения («Файл модифицирован. Сохранить?»), сообщения об ошибке («Файл данных программы не найден. Требуется переустановка программы»). Эта разбивка на типы сообщений является, естественно, не полным, его можно продолжать, но об этом немного позже.
Ради экономии своего времени, вы можете всегда, из любого места программы показать пользователю, к примеру, следующее сообщение:
Конечно, сообщение может быть и серьезным, можно подобные окошки использовать и для других целей вывода информации. Дело ваше. Я иногда этот вид сообщений использую для вывода информации о состоянии программы на этапе программирования.
В чем же заключается экономия времени и экономия текста кода программы. Такое сообщение выводится на экран одной строчкой:
ShowMessage(‘Привет!’);
Тип данных в скобках — String.
Все довольно просто, мы с вами эту команду неоднократно применяли в прошлых уроках.
На этой команде работа процедуры (не всей программы!) приостанавливается. Пока пользователь не нажмет на кнопку Ok, работа с приложением становится невозможным, т.е. нельзя «добраться» до окна, расположенного позади. Т.е. это сообщение открывается модально.
Как вы заметили, заголовок окна простой. Он содержит в себе текст, который отображен на панели задач. По умолчанию имеет название запускаемого EXE файла. Изначально это Project1, в последствии вы его можете сохранить под другим именем («Save Project As…»), при этом название проекта, вместе с ним название компилируемого EXE файла меняется.
Изменить название запущенной программы в панели задач можно в любом месте программы с помощью команды:
Application.Title:=’Название программы’;
К примеру, вы обрабатываете довольно объемный размер данных (чтение файлов), и хотите показывать процент выполнения задания прямо в панели задач (как это сделано в программе DrWeb). Ведь пользователь не всегда сможет смотреть на ваш 10-минутный процесс обработки данных, а скорее всего переключится на другую, менее трудоемкую операцию (карточный пасьянс), постоянно следя за процессом обработки на панели задач.
Изначально, еще до запуска программы на выполнение, на этапе разработки, вы можете это задать название программы в панели задач с помощью главного меню delphi «Project», дальше пункт «Options…», в открывшемся окне на вкладке Application указать в поле Title необходимую строку. Эта строка и будет отображена в панели задач. При этом следует помнить, что слишком длинная фраза в кнопке на панели задач полностью не будет показана. При этом она будет обрезана троеточием, а для того, чтобы узнать полное название запущенной программы, нужно будет подвести мышку (всплывающая подсказка Hint вам покажет полное название).
Вы уже знаете все прелести простой команды вывода строки ShowMessage. Из недостатков отмечу, что нельзя отдельно от названия программы в панели задач, менять заголовок окошка, нельзя получить иконку в окошке, нельзя отображать другие кнопки.
В delphi есть, можно сказать, встроенная команда отображения окна сообщения. Звучит оно так:
MessageDLG(ТЕКСТ_СООБЩЕНИЯ,ТИП_СООБЩЕНИЯ,КНОПКИ,ИНДЕКС_ПОМОЩИ);
Скажу сразу, что к нашим программам мы пока не пишем дополнительно файлов справки, поэтому ИНДЕКС_ПОМОЩИ у нас всегда будет нулевым. Для информации скажу, что если у нас таковой файл имеется, то можно в таком сообщении сделать кнопку «Help». Если пользователь озадачен вопросом или сообщением, то может, не закрывая этого окна, узнать подробнее о дальнейших этапах работы при выборе того или иного пункта.
ТЕКСТ_СООБЩЕНИЯ — строковая величина. Как в предыдущей команде, сообщение показывается внутри окна.
ТИП_СООБЩЕНИЯ — может принимать несколько значений. От этих значений зависит содержимое заголовка и иконка в левом верхнем углу окна.
Тип сообщения | Описание | Вид окна |
mtWarning | Можно использовать в предупреждающих сообщениях. Например, «Вы действительно желаете удалить все данные с диска С:» | |
mtError | Обычное окошко вывода сообщения об ошибки. Всем знаком его вид т.к. это наиболее частое окно в windows |
|
mtInformation | Какая-нибудь информация. Например, «Не найден файл настройки, создается заново» | |
mtConfirmation | Это запрос. Запрос на сохранение перед выходом, спрашивает перед удалением параметра, и т.п. На ваш собственный вкус | |
mtCustom | Это сообщение полностью аналогично ShowMessage |
КНОПКИ — содержит в себе массив кнопок, которые следует показывать в сообщении.
Даю перечень кнопок.
* mbYes
* mbNo
* mbOK
* mbCancel
* mbHelp
* mbAbort
* mbRetry
* mbIgnore
* mbAll
Рассказывать про каждую кнопку не буду, т.к. все равно ее название нельзя сменить. А если вам англоязычный термин непонятен, то тогда какой смысл ее применять :).
Массив кнопок задается в квадратных кавычках []. Например, нам надо задать три кнопки Yes, No, Cancel. Это делается так [mbYes,mbNo,mbCancel].
Поскольку кнопки в сообщении могут быть разные, то MessageDLG является функцией. Она возвращает результат нажатой кнопки.
Соответственно указанным выше кнопкам результат может принимать следующие значения
* mrNone — окно сообщения закрыто не с помощью кнопки (Alt+F4 или кнопкой «закрыть»)
* mrAbort
* mrYes
* mrOk
* mrRetry
* mrNo
* mrCancel
* mrIgnore
* mrAll
Рассмотрим пример. Нам надо спросить у пользователя о дальнейших действиях перед выходом из программы.
1. Сохранить файл.
2. Не сохранять файл.
3. Продолжить редактирование.
Var R:Word; // переменная, в которой хранится результат
…
R:=MessageDLG(‘Сохранить файл перед выходом?’,mtConfirmation,[mbYes,mbNo,mbCancel],0);
if R=mrYes then // если нажата кнопка Yes
begin
// сохраняем файл и завершаем программу
end;
if R=mrNo then // если нажата кнопка No
begin
// завершаем работу программы без сохранения
end;
if R=mrCancel then // если нажата кнопка Cancel
begin
// продолжаем работу без сохранения
end;
Мы рассмотрели команду MessageDLG. Это очень гибкая команда, есть много достоинств, но есть один существенный недостаток — англоязычный интерфейс.
Следующая команда использует системные сообщения пользователю вашей операционной системы. Т.е., если у вас установлена, например немецкая версия windows, то кнопки будут иметь соответствующие названия на немецком языке.
Вот эта команда:
MessageBox(Handle,ТЕКСТ_СООБЩЕНИЯ,ЗАГОЛОВОК_ОКНА,ТИП_СООБЩЕНИЯ);
Первый параметр — указатель на владельца окна сообщения. Этот параметр вам пока ничего не говорит, устанавливайте его в Handle (это ссылка на окно, откуда это сообщение вызывается).
ТЕКСТ_СООБЩЕНИЯ и ЗАГОЛОВОК_ОКНА — имеют тип PChar, поэтому, во избежание недоразумений и появления неизвестного рода ошибок, выдаваемых компилятором, меняйте тип String в PChar «на ходу». Например:
MessageBox(Handle,PChar(‘ТЕКСТ_СООБЩЕНИЯ’),PChar(‘ЗАГОЛОВОК_ОКНА’),…
Это был перевод из одного типа строковой величины в другой тип.
Теперь поговорим о немного сложном параметре ТИП_СООБЩЕНИЯ. Он включает в себя иконку и кнопки.
Кнопки:
* MB_ABORTRETRYIGNORE — кнопки «Прервать», «Повторить», «Пропустить».
* MB_OK — кнопка «Ok».
* MB_OKCANCEL — кнопки «Ok», «Отмена».
* MB_RETRYCANCEL — кнопки «Повторить» и «Отмена».
* MB_YESNO — две кнопки «Да» и «Нет».
* MB_YESNOCANCEL — кнопки «Да», «Нет», «Отмена».
Для того, чтобы отобразить иконку, нужно указать:
* MB_ICONEXCLAMATION
* MB_ICONWARNING
* MB_ICONINFORMATION
* MB_ICONASTERISK
* MB_ICONQUESTION
* MB_ICONSTOP
* MB_ICONERROR
* MB_ICONHAND
Если у вас в сообщении несколько кнопок, а по умолчанию нужно выбрать определенную, то такая кнопка задается:
MB_DEFBUTTON1 — где последняя цифра указывает номер кнопки, выбранной по умолчанию. Это свойство может быть полезным, например, чтобы обезопасить данные от случайного уничтожения. «Удалить файл?». Две кнопки — «Да», «Нет». По умолчанию мы программно выбираем вторую кнопку. Если пользователь сразу нажал на Enter, не осознавая своего поступка, можно сказать по привычке, то ничего страшного не произойдет.
Как же указать параметры иконки, кнопок, кнопки по умолчанию в одном параметре ТИП_СООБЩЕНИЯ. Очень просто. Простым знаком +
Например:
MessageBox(Handle,PChar(‘Выйти из программы?’),PChar(‘Мое сообщение’),MB_ICONINFORMATION+MB_OKCANCEL+MB_DEFBUTTON2);
Выглядит это в программе так, как показано на рисунке:
Итак, MessageBox можно считать идеальной командой вывода сообщения пользователю, которая будет совместима со всеми языковыми версиями windows.
Контроль нажатия на кнопку в MessageBox мы осуществляем аналогично MessageDLG, только возвращаемая величина может принимать следующие значение (соответственно нажатой кнопке):
* IDABORT
* IDCANCEL
* IDIGNORE
* IDNO
* IDOK
* IDRETRY
* IDYES
0 / 0 / 0 Регистрация: 07.12.2013 Сообщений: 5 |
|
1 |
|
Как сделать вывод сообщения об успехе или ошибке25.03.2015, 13:46. Показов 8588. Ответов 2
Помогите пожалуйста. В общем у менять есть edit 1 и edit 2 и надо сделать так,что если числа в edit 1 и edit 2 совпадают выводилось сообщение,что всё верно,а если числа разные то выводилась ошибка. Вроде,как то через showmessage делается,но точно не знаю. p.s Написал програмку для курсача,всё идеально,вот так сказать на финальной стадии застрял. Заранее спасибо!
__________________
0 |
DenNik Житель Земли 2994 / 2987 / 391 Регистрация: 26.07.2011 Сообщений: 11,456 Записей в блоге: 1 |
||||
25.03.2015, 13:51 |
2 |
|||
Решение
Написал програмку для курсача,всё идеально,вот так сказать на финальной стадии застрял. слабо верится. то есть ты сложное сделал, а на простом застрял!
2 |
0 / 0 / 0 Регистрация: 07.12.2013 Сообщений: 5 |
|
25.03.2015, 15:18 [ТС] |
3 |
Спасибо большое,всё отлично. Ну у меня не особо сложная задача. Суть: Берём два числа из десятичной переводим в двоичную,далее считаем их сумму в двоичной системе,затем переводим эту полученную сумму обратно в десятичную и итоге конечный результат в десятичной системе должен совпасть с суммой первых двух вводимы чисел.Как то так. Щяс еще быстренько менюшки и внешний вид оформлю и вообще всё отлично будет.
0 |
Исключения и взаимодействие с API
На текущий момент мы уже знаем достаточно многое из основ ООП. Однако созда-ние приложений под Windows в среде Delphi не ограничивается применением объ-ектно-ориентированного подхода. В частности, иногда возникают такие ситуации, что приходится обращаться к функциям Windows API напрямую. Кроме того, нам следует рассмотреть обработку ошибок в программах, а так же осветить вопрос некоторых глобальных объектов.
Исключения и их классы
Исключительные ситуации, или исключения (exception) могут возникать по ходу выполнения программы ввиду целого ряда причин. Они могут быть вызваны как ошибками в коде программы (например, при попытке обратиться к объекту, который не был предварительно создан), при вводе пользователем неожидаемых значений (например, строки, которая не может быть приведена к числу), при ошибках работы оборудования и т.д. Любая программа, претендующая на качественную разработку, должна уметь обрабатывать все подобные исключительные ситуации.
При возникновении подобных ошибок в программах, созданных при помощи Delphi, автоматически создается объект — Exception. Класс Exception является базовым для ряда других классов исключений — EMathError, EInvalidOp, EZeroDivide и т.д. (названия всех классов, относящиеся к исключениям, принято начинать не с буквы T, а с буквы E). Он происходит непосредственно от класса TObject и имеет 2 свойства — Message и HelpContext, а так же 8 методов.
Свойство Message имеет тип string и содержит описание исключения. При возникновении ошибки этот текст используется в окне сообщения. Ас войство HelpContext определяет индекс раздела справочного файла, содержащего информацию об ошибке. Если значение этого свойства равно нулю, то оно будет ссылаться на раздел справки родительского объекта.
Что касается методов, то все они представлены различными вариантами метода Create. Сам метод Create для исключений определен следующим образом:
constructor Create(const Msg: string);
Т.е., фактически, создавая исключение, следует сразу же назначить значение его свойству Message при помощи аргумента конструктора. Другой вариант конструктора, CreateHelp, позволяет параллельно назначить значение и для второго свойства:
constructor CreateHelp(const Msg: string; AHelpContext: Integer);
Если в тексте сообщения следует привести какие-либо динамически получаемые данные, то используют вариант конструктора с суффиксом Fmt:
constructor CreateFmt(const Msg: string; const Args: array of const);
constructor CreateFmtHelp (const Msg: string; const Args: array of const; AHelpContext: Integer);
При этом значения, указанные в массиве Args, будут подставлены в строку. Для этого используется функция Format, которой передаются строка и массив в качестве аргументов. Эта функция выполняет подстановку значений массива в места строки, выделенные при помощи символа %. Например, если строка выглядит как «Ошибка в функции %s», а массив определен как «[‘MyFunc’]», то результатом выполнения этой функции будет «Ошибка в функции MyFunc». Соответственно, создание подобного исключения будет выглядеть следующим образом:
constructor CreateFmt('Ошибка в функции %s', ['MyFunc']);
Как уже было отмечено, класс Exception имеет ряд потомков, каждый из которых предназначен для обработки того или иного типа ошибок. Например, для математических ошибок определен класс EMathError. Однако этот класс сам по себе не используется, зато его потомки, среди которых отметим классы EInvalidOp, EOverflow, EZeroDivide, используются для оповещения о таких ситуациях, как неверная операция, переполнение буфера и попытка деления на 0, соответственно.
При возникновении исключительной ситуации создается исключение того или иного вида, на основании чего можно определить, в чем именно кроется проблема.
Вызвать исключение в программе можно и искусственным методом — при помощи ключевого слова raise. Например программа может проверять какой-либо ввод пользователя, и в том случае, если он оказывается не тем, что ожидалось, генерировать исключительную ситуацию:
if password <> 'password' then raise Exception.Create('Неверный пароль!');
Выполнение оператора, указанного после raise, приводит к возникновению исключительной ситуации. После этого дальнейшее выполнение кода процедуры прерывается, равно как и кода, вызвавшего эту процедуру, если вызов был произведен из другой подпрограммы. Перемещение исключения можно рассматривать с точки зрения всплытия, т.е. с места своего возникновения ошибка последовательно «всплывает» сначала к вызвавшей данную процедуру или функцию подпрограмме, от нее — к следующей и т.д., пока не дойдет до уровня выполнения программы, т.е. до глобального объекта Application. На этом, конечном этапе и будет выдано сообщение об ошибке.
ПРИМЕЧАНИЕ
С некоторыми глобальными объектами, в том числе с Application, мы ознакомимся несколько позже в этой же главе.
Если при этом ошибка возникла в основном коде программы (т.е. вызвавший ошибку код был написан в самом файле проекта dpr), то на этом выполнение программы прекратится, о чем будет выдано сообщение (рис. 10.1).
Рис. 10.1. Ошибка приложения
В том же случае, если исключительная ситуация произошла в каком-либо модуле, то программа продолжит свою работу, ожидая дальнейших действий пользователя. Однако некоторые данные при этом могут оказаться утерянными (например, функция не вернет значения), или же может оказаться невыполненным какой-либо иной важный код, скажем, создающий глобальные объекты, сохраняющий информацию и т.д. Все это говорит о том, что исключительные ситуации следует обрабатывать.
Обработка исключений
Для обработки исключительных ситуаций в Delphi используются специальные операторы — try…except и try…finally. Эти операторы являются своего рода ловушками для исключительных ситуаций и позволяют разработчику приложения предусмотреть код, обрабатывающий возникшие исключения. Тем самым можно на любом этапе перехватить дальнейшее всплытие ошибки.
При помощи оператора try…except выполняет перехват ошибки, как правило, с целью ее подавления. Он имеет следующий синтаксис:
try
<потенциально вызывающий исключения код>
except
[ on <Класс исключения> do <оператор>; ]
end;
В том случае, если между except и end не писать никакого кода, то исключительная ситуация будет просто подавлена. Однако такое подавление чаще всего не является достаточным условием, поскольку оно не несет никакой информации ни пользователю, ни самой программе. Например, если так подавить ошибку с неверным паролем (а из-за подавления никакого сообщения выдано не будет), то пользователь такой программы может лишь догадываться, почему после того, как он сообщил пароль, ничего не происходит. В данном случае было бы правильным все-таки сообщить о том, что пароль введен не верно. Для этого используют вложенную секцию on…do:
try
if password <> 'password' then raise Exception.Create('Неверный пароль!');
except
on E: Exception do ShowMessage(E.Message);
end;
На сей раз в случае возникновения исключения пользователь получит уведомление о том, что же произошло. Для этого мы создали объект E, которому автоматически присваивается значение ошибки, и использовали его для вывода информации о ней. Дальнейшее выполнение программы в данном случае будет продолжено, поскольку после окончания блока try…end исключение более не существует.
На самом деле, использование такого объекта может быть необязательным, если детальная информация об ошибке не представляется необходимой. В таком случае можно использовать следующий блок обработки исключения:
try
if password <> 'password' then raise Exception.Create('Неверный пароль!');
except
on Exception do ShowMessage('ОШИБКА!');
end;
Что касается блоков обработки, то их может быть несколько, каждый — для своего класса исключения:
try
a:=b*c/d;
except
on EZeroDivide do ShowMessage('Делить на 0 нельзя');
on EOverflow do ShowMessage('Слишком большое число');
on EMathError do ShowMessage('Математическая ошибка');;
end;
Здесь мы определили 3 блока, и в случае возникновения той или иной исключительной ситуации, будет выдано то или иное сообщение. Этим данная часть оператора напоминает оператор case, для которого, как мы помним, существовал вариант «для остальных случаев» — else. Имеется такая возможность и здесь:
try
a:=b*c/d;
except
on EZeroDivide do ShowMessage('Делить на 0 нельзя');
on EOverflow do ShowMessage('Слишком большое число');
on EMathError do ShowMessage('Математическая ошибка');
else
ShowMessage('Общая ошибка');
end;
Наконец, если тип ошибки не имеет никакого значения, то можно оставить только общий обработчик, для чего не требуется даже ключевого слова else:
try
a:=b*c/d;
except
ShowMessage('Общая ошибка');
end;
Важно лишь отметить, что все эти блоки выполняются только тогда, когда возникает исключительная ситуация. При этом, если после ключевого слова try расположено несколько операторов, и исключение возникает в одном из них, то все последующие выполнены не будут. Вместе с тем, случаются ситуации, когда имеется код, который следует выполнить в любом случае, без оглядки на то, что случится перед этим. В таких случаях используют другой оператор - try…finally, и требующий обязательного выполнения код помещают в часть после finally. Типичным примером использования такой конструкции можно считать уничтожение объектов или иные операции освобождения памяти, а так же закрытия файлов и т.д. Например, при работе с файлами всегда следует использовать try…finally для закрытия файла:
try
Rewrite(F);
writeln(F,s);
finally
CloseFile(F);
end;
В данном случае, если даже произойдет ошибка, связанная с доступом к файлу — т.е. если его не удастся открыть (например, если диск защищен от записи), или же записать в него информацию (нет места на диске), закрыт он будет в любом случае, что предотвратит возможные дальнейшие ошибки. При этом само исключение подавлено не будет, т.е. сообщение об ошибке будет выведено и дальнейшее выполнение подпрограммы (но уже после блока finally…end) будет прервано.
Но оба подхода можно комбинировать. Например, в данном случае блок try…finally можно вложить в блок try…except:
try
AssignFile(F);
try
Rewrite(F);
writeln(F,s);
finally
CloseFile(F);
end;
except
on E: Exception do ShowMessage(E.Message);
end;
Кроме этого, в Delphi допускается вкладывать однотипные обработчики ошибок друг в друга, например, один блок try…except может быть вложен в другой.
Глобальные объекты
При создании Windows-приложений нередко возникает необходимость в управлении программой в целом как отдельным объектом. Для этих целей в Delphi предусмотрен специальный объект — Application класса TApplication, представляющий программу в целом. Его использование можно увидеть в любом файле проекта VCL-приложения. Чтобы увидеть это, достаточно создать новое приложение и открыть файл проекта, для откытия которого можно воспользоваться списком модулей, вызываемого кнопкой View Unit (можно так же через главное меню — View ‘ Units, или при помощи сочетания горячих клавиш Ctrl+F12). По умолчанию он имеет название Project1, и его стандартный код имеет вид, приведенный в листинге 10.1.
Листинг 10.1. Заготовка кода для VCL-приложения
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Уже по приведенному в листинге коду мы можем познакомиться с 3 основными методами этого объекта — Initialize, CreateForm и Run. Первый производит подготовительную работу, т.е. фактически, создает объект приложения. Метод CreateForm используется для создания окон приложения, а метод Run производит фактический запуск программы на выполнение. Среди других методов приложения моно отметить такие, как Minimize и Restore, служащие, соответственно, для сворачивания программы на панель задач и для ее восстановления, а так же метод BringToFront, который выводит окно на верхнюю поверхность рабочего стола. Метод Terminate используется для прекращения работы программы (он вызывается автоматически, когда закрывается главное окно приложения). Еще 4 метода — HelpCommand, HelpContext, HelpJump и HelpKeyword — предназначены для работы со справочными файлами.
При работе приложения, в случае обработки больших массивов данных, возникают случаи, когда программа не только не реагирует на действия пользователя, но даже не может выполнить обновление собственного окна. Для того, чтобы предотвратить подобные ситуации, используют специальный метод — ProcessMessages, который предписывает приложению обработать накопившуюся очередь сообщений.
Среди свойств приложения, прежде всего, следует отметить такие, как Title, Icon и HelpFile. Свойство Title определяет заголовок программы, т.е. то, что вы видите на панели задач. Свойство Icon определяет значок («иконку») программы. Ну а свойство HelpFile связывает приложение с файлом справочной информации. Все эти свойства можно определить как программно, написав соответствующий код, так и при помощи окна свойств проекта (Project > Options), на закладке Application (рис. 10.2).
Рис. 10.2. Установка параметров приложения в окне свойств проекта
Если установить в диалоге Project Options новые значения и нажать на кнопку OK, то внесенные изменения для свойств Title и HelpFile отобразятся в коде программы. Что касается значка программы, то он хранится в отдельном файле ресурсов (res), который присоединяется к приложению в процессе компиляции, для чего используется директива «{$R *.res}».
Поскольку любой визуальный компонент может отображать всплывающую текстовую подсказку, то для объекта Application предусмотрен ряд свойств, управляющих видом и выводом таких подсказок. В частности, цвет определяют при помощи свойства HintColor, задержку перед появлением после наведения на компонент мышки — при помощи HintPause, а время его отображения — свойством HintHidePause.
Некоторые свойства приложения доступны только во время выполнения. Среди них можно выделить свойство ExeName, содержащее информацию об имени самого исполняемого файла, включая полный путь к нему.
Помимо Application, при запуске приложения создается еще один глобальный объект, представляющий экранную среду — Screen. При помощи этого объекта можно получить информацию о разрешение экрана, установить вид курсора мыши для приложения, или узнать количество его окон. Основные свойства класса TScreen приведены в таблице 10.1.
Свойство | Тип | Описание |
---|---|---|
ActiveControl | TWinControl | Указывает, какой элемент управления в данный момент имеет фокус ввода |
ActiveForm | TForm | Указывает, какое окно активно в данный момент |
Cursor | TCursor | Определяет вид указателя курсора мышки для приложения |
Cursors | array of HCursor | Список всех курсоров, доступных для приложения |
Fonts | TStrings | Список названий всех шрифтов, доступных для вывода на экран |
FormCount | Integer | Указывает на число окон (форм), созданных приложением |
Forms | array of TForm | Список всех окон, созданных приложением |
Height | Integer | Указывает на вертикальное разрешение экрана |
HintFont | TFont | Определяет шрифт для всплывающих подсказок |
IconFont | TFont | Определяет шрифт для подписей к значкам в диалогах выбора файлов |
MenuFont | TFont | Определяет шрифт для меню |
Width | Integer | Указывает на горизонтальное разрешение экрана |
WorkAreaHeight | Integer | Указывает на высоту рабочего стола Windows |
WorkAreaLeft | Integer | Указывает на координаты левого угла рабочего стола |
WorkAreaRect | Integer | Указывает на координаты прямоугольника, образующего рабочий стол |
WorkAreaTop | Integer | Указывает на координаты верхнего угла рабочего стола |
WorkAreaWidth | Integer | Указывает на ширину рабочего стола |
Использовать объекты Screen и Application можно как в главном модуле программы (файле проекта), так и в модулях отдельных форм. При использовании в главном мо-дуле обычно устанавливают глобальные параметры, например, вид всплывающих подсказок. В частности, можно определить довольно-таки экзотический вид всплы-вающих подсказок, дополнив программу следующими строками:
Screen.HintFont.Color:=$00408080; // цвет шрифта
Screen.HintFont.Size:=14; // размер шрифта
Application.HintColor:=$0080FF80; // цвет фона
Application.HintPause:=1000; // задержка перед появлением 1 секунда
Application.HintHidePause:=2000; // время показа 2 секунды
Если вставить этот код в dpr-файл перед обращением к методу Application.Run, то можно будет убедиться, что через секунду после наведения курсора на окно запу-щенного приложения будет появляться всплывающая подсказка с крупным коричне-вым текстом на зеленом фоне. Разумеется, при этом для окна приложения следует установить значения свойства ShowHint в true, и написать какой-либо текст для свой-ства Hint. Впрочем, это можно сделать не только через инспектор объекта в процессе разработки приложения, но и программно, поместив соответствующий код после создания формы. В результате мы получим код, приведенный в листинге 10.2.
Листинг 10.2. Использование объектов Application и Screen
program app_scr;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Form1.Hint:='Ну и подсказочка!';
Form1.ShowHint:=true;
Screen.HintFont.Color:=$00408080;
Screen.HintFont.Size:=14;
Application.HintColor:=$0080FF80;
Application.HintPause:=1000;
Application.HintHidePause:=2000;
Application.Run;
end.
Здесь же можно установить и такие параметры, как заголовок программы, используя свойство Title объекта Application:
Application.Title:='Super Hint!';
Кроме того, можно поэкспериментировать с такими свойствами объекта Screen, как Height и WorkAreaHeight, причем для вывода информации можно использовать заго-ловок главного окна:
Form1.Caption:='Экран '+IntToStr(Screen.Height)+', рабочий стол '+ IntToStr(Screen.WorkAreaHeight);
В данном случае в строку Uses потребуется дописать модуль SysUtils, поскольку ис-пользованная здесь функция IntToStr расположена именно в этом модуле. Оконча-тельный вариант программы можно найти в каталоге DemoPart2Global.
Работа с INI-файлами
При разработке приложений часто встает вопрос о том, где и как хранить информа-цию, связанную с его настройками. Нередко для этих целей используются специаль-ные INI-файлы, которые хранят в себе информацию, разбитую по логическим груп-пам в виде «ключ-значение». В Delphi имеется класс, обеспечивающий простую ра-боту с такими файлами — TIniFile. Чтобы приложение могло получить доступ к этому классу, в секцию используемых модулей следует добавить inifiles.
Имя файла, ассоциированного с объектом типа TIniFile, задается непосредственно при создании экземпляра этого класса, в конструкторе Create:
var MyIni: TIniFile;
...
TIniFile.Create('myfile.ini');
Впоследствии можно узнать, какой файл ассоциирован с данным объектом при по-мощи его свойства FileName, однако изменить его уже не получится. Вместе с тем, у TIniFile имеется свыше 20 методов, при помощи которых можно считывать, прове-рять и изменять содержимое INI-файла. Все они приведены в таблице 10.2.
Метод | Принимаемые параметры | Описание |
---|---|---|
DeleteKey | const Section, Ident: String | Удаляет указанный ключ из INI файла |
EraseSection | const Section: String | Удаляет содержимое указанной секции в INI файле |
ReadSection | const Section: String; Strings: TStrings | Считывает имена всех ключей в указанной секции и заносит их в список строк |
ReadSections | Strings: TStrings | Считывает названия всех секций в файле и заносит их в список строк |
ReadSectionValues | const Section: String; Strings: TStrings | Считывает все значения в указанной секции и заносит их в список строк |
ReadString | const Section, Ident, Default: String | Считывает и возвращает значение-строку из указанного ключа |
WriteString | const Section, Ident, Value: String | Записывает значение-строку в указанный ключ |
ReadBool | const Section, Ident: String; Default: Boolean | Считывает и возвращает булево значение из указанного ключа |
ReadDate | const Section, Ident: String; Default: TDateTime | Считывает и возвращает значение-дату из указанного ключа |
ReadDateTime | const Section, Ident: String; Default: TDateTime | Считывает и возвращает значение-дату и время из указанного ключа |
ReadFloat | const Section, Ident: String; Default: Double | Считывает и возвращает значение-вещественное число из указанного ключа |
ReadInteger | const Section, Ident: String; Default: Longint | Считывает и возвращает значение-целое число из указанного ключа |
ReadTime | const Section, Ident: String; Default: TDateTime | Считывает и возвращает значение-время из указанного ключа |
SectionExists | const Section: String | Проверяет INI файл на наличие указанной секции |
WriteBool | const Section, Ident: String; Value: Boolean | Записывает булево значение в указанный ключ |
WriteDate | const Section, Ident: String; Value: TDateTime | Записывает значение-дату в указанный ключ |
WriteDateTime | const Section, Ident: String; Value: TDateTime | Записывает значение-дату и время в указанный ключ |
WriteFloat | const Section, Ident: String; Value: Double | Записывает значение-вещественное число в указанный ключ |
WriteInteger | const Section, Ident: String; Value: Longint | Записывает значение-целое в указанный ключ |
WriteTime | const Section, Ident: String; Value: TDateTime | Записывает значение-время в указанный ключ |
ValueExists | const Section, Ident: String | Проверяет INI файл на наличие указанного ключа в определенной секции |
Таким образом, можно без каких-либо дополнительных накладных расходов (с точки зрения написания собственного кода), создавать и считывать стандартные INI-файлы. Например, мы можем создать приложение, которое сможет «запоминать» введенную информацию и отображать ее при следующем запуске. В принципе, мы уже делали нечто подобное еще при создании программы «угадывания чисел», рассмотренной в первой части. Однако тогда мы лишь последовательно записывали в файл пару строк, а затем таким же образом их считывали. Но если бы нам требовалось сохранить большее количество значений, то мы столкнулись бы с трудностями такого рода, как невозможность идентифицировать то или иное значение при просмотре файла. Кроме того, пришлось бы постоянно держать в уме, какая по строка что должна хранить. Использование INI-файлов решает эту задачу.
Для примера возьмем консольное приложение, которое будет последовательно спрашивать различную информацию у пользователя, а затем сохранит ее в указанном файле. При следующем запуске она сможет считать этот файл и вывести информацию из него на экран. Основное тело программы при этом может получиться примерно таким, как показано в листинге 10.3.
Листинг 10.3. Название листинга
program myini;
{$APPTYPE CONSOLE}
uses
SysUtils, IniFiles;
var
ans: Char;
fn: string;
begin
write('Load data from an INI file? [Y/N]');
readln(ans);
if (ans='Y') or (ans='y') then begin
write('Please input file name: ');
readln(fn);
fn:='c:'+fn+'.ini';
if FileExists(fn) then begin
ShowData(fn);
end else begin
writeln('File not found and will be created.');
FillData(fn);
end;
end else begin
write('Please input file name to save data: ');
readln(fn);
fn:='c:'+fn+'.ini';
FillData(fn);
end;
readln(fn);
end.
Прежде всего, наша программа интересуется, хочет ли пользователь просмотреть информацию из уже существующего файла, или нет, и если хочет, то запрашивает имя файла. Здесь мы подразумеваем, что пользователь будет вводить только имя файла, без пути и расширения, которые добавляются автоматически. Затем стандартная функция FileExists проверяет получившийся файл на существование, после чего либо выводит его содержимое при помощи процедуры ShowDate (которую нам еще предстоит создать), либо выводит сообщение о том, что файл не найден, но будет создан. После этого программа обращается к процедуре FillData, которая так же будет нами написана для ввода информации и сохранения ее в INI-файле. Эта же функция будет вызвана и в том случае, если пользователь изначально откажется от вывода информации, в таком случае программа предварительно запросит имя файла для дальнейшего сохранения.
Теперь, когда основа программы готова, можно определиться, какие данные мы хотим хранить, и какой для этого понадобится формат файла. Допустим, мы хотим сохранить информацию 2-х категорий: персональную и рабочую. В таком случае наш INI файл будет состоять из 2 секций, скажем, Userdata и Jobdata. В первой секции сохраним имя (Name) и возраст (Age), а во второй — должность (Title) и оклад (Salary). Процедура, отвечающая за вывод информации, получится достаточно простой — в ней достаточно создать INI-файл с указанным именем и последовательно считывать информацию, попутно выводя ее на экран. Например, для строкового значения мы получим следующий код:
writeln('Name...... '+IniF.ReadString('Userdata','Name','Anonymous'));
Если же речь идет о числовом значении, то нам придется предварительно преобразовать его в строку:
writeln('Age....... '+IntToStr(IniF.ReadInteger('Userdata','Age',0)));
Несколько сложнее получится код процедуры для записи файла, что, впрочем, связано не с самой записью данных, а в том, что их предварительно следует получить от пользователя. Поэтому там, где мы при выводе обходились одной строкой кода, для ввода понадобится целых 3, а так же переменная для хранения вводимого значения:
write('Name: ');
readln(s);
IniF.WriteString('Userdata','Name',s);
Подобный код потребуется выполнить для каждого поля данных, при этом нам понадобятся 3 различных переменных для хранения данных 3 типов (дважды — строк, и по разу целое и вещественное числа). Предварительно следует не забыть создать переменную типа TIniFile, и вывести пояснительный текст, а к завершению работы процедуры освободить память, занимаемую более не нужной переменной. Последнее условие следует выполнить и в процедуре ShowData. В итоге мы получим код, приведенный в листинге 10.4.
Листинг 10.4. Процедуры сохранения и считывания INI-файлов
procedure FillData(fn: string);
var
IniF: TIniFile;
s: string;
i: integer;
f: double;
begin
IniF:=TIniFile.Create(fn);
writeln('Please fill a form...');
write('Name: ');
readln(s);
IniF.WriteString('Userdata','Name',s);
write('Age: ');
readln(i);
IniF.WriteInteger('Userdata','Age',i);
write('Position: ');
readln(s);
IniF.WriteString('Jobdata','Title',s);
write('Salary: ');
readln(f);
IniF.WriteFloat('Jobdata','Salary',f);
IniF.Free;
end;
procedure ShowData(fn: string);
var
IniF: TIniFile;
begin
IniF:=TIniFile.Create(fn);
writeln('Name...... '+IniF.ReadString('Userdata','Name','Anonymous'));
writeln('Age....... '+IntToStr(IniF.ReadInteger('Userdata','Age',0)));
writeln('Position.. '+IniF.ReadString('Jobdata','Title','Unemployed'));
writeln('Salary.... '+FloatToStrF(IniF.ReadFloat('Jobdata','Salary',0.00),ffFixed,6,2));
IniF.Free;
end;
С полным исходным кодом программы можно ознакомиться в примере, расположенном в каталоге DemoPart2IniFiles.
Работа с реестром Windows
Файлы INI и класс TIniFiles — достаточно удобный способ хранения различной настроечной информации. Тем не менее, начиная с Windows 95, появилось централизованное хранилище для настроек системы и всех установленных программ — реестр (Registry). При разработке приложений в Delphi удобнее всего работать с реестром, используя класс TRegistry. Чтобы включить объявление этого класса, следует указать модуль registry в списке uses.
Реестр Windows имеет несколько ключевых разделов, в чем можно убедиться, открыв имеющуюся в Windows программу редактирования реестра (regedit). В частности это разделы HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_USERS, HKEY_LOCAL_MACHINE и HKEY_CURRENT_CONFIG. Чтобы приступить к работе с реестром из программы, требуется указать один из разделов. Делается это при помощи свойства RootKey:
var Reg: TRegistry;
...
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
Далее в ход идут методы класса TRegistry. В частности, за выбор раздела реестра, из которого надо будет считывать данные, используется метод OpenKeyReadOnly. В качестве аргумента ему передается адрес раздела реестра, например:
Reg.OpenKeyReadOnly('SOFTWAREMySoftTestApp');
Если указанный раздел существует, и к нему может быть обеспечен доступ, то обращение к данному методу вернет истину. Если же раздела может не существовать, или если требуется открыть раздел на запись, то используют метод OpenKey:
Reg.OpenKey('SOFTWAREMySoftTestApp',true);
Для него в качестве 2-го параметра указывают булево значение, которое указывает на то, должен ли указанный раздел быть создан, если его не существует. В результате выполнения приведенного кода раздел, при необходимости, будет создан и открыть на чтение и запись. Если же требуется только создать новый раздел, то используют метод CreateKey:
Reg.CreateKey('SOFTWAREMySoftTestApp');
Для удаления раздела используют метод DeleteKey, а для проверки указанного раздела на существование — KeyExists. Подобно методу CreateKey, эти методы так же принимают адрес раздела и возвращают ложь или истину в зависимости от результата операции.
Если же требуется выполнить проверку на наличие значения в текущем открытом разделе, то используют метод ValueExists, которому в качестве аргумента передают имя значения.
Что касается записи и считывания значений, то, подобно классу TIniFile, для TRegistry определен ряд методов для взаимодействия с данными различных типов, причем для реестра к типам Boolean, String, Double, Integer и даты-времени, добавляется еще и Currency. Соответственно, мы имеем 8 пар методов для этих целей.
Для примера рассмотрим приложение, состоящее из единственного окна, которое будет «запоминать» свои размеры и расположение на экране. Для этого создадим новое VCL-приложение (File ‘ New ‘ Application), щелкнем сначала по его форме (Form1), а затем — по окну инспектора объекта (Object Inspector). В нем выберем закладку Events (события), найдем событие OnClose и дважды щелкнем по строке напротив. В результате мы получим заготовку для процедуры TForm1.FormClose, в которую нам надо будет добавить объявление переменной для реестра:
var
Reg: TRegistry;
Затем в теле функции напишем следующие строки:
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
Reg.OpenKey('SOFTWAREMySoftTestApp',true);
Reg.WriteInteger('left',Form1.Left);
Reg.WriteInteger('top',Form1.Top);
Reg.WriteInteger('height',Form1.Height);
Reg.WriteInteger('width',Form1.Width);
Reg.Free;
Вначале мы создаем экземпляр класса, затем выбираем корневой раздел, после чего открываем ключ на запись (он будет создан при необходимости), и последовательно заносим в него пространственные координаты окна. В завершение работы этой процедуры мы экземпляр класса удаляется из памяти за ненадобностью.
Теперь рассмотрим считывание из реестра, для чего создадим процедуру, обрабатывающую событие создания окна, для чего в инспекторе объекта найдем событие OnCreate и сделаем двойной щелчок напротив него. В получившейся процедуре нам так же понадобится сначала объявить переменную Reg, затем создать экземпляр класса и установить корневой раздел. Затем следует открыть раздел на чтение, причем если это окажется невозможным (а при первом запуске так и будет, поскольку раздел будет создан только после выхода из программы), то считывать ничего не потребуется. Поэтому задействуем условный оператор:
if Reg.OpenKeyReadOnly('SOFTWAREMySoftTestApp') then begin
...
end;
После этого остается считать все нужные данные из реестра, присваивая хранящиеся в них значения соответствующим свойствам Form1. Например, для высоты и ширины мы получим:
Form1.Height:=Reg.ReadInteger('height');
Form1.Width:=Reg.ReadInteger('width');
Вместе с тем, было бы полезным все-таки проверять наличие запрашиваемых значений в реестре, чтобы избежать возникновения исключительных ситуаций. Для этого всякий раз надо будет проверять ключ на существование:
if Reg.ValueExists('width') then Form1.Width:=Reg.ReadInteger('width');
В результате код этого модуля программы получит приблизительно такой вид, как показано в листинге 10.5.
Листинг 10.5. Сохранение координат и размеров окна в реестре
unit Unit1;
interface
uses
Windows, Forms, Registry;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
Reg: TRegistry;
begin
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
if Reg.OpenKeyReadOnly('SOFTWAREMySoftTestApp') then begin
if Reg.ValueExists('left') then
Form1.Left:=Reg.ReadInteger('left');
if Reg.ValueExists('top') then
Form1.Top:=Reg.ReadInteger('top');
if Reg.ValueExists('height') then
Form1.Height:=Reg.ReadInteger('height');
if Reg.ValueExists('width') then
Form1.Width:=Reg.ReadInteger('width');
end;
Reg.Free;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
Reg: TRegistry;
begin
Reg:=TRegistry.Create;
Reg.RootKey:=HKEY_CURRENT_USER;
Reg.OpenKey('SOFTWAREMySoftTestApp',true);
Reg.WriteInteger('left',Form1.Left);
Reg.WriteInteger('top',Form1.Top);
Reg.WriteInteger('height',Form1.Height);
Reg.WriteInteger('width',Form1.Width);
Reg.Free;
end;
end.
С исходным кодом приложения так же можно ознакомится, посмотрев его в каталоге DemoPart2Registry.
Процедуры и функции стандартных диалогов
В Delphi предусмотрено несколько процедур и функций, предназначенных для вывода простых диалоговых окон. В частности, процедура ShowMessage и функция MessageDlg позволяют вывести сообщение, а функции InputBox и InputQuery отображают окно для ввода информации.
Простейшим вариантом вывода сообщения является использование процедуры ShowMessage. Она отображает переданную ей в качестве аргумента строку на простом диалоговом окне с единственной кнопкой OK. Типичный пример использования этой процедуры — информирование пользователя о выполнении той или иной части программы:
ShowMessage('Формат диска C: завершен');
Кроме самой процедуры ShowMessage, имеются 2 других варианта — ShowMessagePos и ShowMessageFmt. Первый позволяет вывести диалоговое окно в определенном месте, что достигается путем указания координат по горизонтали и вертикали:
ShowMessagePos('Формат диска C: завершен',100,200);
Второй позволяет вывести отформатированную строку, используя обращение к функции Format, как и в случае с конструктором исключений. Таким образом, для вывода сообщения с переменной частью предпочтительно использовать именно этот вариант процедуры:
ShowMessageFmt('Формат диска %s завершен',['C:']);
Все варианты процедуры ShowMessage выводят окно с единственной кнопкой OK, при этом, разумеется, никакого значения не возвращается. В том же случае, если сообщение выводится для того, чтобы запросить у пользователя подтверждения на то или иное действие, то нам, во-первых, потребуется функция — чтобы получить вариант ответа, а так же возможность указать возможные варианты. Все это мы имеем в лице функции MessageDlg, которая имеет следующее определение:
function MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Word;
Здесь сразу же требуется прояснить 2 момента: тип диалога и тип кнопок. За тип диалога отвкечает 2-й параметр, который имеет тип TMsgDlgType и может принимать одно из следующих значений:
- mtWarning — диалог типа «предупреждение», имеет заголовок «Warning» и рисунок, изображающий восклицательный знак на фоне желтого треугольника;
- mtError — диалог типа «ошибка», имеет заголовок «Error» и изображение косого креста в красном круге;
- mtInformation — диалог типа «информация», имеет заголовок «Information» и значок со стилизованной буквой «i» в синих тонах;
- mtConfirmation — диалог типа «подтверждение», имеет заголовок «Confirm» и рисунок с зеленым вопросительным знаком;
- mtCustom — диалог произвольного типа, имеет заголовок, соответствующий имени выполняемого файла и не содержит изображения.
ПРИМЕЧАНИЕ
Внешний вид изображений, символизирующих диалог того или иного типа, периодически претерпевает некоторые изменения, в зависимости от версии Delphi.
Следующий параметр, имеющий перечисляемый тип TMsgDlgButtons, позволяет указать, какие кнопки должны быть расположены на диалоговом окне. Всего предусмотрено 11 вариантов кнопок, среди них предусмотрены такие, как OK, Cancel, Yes, No и т.д. При этом каждая такая кнопка (кроме Help), будучи нажатой пользователем, закрывает окно, а функция возвращает значение, соответствующее нажатой кнопке. Все варианты кнопок и возвращаемые ими значения, приведены в таблице 10.3.
Значение | Описание | Возвращаемый результат |
---|---|---|
mbYes | Кнопка с надписью «Yes» (да) | mrYes |
mbNo | Кнопка с надписью «No» (нет) | mrNo |
mbOK | Кнопка с надписью «OK» | mrOk |
mbCancel | Кнопка с надписью «Cancel» (отмена) | mrCancel |
mbAbort | Кнопка с надписью «Abort» (прервать) | mrAbort |
mbRetry | Кнопка с надписью «Retry» (повторить) | mrRetry |
mbIgnore | Кнопка с надписью «Ignore» (игнорировать) | meIgnore |
mbAll | Кнопка с надписью «All» (все) | mrAll |
mbNoToAll | Кнопка с надписью «No to All» (нет для всех) | mrNoToAll |
mbYesToAll | Кнопка с надписью «Yes to All» (да для всех) | mrYesToAll |
mbHelp | Кнопка с надписью «Help» (справка) | — |
Следует оговориться, что все возвращаемые значения, на самом деле, являются целыми числами, что видно по определению функции. Но поскольку запомнить, что, к примеру, возвращаемое значение для OK — это 1, а для Yes — 6, весьма проблематично, то на практике вместо них используются константы, которые как раз и были приведены в таблице 10.3.
Что касается вариантов использования этой функции, то оно сводится к тому, что пользователю выводится какое-либо сообщение, предусматривающее возможность того или иного ответного действия:
MessageDlg('Ошибка чтения с диска. Продолжить?', mtError, [mbRetry, mbAbort], 0);
Поскольку эта функция возвращает то или иное значение, то ее использование часто сопровождается условным оператором:
if MessageDlg('Форматировать диск C:?',mtConfirmation,[mbYes,mbNo],0) = mrYes then FormatDriveCProc();
Другой вариант, для случая с множественными вариантами ответа — использование совместно с оператором-переключателем:
case MessageDlg('Файл изменен. Сохранить перед выходом?', mtWarning, [mbYes, mbNo, mbCancel], 0) of
mrYes: begin SaveFileProc(); Close; end;
mrNo: Close;
mrCancel: exit;
end;
Подобно процедуре ShowMessage, для функции MessageDlg так же предусмотрен вариант с позиционированным выводом окна. Такой вариант этой функции называется MessageDlgPos. Ее отличие от MessageDlg состоит в том, что к списку аргументов добавлено еще 2 параметра, отвечающих за расположение окна. Такой вариант используется, например, при поиске с заменой в текстовых редакторах:
MessageDlgPos('Заменить это вхождение?', mtConfirmation, [mbYes, mbNo], 0, X, Y);
Все рассмотренные нами подпрограммы применяются для вывода сообщений. Что касается ввода, то для этих целей, как уже отмечалось, используют функции InputBox и InputQuery. Обе они выводят окно, позволяющее пользователю ввести какое-либо значение — число или строку. Различие между ними состоит лишь в том, что InputBox возвращает непосредственно результат (в виде строки), а InputQuery — истину или ложь, в зависимости от того, нажмет пользователь OK или Cancel. При этом само значение возвращается в качестве одного из параметров. В итоге мы имеем следующий синтаксис для этих функций:
function InputBox(const ACaption, APrompt, ADefault: string): string;
function InputQuery(const ACaption, APrompt: string; var Value: string): Boolean;
Таким образом, какую из функций лучше использовать в данный момент, зависит от контекста применения. Например, если надо просто получить какое-либо значение от пользователя, то можно использовать функцию InputBox:
UserName := InputBox('Запрос','Введите ваше имя','анонимно');
В данном случае последний параметр функции будет использован в качестве значения по умолчанию (рис. 10.3).
Рис. 10.3. Диалоговое окно функции InputBox
Если же в зависимости от того, введет или нет пользователь новое значение, должна быть выполнена та или иная ветвь алгоритма, то предпочтительнее использовать функцию InputQurey:
if InputQurey('Курс доллара ','Введите новый курс',NewCur) then UpdatePrc();
Помимо приведенных здесь процедур и функций, в VCL имеется ряд иных подпрограмм, использующих диалоговые окна, включая такие, как диалог выбора каталога или файла. Но поскольку их использование сопряжено с некоторыми неудобствами, в частности, им приходится передавать большое число параметров, то на практике для тех же целей чаще используют компоненты. Например, функция PromptForFileName используется для вывода диалога сохранения или открытия файла. Но более типичным (и удобным!) вариантом обращения к таким диалогам является использование таких стандартных компонент VCL, как TOpenDialog и TSaveDialog, с которыми мы познакомимся в следующей части этой книги.
Обработка сообщений и Windows API
Как ни широк охват VCL, иногда все-таки возникает потребность в обращении к функциям Windows напрямую. Например, для того же самого вывода окна с текстовым сообщением можно использовать собственную функцию Windows API — MessageBox:
MessageBox(0, 'Текст сообщения', 'Заголовок', MB_OK);
Необходимость использования функций Windows API может быть вызвана, например, соображениями компактности исполняемого файла: использование диалогов Delphi автоматически подразумевает использование целого рада модулей, необходимых для оконного интерфейса. Если же в самой программе такие модули (например, forms) не задействуются, то их включение в исполняемый код только ради диалога не является хорошей идеей.
В то же время, обращение к функциям Windows API может быть вызвано, например, необходимостью перехвата непредусмотренных в Delphi сообщений.
ПРИМЕЧАНИЕ
Еще одной темой, важной для дальнейшего изучения программирования в Windows вообще и в среде Delphi в частности, является концепция событийного программирования. Дело в том, что хотя ОС Windows, в отличие от Delphi, и не является объектной средой, подход к организации взаимодействия приложений (как с пользователем, так и с системой), основан на одном и том же, а именно — на событиях.
Как мы уже знаем, для событий в VCL используются обработчики событий. Но важно знать, что каждое событие порождает сообщение. Таким образом, отслеживая поступающие сообщения и отсылая собственные, мы можем действовать в обход ограничений VCL.
Для отправки сообщений чаще всего используют функции SendMessage и PostMessage. Обе они выполняют отправку сообщения конкретному окну, разница заключается лишь в том, что SendMessage ожидает ответа от получившего сообщение обработчика, а PostMessage возвращает ответ немедленно. Ценность этих функций состоит в том, что в отличие от средств, предоставляемых VCL, они могут взаимодействовать не только в рамках одного приложения, но и между совершенно разными программами и даже устройствами.
Хотя детальное ознакомления с работой Windows API явно не вписывается в рамки данной книги (не забываем, что Delphi была создана как раз для того, чтобы скрыть сложную и неуклюжую API Windows), отметим все-таки некоторые связанные с ней аспекты. Прежде всего, это касается типов данных. Хотя ранние версии Windows были написаны на Pascal, со временем Microsoft перешла на использование C и C++, поэтому типы данных в представлении Windows несколько отличаются от таковых в Delphi. Прежде всего, это касается строк: при работе с Windows напрямую следует использовать не обычные, а C-строки. В Object Pascal для этого предусмотрен специальный тип данных — PChar, а так же функции для преобразования строк одного вида в другой. Так, для преобразования Pascal-строк в C-строки используют функцию StrPCopy, а для обратного преобразования — функцию StrPas.
var
a: PChar;
s: string;
...
s:='Строка';
new(a); // для С-строк следует предварительно выделять память
StrPCopy(a,s); // содержимое Pascal-строки s скопировано в C-строку a
s:=StrPas(a);
Другие типы данных, часто используемые при работе с API — целые числа, булевы значения и указатели. В таких случаях можно использовать стандартные для Object Pascal типы данных, а к нужному виду они, при необходимости, будут приводиться автоматически.
СОВЕТ
В поставку Delphi включена документация по Windows API. Ссылки на файлы вы найдете в разделе MS SDK Help Files, вложенном в раздел Help программной группы Delphi в меню кнопки пуск. Наибольший интерес с точки зрения изучения функций API представляет собой файл Win32 Programmer’s reference.
Что касается VCL, то в Delphi все же имеется специальный компонент, который может отлавливать все сообщения, адресуемые приложению. Для этого существует компонент AppEvents, который принимает все сообщения, адресованные объекту Application. Среди событий, отслеживаемых компонентом AppEvents, выделим OnMessage — именно это событие происходит, когда приложение получает сообщение от Windows или иной программы. Кроме того, ряд компонент, на самом деле, являются оболочкой для вызова тех или иных функций Windows. Впрочем, о компонентах Delphi будет рассказано в следующей части этой книги.
« Черчение, рисование и печать
|
Работа с VCL в среде Delphi »
Техподдержка / Связаться с нами
Copyright © 1999-2020 SNK. Все права защищены.
При использовании материалов с сайта ссылка на источник обязательна.
Допустим, сделана опечатка и неправильно написано какое-нибудь ключевое слово. В этом случае при попытке запуска программы внизу появляется окно, в котором отображены сообщения об ошибках. При этом программа не запустится. Благодаря подсказке такую ошибку легко найти и исправить.
Частой ошибкой начинающих является пропуск конструкции begin – end в цикле. При
этом имеется в виду, что в цикле должны выполняться, например, обе команды, но на самом-то деле в цикле, конечно, будет выполняться только первая, а вторая выполнится только один раз – потом, когда программа выйдет из цикла. При попытке запуска появляется сообщение. Но это не ошибка, а предупреждение. В нем обращается внимание на то, что параметр цикла после выполнения цикла может быть неопределенным (он присутствует во второй команде).
Однако, несмотря на предупреждение, программа может запуститься. Если вводятся
дкакие-либо данные, то появляется сообщение об исключительной ситуации – exception. При этом программа приостанавливается, переходя из режима исполнения в режим отладки. Чтобы перейти к обычному редактированию кода, лучше остановить программу. Это можно сделать с помощью команды Program Reset. Затем можно поправить ошибку и вновь запустить программу.
В большие программы всегда закрадываются ошибки. Их надо быстро и квалифицированно найти и исправить.
Механизм исключительных ситуаций (exception)
одно из больших достоинств Delphi. С их помощью вы можете контролировать
возникновение ошибок и создавать в результате устойчивые к ошибкам программы.
По мере знакомства с языком и средой программист проходит несколько этапов. На
первом этапе он, по незнанию, путает типы, забывает ставить знаки препинания (например, точку с запятой в конце строки), некорректно использует операторы и т.п. В результате написанный им код в принципе невозможно исполнить. И это хорошо – 15 поскольку допущенные им ошибки оказываются автоматически выявленными на этапе компиляции, более того, часто среда программирования сама подсказывает, какая ошибка допущена, и, что важно, указывает строку, которую нужно поправить. По мере изучения языка и борьбы с синтаксическими ошибками программист плавно переходит к следующему этапу. Теперь он уже не делает таких простейших ошибок, но, поскольку сложность его программ возрастает, возрастает и вероятность совершения им ошибки, при которой программа все равно запустится. Поскольку, с точки зрения компилятора, явной ошибки нет, а некоторые странности кода, по-видимому, являются замыслом программиста. Однако компилятор все-таки сообщает об этих странностях с помощью предупреждений (Warning).
Советуем всегда обращать на них внимание, проверять при их появлении, нет ли ошибки, и вообще стараться писать код так, чтобы не было предупреждений.
Опасность таких скрытых ошибок состоит:
1) в том, что они таятся в той части кода, которую программист написал и уверен, что
она правильная (программа запустилась), а значит, и не очень внимательно будет
искать ошибку;
2) в том, что проявляется эта ошибка совсем в другом месте кода – не в том, в котором
допущена. А это приводит к долгим поискам ее по всей программе.
При возникновении исключительной ситуации можно проигнорировать ее и запустить
исполнение программы дальше, нажав F9. В этом случае программа выдает сообщение об ошибке. Необходимо найти ошибку – понять, в какой строке и почему происходит сбой. Для этого можно воспользоваться трассировкой. Для того чтобы определить первую строчку, начиная с которой будет проводиться трассировка, нужно поставить Breakpoint – точку останова.
Когда исполняемый код доходит до точки останова, исполнение программы
приостанавливается, и надо перейти в режим отладки. В режиме отладки можно исполнять последовательно программу по шагам, контролировать и изменять значения переменных и т.п. Этот режим служит для обнаружения и ликвидации ошибок. В этом случае появляется возможность просмотреть или изменить текущие значения переменных, однако изменение кода во время отладки невозможно. Измененный текст заработает только после перезапуска программы.
Чтобы выполнить текущую строку, на которой стоит курсор отладки, нажмите F7 или
F8. Строка выполнилась, и курсор сместился. Если необходимо перейти к следующей строке, то можно нажать F8, если нужно зайти в какую-либо функцию, то нажимают клавишу F7 и продолжают трассировку.
Для того чтобы в ходе отладки узнать значение той или иной переменной, нужно просто подвести к ней курсор. Появится hint со значением этой переменной. Это, однако, работает не со всеми переменными, а только с доступными в данный момент. Если нужно постоянно контролировать значение переменной, то еще проще добавить ее в список Watch.
Для более основательного слежения за значениями можете воспользоваться Списком Наблюдения (Watch List, Ctrl+F5).
Таким образом, при программировании среда Delphi может находиться в различных
режимах:
• Режим редактирования – режим, в котором редактируется код проекта,
модифицируется форма, добавляя на нее компоненты и настраивая их свойства. Это
основной режим.
• Режим исполнения программы – режим, в который среда переходит, как только
нажата клавиша F9 и был построен exe-файл. Фактически, в этом режиме происходиткак раз исполнение получившегося exe-файла проекта. Программа исполняется так,
как если бы ее вызвали не из Delphi, а просто из Windows.
• Режим отладки – в этот режим можно перейти из режима исполнения программы.
При этом программа будет приостановлена (но не остановлена совсем).
Чтобы продолжить трассировку (последовательный переход от команды к команде),
можете воспользоваться клавишами:
• F9 (Run) – продолжить программу, не трассируя ее.
• F8 (Step over) – выполняется текущая строка кода, и переходят к следующей строке.
• F7 (Trace Into) – то же, что и F8, с тем отличием, что если в текущей строчке
содержится вызов какой-либо функции или процедуры, то попадают внутрь этой
процедуры и трассируют ее до конца, затем из нее возвращаетс и переходят к
следующей строке (на которую перешли бы сразу, если бы нажали F8).
• F4 (Run to Cursor) – переход в режим исполнения программы до тех пор, пока не
должна будет выполнена строка, на которой стоит текстовый курсор (аналогично
тому, как если бы была установлена точка останова)
• Shift+F8 (Run Until Return) – процедура выполняется до конца.
• Ctrl+F2 (Program Reset) – остановка трассировки и переход в режим редактирования
кода. (Иногда целесообразнее, если это не грозит ошибками, продолжить исполнение
программы (F9) и выйти из нее нормальным образом, закрыв главную форму).
При работе в Delphi сообщение об ошибке фактически появляется дважды: сначала
выводится окно об исключительной ситуации и программа приостанавливается, а потом,
если нажать F9 (F8, F7 и т.п.), – возникает стандартное сообщение об ошибке Windows.
Итак:
1. Произошла ошибка.
2. Программа приостанавливается.
3. Выводится сообщение об exception. Это сообщение для программиста. Среда Delphi
сообщает, что программа не в состоянии выполнить какую-то свою команду.
Программист не предусмотрел возможность исключительной ситуации. Среда Delphi
приостанавливает программу, чтобы программист разобрался, где и в чем ошибка.
Отключить приостановку (2)–(3) можно, сняв флажок Menu => Tools => Debugger
Options => Language Exceptions => Stop on Delphi Exceptions.
4. Нажатие клавиши F9 (F8, F7 или др.).
5. Выводится сообщение об ошибке. Это сообщение для пользователя программы
(ситуация запуска приложения не из Delphi, а через exe-файл из Windows, т.е. не
существовует пунктов 2, 3, 4).
6. Программа продолжается (при этом она не сумела выполнить ту часть, в которой
произошла ошибка, и значит, если эта часть важная, продолжение может
сопровождаться дальнейшими ошибками).
Механизм обработки исключительных ситуаций заключается в том, что если
произошла ошибка (1) и не надо выводить (5), предпринимаются действия, чтобы (6) исполнялось корректно.
Для этого «опасная» команда (или целый блок) помещается внутрь конструкции try..except..end или try..finally..end.
Блок try..finally..end используется аналогично try..except.., но с тем отличием, что блок
команд между finally и end выполняется в любом случае, вне зависимости от того, было исключение между try и finally или нет.