Access Violation
Нарушение доступа — это ночной кошмар программистов, ужас, летящий на крыльях ночи... Весь ужас в том, что очень часто это — мина с часовым механизмом, внезапно взрывающаяся после сотен, а то и тысяч строк пройденного кода.
В действительности access violation — всего лишь простая ошибка, означающая, что ваше приложение "получило по рукам" от операционной системы за попытку влезть в область памяти, ему не принадлежащей. Когда вы получаете сообщение об этом (рис. 2.28), вам рассказывают, кто (первое число) и куда (второе число) пытался залезть. Первое число предоставляет адрес инструкции, попытавшейся нарушить границы, а второе указывает, куда именно хотела обратиться инструкция-нарушительница.
Вернитесь в среду, выберите команду Search/Find Error, введите адрес ошибки (первое число в сообщении) в поле ввода диалогового окна, щелкните на кнопке ОК и читайте подходящую молитву. Если вам повезет, в окне появится строка, вызвавшая ошибку. Гораздо чаще этого не происходит, так как ошибка оказывается где-то в VCL или библиотеке, скомпилированной без отладочной информации, и вызывает ее передача неверного параметра в функцию, при отработке которого и происходит ошибка доступа.
Даже скомпилировав VCL с отладочной информацией, вы, скорее всего, сможете получить только имя функции, вызвавшей ошибку, и вам все равно придется потратить немало времени на поиски ошибки где-то совсем в другом месте.
Active
Это свойство возвращает значение True, если в приложении в текущий момент содержится фокус ввода. Если Active приложения имеет значение True, то и свойство Active для одной из форм также равно True. Обычно оно используется для определения, имеет ли приложение фокус ввода, перед выводом строки состояния или прорисовкой объекта TCanvas.
Совет: Даже будучи неактивным, приложение продолжает получать сообщения о перемещении мыши.
Свойство Active определяет, имеет ли форма фокус ввода. Если имеет, оно возвращает True, если нет False. Windows выводит заголовок активной формы цветом, отличающимся от цвета неактивных.
Совет: Неактивные окна продолжают получать сообщения о перемещении и выборе мыши.
Независимо от типа приложения в один момент времени может быть активной только одна форма. Вы можете обратить внимание на то, что заголовок родительской формы в MDI-приложении изображен "активным" цветом. Не попадитесь на эту удочку — свойство Active родительского MDI-окна, никогда не бывает равным True.
Совет: Свойство ActiveForm класса TScreen, возвращает форму, которая в данный момент имеет фокус ввода.
ActiveControl
Это свойство возвращает объект TWinControl, имеющий фокус ввода. Обычно оно используется для реализации команд Copy, Cut и Paste для текстовых управляющих элементов. Следующий код, помещенный в обработчик TMenuItem, выполняет функцию Copy.
procedure TFormI.mnuEditCopyClick(Sender: TObject);
begin
Screen.ActiveControl.Perform(WM_COPY,0,0);
end;
Все, что происходит в мире Windows, базируется на сообщениях. Для выполнения какой-либо функции управляющие элементы часто отсылают сообщения самим себе. Так и в этом примере управление происходит путем передачи сообщения WM_COPY.
Свойство ActiveControl указывает на потомка TWinControl, имеющего в настоящий момент фокус ввода. Вы можете установить значение во время создания программы, определив, какой элемент будет иметь фокус ввода при инициализации формы. Назначение ActiveControl во время работы программы— установка фокуса ввода в поле с некорректно введенными данными. Приведенный ниже фрагмент кода позволяет проверить текст, введенный в элемент editCustName, перед закрытием формы.
procedure TDataEntryForm.FormCloseQuery(Sender: Tobject;
var CanClose: Boolean);
begin
{Проверяем, введен ли текст в элемент.}
if edtCustName.Text = ' ' then
begin
{Запрещаем закрытие.}
CanClose:= False;
(Устанавливаем фокус в поле с некорректными данными.)
ActiveControl:= editCustName;
end;
end;
Совет: Метод SetFocus потомков TWinControl устанавливает фокус ввода и обновляет свойство ActiveControl. Большинство событий передает параметр Sender своему обработчику. Sender определяет, какой элемент обнаружил событие и запустил обработчика.
ActiveForm
Это свойство возвращает объект TForm, имеющий фокус ввода. Если приложение неактивно, свойство указывает, какая именно форма будет иметь фокус ввода при активизации приложения. В качестве примера используем свойство для создания мигающего заголовка формы, чтобы привлечь внимание пользователя. Функция Windows API, предназначенная для этой цели, должна получить дескриптор окна:
FlashWindow(Screen.Active Form.Handle,False);
ActiveMDIChild
Это свойство возвращает дочерний объект TForm, имеющий в текущее время фокус ввода. Оно полезно, когда родительская форма содержит панель инструментов или меню, команды которых распространяются на открытую дочернюю форму.
Например, представим, что проект использует дочернюю форму, содержащую элемент TMemo, названный memDailyNotes. Имя класса этой дочерней формы— TfrmMDIChild. Родительская форма содержит кнопку Clear в панели инструментов, которая удаляет содержимое memDailyNotes в активной дочерней форме. Вот как это реализуется.
procedure TfrmMDIParent.spbtnClearClick(Sender: TObject);
begin
if not (ActiveMDIChild = Nil) then
if ActiveMDIChild is TfrmMDIChild then
TfrmMDIChild(ActiveMDIChild).memDailyNotes.Clear;
end;
В первой строке проверяется, равен ли ActiveMDIChild значению Nil, так как в этом случае обращение к объекту вызовет исключительную ситуацию.
Совет: ActiveMDIChild равен Nil, если нет открытых дочерних форм или свойство FormStyle не равно fsMDIForm.
Поскольку ActiveMDIChild возвращает объект TForm, компилятор не имеет доступа к memDailyNotes — объекту TfrmMDIChild. Вторая строка проверят соответствие типов, т.е. действительно ли ActiveMDIChild указывает на объект TfrmMDIChild.
Третья строка выполняет преобразование типа и вызывает метод Clear компонента memDailyNotes.
Активизирование существующей копии
Все-таки, сказать пользователю "Ты уже запустил одну копию, теперь иди и ищи ее!"— как-то негуманно... Более профессиональным решением будет активизировать существующую копию с помощью другой функции Windows API — SetForegroundWindow. Измените проект следующим образом.
var
hwndPrev: HWND;
begin
Application.Initialize;
hwndPrev:= FindWindow('TFormi','Formi');
if hwndPrev < 0 then
begin
SetForegroundWindow(hwndPrev);
Application.Terminate;
end;
Application.CreateForm(TFormi,Formi);
Application.Run;
end.
Application
Поле Title определяет название вашего приложения, выводимого в панели задач (например, Delphi устанавливает его по имени текущего проекта). Если вы не введете названия, будет использоваться название, установленное по умолчанию (DELPHI32).
Поле Help file определяет файл справки, подключаемый к вашему приложению, что позволяет использовать систему контекстной справки.
Кнопка Load Icon позволяет установить пиктограмму приложения, используемую как пиктограмму по умолчанию в ярлыках и панели задач.
С помощью последней опции. Target file extension, можно переопределить стандартное расширение создаваемого файла (DLL — для динамически линкуемых библиотек, ОСХ — для элементов ActiveX и т.п.). Однако это расширение можно не устанавливать, так как Delphi весьма корректно работает по умолчанию.
AutoScroll, HorzScrollBar и VertScrollBar
Свойство AutoScroll
управляет появлением полос прокрутки в форме, размеры которой не позволяют вывести все ее элементы одновременно. Если свойство равно True,
и вы изменили размеры так, что не все элементы формы видны, в форме автоматически появляются полосы прокрутки. Если же значение свойства— False, вы теряете доступ к элементам формы, не поместившимся на экране.
Совет: Компонент TScrollBar, позволяет прокручивать форму независимо от свойства AutoScroll.
Вы можете управлять полосами прокрутки с помощью свойств HorzScrollBar и VertScrollBar. Это весьма полезно в программах, реализующих свойство распахивания окна. Поскольку размеры выводимой диаграммы могут быть больше размеров формы, а выводите вы ее самостоятельно, AutoScroll не активизируется, и вам следует обеспечить прокрутку и рисование, самому. Вот пример такого кода, обеспечивающего прокрутку в двойном размере формы.
{Устанавливаем диапазон вертикальной прокрутки.}
VetrScrollBar.Range:= Height * 2;
{Показываем вертикальную полосу прокрутки.}
VertScrollBar.Visible:= True;
{Устанавливаем диапазон горизонтальной прокрутки.}
HorzScrollBar.Range:= Width * 2;
{Показываем горизонтальную полосу прокрутки.}
HorzScrollBar.Visible:= True;
Автоматическое создание форм
По умолчанию при запуске приложения Delphi автоматически создает по одному экземпляру каждого класса форм в проекте и освобождает их при завершении программы. Автоматическое создание обрабатывается генерируемым Delphi кодом в трех местах.
Первое — раздел интерфейса в файле модуля формы.
type
TForm1 = class (TForm)
private
{Закрытые объявления.}
public
{Открытые объявления.}
end;
В данном фрагменте кода объявляется класс TForm1.
Вторым является место, в котором описывается переменная класса.
var Form1: TForm1;
Здесь описана переменная Form1, указывающая на экземпляр класса TForm1 и доступная из любого модуля. Обычно она используется во время работы программы для управления формой.
Третье место находится в исходном тексте проекта, доступ к которому можно получить с помощью меню View/ Project Source. Этот код выглядит как:
Application.CreateForm(TForm1, Form1);
Процесс удаления форм обрабатывается с помощью концепции владельцев объектов: когда объект уничтожается, автоматически уничтожаются все объекты, которыми он владеет. Созданная описанным образом форма принадлежит объекту Application и уничтожается при закрытии приложения.
BorderIcons
Свойство Borderlcons представляет собой набор логических значений, использующийся для определения набора пиктограмм в заголовке формы.
Значения biMinimize и biMaximize создают пиктограммы, которые позволяют свернуть и развернуть форму с помощью мыши.
Совет: Для того чтобы значения biMinimize и biMaximize работали, необходимо установить свойство BorderStyle равным bsSizeable или bsSizeToolWin.
Значение biHelp выводит кнопку с вопросительным знаком. Щелчок на ней вызывает контекстно-зависимую справку, которая выводится, как текст подсказки Hint, т.е. без вызова Windows Help. На рис. 1.1 представлена такая кнопка.
![](image/bordericons_1.jpg)
Рис. 1.1. Доступ к контекстно-зависимой справке можно получить с помощью щелчка на кнопке с вопросительным знаком в заголовке формы.
Значение biSystemMenu создает слева от заголовка пиктограмму, позволяющую вызывать системное меню, как показано на рис. 1.2.
![](image/ris1-2.jpg)
Рис. 1.2. Системное меню позволяет перемещать и закрывать форму, а также изменять ее размеры.
Совет: Для того чтобы значения biMinimize, biMaximize и biHelp работали, необходимо присвоить свойству заметку BorderIcons значение biSystemMenu.
BorderStyle
Свойство BorderStyle перечислимого типа позволяет определить:
вид заголовка формы
доступные кнопки в заголовке формы
отображение строки меню
поведение границ формы
На рис. 1.3 показана форма для шести значений BorderStyle. Каждая форма создавалась как форма размером 200х200 пикселей.
![]() |
![]() |
![]() | |||
![]() |
![]() |
![]() |
Рис. 1.3. Влияние значения BorderStyle на вид формы. Значения по часовой стрелке, начиная с левой верхней формы, таковы: bsSizeable, bsDialog, bsSingle, bsSizeToolWin,bsToolWindow и bsNone
По умолчанию свойство BorderStyle имеет значение bsSizeable, создающее обычное окно с изменяемыми размерами. Такое окно имеет стандартную строку заголовка и не имеет ограничений на расположение в ней кнопок. Примеры таких окон — программы Explorer и Notepad.
Значение bsDialog создает диалоговое окно, которое используется, когда программа требует от вас ответа для продолжения выполнения программы или для вывода информации, 16-разрядные версии Windows выводили такое окно как окно с широкой границей того же цвета, что и заголовок. Сейчас, если вы будете следовать новому трехмерному интерфейсу, границы окна будут выглядеть так же, как границы обычного окна! Видимое различие между стандартными и диалоговыми окнами в связи с тем, что последнее не может изменять размеры, состоит лишь в том, что указатель мыши не изменяется при пересечении рамки окна.
Совет: Значения biMinimize и biMaximize свойства Borderlcons не будут работать, если свойство BorderStyle установлено равным bsDialog.
Третий по популярности стиль окон — bsSingle, создающий форму, которая не может изменять размеры во время работы. В отличие от bsDialog, bsSingle не запрещает установку любых пиктограмм. Единственное ограничение состоит в том, что кнопка сворачивания окна, будучи выведенной, является недоступной (блокированной). Пример такой программы — Calculator. На рис. 1.4 вы видите другой пример окна bsSingle.
![](image/ris1-4.jpg)
Рис. 1.4. Стиль bsSingle полезен, когда пользователю не надо изменять размер окна.
Панель инструментов (Toolbar) позволяет быстро получить доступ к сгруппированным функциям. В Delphi можно сконструировать панель инструментов, поместив группу компонентов TSpeedButton в форму, имеющую стиль bsSizeToolWin или bsToolWindow. Окно в стиле bsSizeToolWin может изменять размеры и не имеет кнопок biMinimize, biMaximize HbiHelp. Окно в стиле bsToolWindow действует так же, но не позволяет изменять размеры.
Стиль bsNone создает окно без рамки и заголовка. Такое окно не рекомендуется использовать в качестве стандартного или диалогового, однако оно может быть полезным в программах сохранения экрана или заставках.
Совет: Если вы выбрали для свойства BorderStyle значение, создающее окно с разрешенным изменением размеров, Delphi автоматически установит значение AutoScroll равным True. Формы со стилями bsDialog и bsNone не могут иметь строки меню.
Булевы типы
На ранней стадии обучения программисты осваивают понятие бита, два состояния которого можно использовать для записи информации о чем-либо, представляющем собой одно из двух. Бит может обозначать 0 или 1, ДА или НЕТ, ВКЛЮЧЕНО или ВЫКЛЮЧЕНО, ВЕРХ или НИЗ, СТОЯТЬ или ИДТИ. В Object Pascal информация о чем-либо, что можно представить как ИСТИНА (True) или ЛОЖЬ (False), хранится в переменных булевых типов. Всего таких типов че-тыре, и они представлены в табл. 1.4.
Таблица 1.4. Размеры переменных булевых типов
Тип | Размер |
Boolean | 1 байт |
ByteBool | 1 байт |
WordBool | 2 байт (объем Word) |
LongBool | 4 байт (объем Longint) |
По аналогии с целыми и символьными типами, подразделяющимися на физические и логические, естественно предположить, что ByteBool, WordBool и LongBool — физические типы, Boolean — логический. Но в данном случае это не совсем так. Все четыре типа различны. Для Object Pascal предпочтителен тип Boolean, остальные определены для совместимости с другими языками программирования и операционными системами.
Переменным типа Boolean можно присваивать только значения True (истина) и False (ложь). Переменные ByteBool, WordBool и LongBool могут принимать и другие порядковые значения, интерпретируемые обычно как False в случае нуля и True — при любом ненулевом значении.
Совет: Булевы типы в Delphi можно сравнить с типом LOGICAL языка FORTRAN. В Basic, С и C++ булевы типы как таковые отсутствуют. Булевы выражения в этих языках применяются точно так же, как во всех остальных, однако результаты этих выражений интерпретируются не как значения отдельного типа, а как целые числа. Как в Basic, так и в C/C++ булевы выражения дают численные результаты, интерпретируемые как False в случае 0 и True — в случае любого ненулевого значения. Это совместимо с порядковыми значениями булевых выражений в Delphi. В C/C++ простые сравнения дают результат 1 (True) или 0 (False). Это эквивалентно булевым значениям Delphi. Только результат сравнения в Delphi выводится как булевый, а не целый. В большинстве случаев типу Boolean из Delphi соответствует тип char в C/C++. В Basic зарезервированы слова TRUE (эквивалентно константе -1) и FALSE (эквивалентно константе 0). В Basic TRUE меньше FALSE, в Delphi, наоборот, False меньше True.
Целые типы
В переменных целых типов информация представляется в виде целых чисел, т.е. чисел не имеющих дробной части. Определенные в Object Pascal целые типы подразделяются на физические (фундаментальные) и логические (общие). При программировании удобнее использовать логические целые типы, которые задают объем переменных в зависимости от типа микропроцессора и операционной среды таким образом, чтобы достигалась максимальная эффективность. Физические целые типы следует применять лишь в тех случаях, когда в первую очередь важны именно диапазон значений и физический объем переменной. В Object Pascal определены следующие целые типы.
Integer
Shortint
Smallint
Longint
Byte
Word
Cardinal
Обратите внимание, что один из этих целых типов назван именно целым (integer). Это может иногда приводить к путанице, но мы легко сможем ее избежать, применяя термин целый к. группе типов, a integer — к конкретному типу, определяемому в программе этим ключевым словом. Переменные физических целых типов имеют разные диапазоны значений в зависимости от того, сколько байтов памяти они занимают (что равно значению, возвращаемому функцией SizeOf для данного типа). Диапазоны значений для всех физических типов перечислены в табл. 1.2.
Таблица 1.2. Физические целые типы
Тип | Диапазон значении | Физический формат |
Shortint | -128-127 | 8 бит, со знаком |
Smallint | -32 768-32 767 | 16 бит, со знаком |
Longint | -2 147 483 648-2 147 483 647 | 32 бит, со знаком |
Byte | 0-255 | 8 бит, без знака |
Word | 0-65 535 | 16 бит, без знака |
Диапазоны значений и форматы физических целых типов не зависят от микропроцессора и операционной системы, в которых выполняется программа. Они не меняются (или, по крайней мере, не должны меняться) с изменением реализации или версии Object Pascal.
Диапазоны значений логических целых типов (Integer и Cardinal) определяются совершенно иным образом. Как видно из табл. 1.3, они никак не связаны с диапазонами соответствующих физических типов. Обратите внимание, что в Delphi по умолчанию задано 32-разрядное представление.
Таблица 1.3. Логические целые типы
Тип | Диапазон значений | Физический формат |
Integer | -32 768-32 767 | 16 бит, со знаком (SmalIInt) |
Integer | -2 147 483 648-2 147 483 647 | 32 бит, со знаком (Longint) |
Cardinal | 0-65 535 | 16 бит, без знака (Word) |
Cardinal | 0-2 147483647 | 32 бит, без знака (Longint) |
Совет: В С и C++ для целых значений определены типы int, short int (или просто short) и long int (или просто long). Тип int из C/C++ соответствует типу Integer из Delphi, a long из C/C++ — Longint из Delphi. Однако Shortint из C/C++ соответствует в Delphi не Shortint, a Smalltlnt. Эквивалент Shortint из Delphi в C/C++— это signed char. Тип unsigned char в C/C++ соответствует типу Byte из Delphi. В C/C++ существует еще тип unsigned long, аналога которому в Delphi нет.
Над целыми данными выполняются все операции, определенные для порядковых типов, но с ними все же удобнее работать как с числами, а не с "нечисленными порядковыми типами". Как и "живые" числа, данные целых типов можно складывать (+), вычитать (-) и умножать (*). Однако некоторые операции и функции, применяемые к данным целых типов, имеют несколько иной смысл.
Операция | Результат |
Abs (X) | Возвращает абсолютное целое значение Х |
Х Div Y | Возвращает целую часть частного деления Х на Y |
Х Mod Y | Возвращает остаток частного деления Х на Y |
Odd (X) | Возвращает булево True (истина), если Х — нечетное целое, и False (ложь) — в противном случае |
Sqr (X) | Возвращает целый квадрат Х (т.е. Х*Х) |
ClientHeight и C
lientWidth
Окно состоит из двух частей — клиентской и не клиентской. Обычно приложение выводит изображения только в клиентской области, размер которой возвращается через свойства ClientHeight и ClientWidth. Обычно эти свойства используются для того, чтобы убедиться, что в форме может выводиться весь объект определенного размера. Показанный ниже текст приводит размер клиентской области формы в соответствие размерам изображения, содержащегося в компоненте TImage, ImgPicture.
with imgPicture.Picture do
begin
(Изменение размера.)
ClientWidth:= Width;
ClientHeight:= Height;
end;
Не клиентская область обычно прорисовывается Windows и включает строку заголовка, меню и рамку окна. Вы можете рисовать в этой части окна, перехватив сообщение WM_NCPAINT.
Compiler
Вкладка компилятора содержит огромное количество переключателей, позволяющих устанавливать опции компилятора. Две особенно полезные опции. Show hints и Show warnings, помогут вам при отладке (при этом компилятор будет выдавать множество предупреждений, например об использовании неинициализированной переменной).
Cursor
Это свойство определяет форму указателя мыши для всего приложения. Обычно оно используется для отображения песочных часов, чтобы в то время, пока пользователь думает о сложной работе, выполняемой приложением, немного передохнуть.
{Придать курсору форму песочных часов.}
Screen.Cursor:= crHourglass;
try
{Попытаемся ничего не делать какое-то время.}
for iCount:=1 to 1000000000 do;
finally
{Восстановим форму указателя.}
Screen.Cursor:= crDefault;
end;
Форму указателя можно изменить для каждого потомка TControl (включая ТForm) отдельно.
Data_type
Типы данных
С помощью типов данных программист указывает компилятору, как хранить информацию в программе. При объявлении переменной необходимо указать ее тип. Одни типы уже определены в языке, другие программисту приходится задавать самому. В ранних языках программирования допускалось ограниченное число типов данных, и Pascal оказался одним из первых языков, допускающих определение в программе новых типов.
Типы данных, определяемые пользователем, обычно задаются в разделе определения типов программы или модуля (unit), однако это можно делать и внутри процедур или функции. Объявления типов действуют в пределах того блока, в котором они размещены. Вне этого блока ссылаться на такие типы нельзя. Внутри же они заменяют все внешние типы с тем же именем. Объявленные типы данных можно применять в любом месте области их видимости; запрещена только ссылка определяемого типа на самого себя (тут, однако, есть одно исключение, касающееся указателей).
Объявления типов в Pascal являются для компилятора чем-то вроде схем, которые он должен запомнить на случай, если вдруг встретит в программе ссылки на тот или иной тип. Само по себе объявление типа не вносит в программу никаких изменений.
Что же касается объявлений var, то они задают компилятору некоторые действия, связанные с ранее объявленными типами. Тип переменной ограничивает как ее значения, так и операции, которые можно выполнять с этими значениями.
Определения типов и переменных могут размещаться в нескольких местах компонентов программы. Выглядят же они следующим образом.
type
typel = type definitioni; //Новые типы данных определяются в разделе "type". Каждому новому
// типу присваивается имя, затем он определяется через уже
//существующие типы.
type2 = type__definition2; // В одном разделе "type" можно объявить несколько типов.
//Самое простое определение типа состоит из имени типа,
type3 = typel; // определенного ранее.
// Новые переменные объявляются в
var // разделе "var". Каждой новой
var1: type definitions; // переменной сначала присваивается имя, а затем — тип (на основе
// ранее определенных типов).
var2, var3: type definition4; // В одном разделе "var" можно объявить несколько переменных.
// Нескольким переменным можно присваивать один и тот же тип.
var4 : typel; // Программу легче читать, если переменным присвоены
//существующие типы.
Синтаксис Object Pascal позволяет одновременно конструировать исключительно сложные типы и определение переменных. Однако определение типов в разделах type тех или иных блоков дает возможность использовать эти типы в разных частях программы. Новые типы определяются из типов следующих категории.
Простые типы для хранения информации в форме чисел и других "упорядоченных" значении.
Строковые типы для хранения последовательностей символов.
Структурные типы для одновременного хранения информации разных типов.
Указательные типы для косвенного обращения к переменным заданных типов.
Процедурные типы для обращения к процедурам и функциям, рассматриваемым как переменные.
Вариантные типы для хранения в одной переменной данных различных типов.
Обычно идентификаторы типов используются только при определении новых типов или объявлении переменных. Есть, однако, несколько функций, в которых имя типа может использоваться как часть выполняемого оператора. Например, функция SizeOf (Т) возвращает количество байтов, занимаемых переменной Т.
Функция SizeOf очень важна для написания эффективных программ. Многие из определенных в Object Pascal типов имеют очень сложную структуру и могут занимать в памяти довольно много места. При этом элементы таких типов созданы скорее для представления значений в некотором логическом порядке, а не для того, чтобы занимать место в памяти. Функция SizeOf избавляет программиста от необходимости вычислять объем данных в подобных случаях.
Действительные типы
В переменных действительных типов содержатся числа, состоящие из целой и дробной частей. В Object Pascal определено шесть действительных типов. Все типы могут представлять число 0, однако они различаются пороговым (минимальным положительным) и максимальным значениями, которые могут представлять, а также точностью (количеством значащих цифр) и объемом. Действительные типы описываются в табл. 1.5.
Таблица 1.5. Действительные типы.
Тип | Порог | Максимальное значение | Количество значащих цифр | Объем (байт) |
Real | 2.9E-39 | 1.7Е38 | 11-12 | 6 |
Single | 1.5E-45 | 3.4Е38 | 7-8 | 4 |
Double | 5.0E-324 | 1.7Е308 | 15-16 | 8 |
Extended | 3.4E-4932 | 1.IE4932 | 19-20 | 10 |
Comp | 1.0 | 9.2Е18 | 19-20 | 8 |
Currency | 0.0001 | 9.2Е14 | 19-20 | 8 |
Совет: Тип Real предназначен для совместимости с ранними версиями Delphi и Borland Pascal. Формат этого типа неудобен для семейства процессоров Intel, поэтому операции с типом Real выполняются несколько медленнее операций над остальными действительными типами.
Целые типы представляют целые числа, т.е. числа, дробная часть которых равна нулю. Разница между двумя неодинаковыми целыми числами не может быть меньше единицы. Именно благодаря этому целые числа применяются для обозначения дискретных величин, независимо от того, имеют ли реальные объекты какое-либо отношение к числам. Действительные типы предназначены для представления чисел, которые могут иметь дробную часть, поэтому они полезны для представления величин, которые могут быть довольно близкими, почти непрерывными.
Заметьте, именно почти. Несмотря на название действительные, переменные этих типов отличаются от математических действительных чисел. В Object Pascal действительный тип — это подмножество математических действительных чисел, которые можно представить в формате с плавающей запятой и фиксированным числом цифр. Для невнимательных программистов ситуация усугубляется тем, что в стандартных форматах IEEE (Institute of Electrical and Electronic Engi-neers — Институт инженеров- электриков и электронщиков), применяемых в программах Delphi и вообще в большинстве программ для Windows, возможно точное представление только чисел с фиксированным числом бит в дробной части. Удивительно, но такое простое число, как 0,1, записывается в расширенном формате IEEE с некоторой погрешностью, пусть очень небольшой. Из-за этого представление с плавающей запятой оказывается несколько неудобным для программ, в которых сохраняется и выводится фиксированное число десятичных разрядов численных значений. Это относится и к программам, работающим с ''живыми" деньгами.
Для частичного решения этой проблемы в Object Pascal определены два формата с фиксированной запятой. Тип Comp (computational — вычислительный) содержит только целые числа в диапазоне от -263+1 до 263-1, что примерно соответствует диапазону от —9,2х1018
до 9,2х1018. При программировании операций с американской валютой разработчикам обычно приходится искать естественный способ записи денежных сумм, в котором целая часть числа определяет количество долларов, дробная — центов. Если такие значения записывать в переменные типа Comp, придется представлять их в виде целого числа центов. В этом случае следует умножать значение на 100 для обращения центов в доллары, а затем делить на 100, чтобы снова получить центы.
Этих забот можно избежать, если воспользоваться типом Currency. В этом случае задачу выбора масштаба возьмет на себя компилятор. Физически значения Currency записываются в память того же объема, что и Comp, как целые числа, однако компилятор не забывает вовремя разделить значение на 10 000 (не на 100!) для его приведения в соответствие с денежным знаком и умножить на 10 000 перед записью в память. Это обеспечивает абсолютную точность в четыре десятичных знака после запятой.
В Delphi есть модуль System, содержащий ряд процедур обработки данных действительных типов. Наиболее распространенные из них перечислены в табл. 1.6. Много полезных процедур содержится также в модулях SysUtils и Math.
Таблица 1.6. Функции действительных типов
Функция | Возвращаемое значение |
Abs (x) | Абсолютная величина х |
АгсТаn(х) | Арктангенс х |
Cos (х) | Косинус х (х выражается в радианах, а не в градусах) |
Ехр (х) | Экспоненциальная функция от х |
Frac(x) | Дробная часть х |
Int (х) | Целая часть х. Несмотря на название, возвращает действительное значение (с плавающей запятой), т.е. просто устанавливает нуль в дробной части |
Ln (х) | Натуральный логарифм от х |
Pi | Число Пи (3.1416...) |
Round (х) | Ближайшее к х целое значение. Возвращает значение целого типа. Условие "ближайшее к х" не работает, если верхнее и нижнее значения оказываются равноудаленными (например, ес-ли дробная часть точно равна 0,5). В этих случаях Delphi перекладывает решение на опера-ционную систему. Обычно процессоры Intel решают эту задачу в соответствии с рекоменда-цией IEEE округлять в сторону ближайшего четного целого числа. Иногда такой подход на-зывают "банкирским округлением" |
Sin(x) | Синус х |
Sqr(x) | Квадрат х, т.е. X*X |
Sqrt (х) | Квадратный корень от х |
Тrunc (х) | Целая часть х. В отличие от Int, возвращающей действительное значение, Trunc возвращает целое |
Диалоговое окно Evaluate/Modify
Для вывода диалогового окна Evaluate/Modify выберите команду Run/Evaluate/Modify (рис 2.14). Другой способ вызова диалогового окна — установить курсор в окне редактирования на необходимой вам переменной, щелкнуть правой кнопкой мыши и в контекстном меню выбрать команду Evaluate/Modify.
Введите выражение в поле Expression так же, как в диалоговом окне Watch Properties (см рис 2.12). Затем щелкните на кнопке Evaluate для того, чтобы увидеть результат в поле Result. Если выражение состоит только из имени простой переменной (не массива или структуры!), можете ввести новое значение для переменной в поле New Value и, щелкнув на кнопке Modify, присвоить переменной новое значение. Это позволяет корректировать значения переменных в процессе отладки, не останавливаясь и не перекомпилируя всю программу, что сбережет ваше время и нервы, и даст возможность, найдя одну ошибку, искать другие, а исправлением первой ошибки заняться чуть позже.
![](image/ris2-14.jpg)
Рис 2.14 Использование диалогового окна Evaluate/Modify для проверки изменения отдельной переменной.
Диалоговое окно Evaluate/Modify — немодальное, т. е. вы можете не закрывать его, продолжая отладку. Однако учтите, что в отличие от окна Watch List диалоговое окно Evaluate/Modify не отслеживает изменения значений переменных и для получения информации о текущем состоянии переменной вам необходимо воспользоваться кнопкой Evaluate.
Так же, как и окно Watch List, диалоговое окно Evaluate/Modify может выводить сообщения об ошибках, если отладчик не в состоянии вывести информацию о переменных. И точно так же не выводится информация о выражениях, содержащих вызов функций.
Как видите, окно Watch List и диалоговое окно Evaluate/Modify очень похожи, но каждое из них имеет свои преимущества в различных ситуациях. Обратите внимание на одно существенное отличие диалогового окна Evaluate/Modify его вывод выполняется в поле с несколькими строками, а потому оно более удобно для просмотра структур и объектов.
Динамическое создание форм
Хотя автоматическое создание форм полезно при разработке SDI-приложений, при создании MDI-приложении оно, как правило, неприемлемо.
Для создания нового экземпляра формы используйте конструктор Create класса формы. Приведенный ниже код создает новый экземпляр TForm1 во время работы программы и устанавливает его свойство Caption равным 'New Form'.
Form1:= TForm1.Create(Application);
Form1.Caption:= 'New Form';
Конструктор Create получает от вас в качестве параметра потомка TComponent, который и будет владельцем вашей формы. Обычно в качестве владельца выступает Application, чтобы все формы были автоматически закрыты по окончании работы приложения. Вы можете также передать параметр Nil, создав форму без владельца (или владеющую собой — как вам больше нравится), но тогда закрывать и уничтожать ее придется вам. В случае возникновения необрабатываемой ошибки такая форма останется в памяти, что не говорит о высоком профессионализме программиста...
В приведенном ниже коде Form1 указывает только на последнюю созданную форму. Если вам это не нравится, воспользуйтесь приведенным ниже кодом — возможно, он более точно отвечает вашим запросам:
with TFormI.Create(Application) do
Caption:= 'New Form';
Совет: При разработке MDI-приложения метод Show не нужен, так как Delphi автоматически показывает все вновь созданные дочерние MDI-формы. В случае SDI-приложения вы обязаны использовать метод Show.
Даже при динамическом создании форм Delphi попытается навязать вам свои услуги по созданию экземпляра каждой формы. Чтобы отказаться от них, воспользуйтесь диалоговым окном Project Options, изображенным на рис. 1.14, и удалите классы форм из списка Auto-create forms.
![](image/ris1-18.jpg)
Рис. 1.14. Диалоговое окно Project Options позволяет установить опции для текущего проекта
Если вы захотите получить доступ к отдельному дочернему экземпляру класса, используйте свойство MDIChildren, описываемое в следующем разделе.
Directories/Conditionals
Установки Output и Unit output определяют, где компилятор размещает ЕХЕ или DLL, а также скомпилированные модули. Если оставить опции незаполненными, создаваемые модули будут располагаться там же, где и исходные тексты, а выходные выполняемые файлы или DLL — в папке проекта.
Conditional defines определяют флаги, проверяемые в процессе компиляции и используемые, как правило, для включения или исключения блоков кода из проекта при компиляции.
Unit Aliases существует для совместимости со старыми версиями Delphi (в свое время модуль Windows был разбит на два файла и для сборки одного модуля следовало присвоить один и тот же псевдоним Windows обоим файлам).
Добавление шаблонов проектов
Помимо стандартных, вы, вероятно, захотите иметь и собственные шаблоны. Для этого добавьте их в Object Repository следующим образом.
Создайте проект, добавьте в него код и объекты по вашему усмотрению.
Сохраните проект. Вернитесь к разделу "Разделяемое хранилище", чтобы вспомнить о том, где и как хранить шаблоны.
Выберите команду Project/Add To Repository, после чего будет выведено диалоговое окно Add to Repository, показанное на рис. 1.18.
Введите запрашиваемую информацию, щелкните на кнопке ОК, и проект будет добавлен в Object Repository в качестве шаблона.
![](image/ris1-24.jpg)
Рис. 1.18. Диалоговое окно Add to Repository позволяет добавить собственный шаблон проекта в Object Repository
Добавление собственного шаблона
Хотя имеющиеся шаблоны весьма полезны и хорошо сделаны, для продолжительной профессиональной работы их будет недостаточно. Наверняка нужно будет что-либо доработать или создать новую форму, которую можно было бы использовать в других приложениях. Чтобы не делать одну и ту же работу дважды (трижды, восемьюжды...), создайте шаблон формы и поместите его в хранилище объектов.
Создайте форму, добавьте в нее компоненты и приправьте все это кодом по вашему вкусу. Конечно, вы вполне можете использовать в качестве заготовки имеющийся шаблон.
Сохраните форму в папке OBJREPOS Delphi.
Совет: Object Repository не хранит копий всех шаблонов, а устанавливает связи с их DFM- и PAS-файлами. Если вы удалите такой файл, шаблон станет недееспособным.
Щелкните правой кнопкой мыши на форме и затем выберите команду Add to Repository. При этом Delphi выведет диалоговое окно Add To Repository, показанное на рис. 1.7.
![](image/ris1-8.jpg)
Рис. 1.6. Шаблоны форм позволяют использовать заготовленные общие формы
![](image/ris1-9.jpg)
Рис. 1.7. Используйте диалоговое окно Add To Repository для добавления ваших собственных шаблонов в хранилище объектов
Из списка Forms выберите форму, которую нужно добавить в хранилище.
Введите заголовок формы в поле Title (он будет использоваться в качестве подписи под пиктограммой в диалоговом окне New Items).
Из раскрывающегося списка Page выберите страницу, на которой будет размещен шаблон.
Щелкните на кнопке ОК, и форма будет добавлена в Object Repository.
Совет: Delphi автоматически включает вновь созданные формы в текущий проект. Они связаны с проектом, как
будто вы воспользовались опцией Use.
Element_ActiveX
Элементы управления ActiveX
Теперь займемся увлекательным делом — создадим элементы управления ActiveX. Рассмотрим, что собой представляв ActiveX и чем элементы управления ActiveX лучше или хуже стандартных компонентов Delphi на базе библиотек VCL.
Технология AcliveX компании Microsoft представляет собой технологию ОСХ, переделанную для обеспечения пepедачи элементов управления через службы Internet, в основном через World Wide Web. Я уверен, что читатель спросит "Это все хорошо, но как технология ActiveX может помочь мне?". Но неужели вам не хочется создать элементы управления, которые можно использовать не только в Delphi, но и в таких средах программирования, как Borland C++ Builde Visual C++ и Visual Basic? Технология ActiveX предоставляет вам такую возможность.
Чтобы использовать эту возможность, Delphi предлагает с помощью среды DAX заключить потомка класса TWin Control в элемент управления ActiveX. Ниже перечислены платформы, на которых сертифицированы для выполнены элементы управления ActiveX, поставляемые с Delphi.
Borland Delphi версии 2 и 3.
Borland C++ Builder.
Borland Paradox 8.
Borland IntraBuilder.
Microsoft Visual C++.
Microsoft Visual Basic версии 4 и 5.
Microsoft Internet Explorer 3.01.
Microsoft ActiveX Control Pad.
Microsoft Frontpage.
Создание элемента управления ActiveX предусматривает выполнение следующих этапов.
Элемент управления VCL должен быть вставлен в палитру компонентов Delphi и должен быть потомком класса TWinControl. Чтобы создать элемент управления ActiveX, являющийся потомком TGraphicControl. в большинстве случаев достаточно изменить базовый класс на TCustomControl. Этот способ использован в примере, который будет приведен немного позже.
Запустите мастера ActiveX Control, выбрав команду File/New и дважды щелкнув на пиктограмме ActiveX Control во вкладке ActiveX. В окне мастера выберите компонент VCL, который нужно преобразовать в элемент ActiveX, укажите имя элемента ActiveX, включите или отключите информацию о лицензировании, версии и т.п. После щелчка на кнопке OK Delphi создаст библиотеку типов со всеми свойствами, объявленными как public и published, методами и событиями. Дополнительно создаются два файла исходного кода: в одном из них содержатся определения из библиотеки типов (интерфейсы, диспинтерфейсы и т.д.), а во втором — реализации методов интерфейса, определенных в первом файле.
В процессе создания библиотеки типов Delphi может преобразовать не все конструкции языка то ли потому, что нет смысла преобразовывать отдельные конструкции, то ли потому, что она не знает, как преобразовать некоторые конструкции языка Object Pascal. Независимо от причины, по которой преобразование не выполнилось, в определение элемента ActiveX можно легко добавить любые свойства, методы и события. Для этого откройте библиотеку типов (с помощью команды View/Type Library), внесите необходимые изменения и щелкните на кнопке Refresh панели инструментов редактора библиотек типов, что позволит Delphi обновить код.
Создайте код всех методов Get и Set, в которых не реализована необходимая функциональность или которые оставлены пустыми, как добавления к библиотеке типов. Это относится и к обработчикам событий.
Теперь вы, возможно, пожелаете создать одну или несколько страниц свойств. В средах, не поддерживающих инспекторов свойств, это даст возможность пользователю, щелкнув правой кнопкой мыши, вызвать некоторое подобие инспектора свойств для изменения значений свойств элемента управления. Для этого, как минимум, нужно создать основную страницу свойств. Delphi обладает несколькими стандартными страницами свойств для управления цветом, шрифтами, изображением и списком строк Delphi.
Откомпилируйте и зарегистрируйте элемент управления.
ОСХ-файл можно импортировать в любую среду разработки, поддерживающую элементы управления ActiveX, которые созданы в Delphi.
Error Setting Debug Exception Hook
Если вы увидели сообщение, показанное рис. 2.26, значит, отладчик оказался в трудном и, главное, нестабильном положении, что обычно происходит после аварийной остановки отлаживаемого приложения. Что делать? Попробуйте воспользоваться командой Run/Program Reset и запустить приложение еще раз. Не помогло? Выполните команду Program/Build All. И это не дает результата? Тогда вам придется выйти из среды разработки
и запустить ее еще раз. Самый последний совет — проделать то же и с операционной системой...
![](image/ris2-27.jpg)
Рис. 2.26. Сообщение Error setting debug exception hook
EXEName
Это свойство представляет собой строку, содержащую полный путь выполняемого файла (аналог в С— argv[0]). Чаще всего оно используется для определения рабочего каталога приложения, в котором могут находиться файлы данных или инициализации программы.
Совет: Для получения из EXEName рабочего каталога используйте функцию ExtractFilePath или Extract-FileDir из модуля SysUtils.
External Exceptions
Сообщение об ошибке External exception, показанное на рис. 2.27, может вызываться порожденной приложением исключительной ситуацией, перехваченной He-Delphi-модулем (DLL). Коды ошибок определены в файле WINDOWS.PAS, включенном в поставку Delphi; их символические имена имеют вид STATUS_xxxxx. Например, показанная на рис. 2.28, исключительная ситуация C000001D— исключительная ситуация STATUS_ILLEGAL_INSTRUCTION. Это, конечно, позволяет судить о том, что произошло, но не дает никакой информации о том, где это произошло, так что единственный способ найти ошибку — разделять и властвовать, т.е. пересмотреть приложение до возникновения исключительной ситуации.
![](image/ris2-28.jpg)
Рис. 2.27. Сообщение о нарушении доступа
![](image/ris2-29.jpg)
Рис. 2.28. Сообщение о внешней исключительной ситуации
Фабрики объектов в среде DAX
Delphi предоставляет клиентам (контроллерам) объекты серверов СОМ посредством использования фабрик (factories) объектов, которые регистрируются с глобальным сервером СОМ Delphi СОМ Server (ComServer), определенным в модуле ComServ. Сервер СОМ Delphi обрабатывает все запросы объектов СОМ и создает запрашиваемые объекты, если такие зарегистрированы. Классы фабрик объектов используются для поддержки объектов СОМ, типизированных объектов СОМ, объектов автоматизации элементов управления, которые показаны ниже в порядке наследования.
TComObjectFactory
TActiveXPropertyPageFactory
TTypedComObjectFactory
TAutoObj ectFactory
TActiveXControlFactory
TActiveFormFactory
Классы TActiveXControlFactory и TActiveFormFactory используются для регистрации элементов управления ActiveX и форм ActiveForm.
Что же делают эти объекты? Они инкапсулируют интерфейс IClassFactory, используемый для создания объектов с ответствующего класса каждый раз, когда клиентское приложение запрашивает определенный объект. На эти классы также возложена ответственность за внесение записей в реестр Windows в соответствии с типом класса фабрики. Например, кла TActiveXControlFactory вносит в реестр информацию о сервере ActiveX и соответствующей библиотеке типов.
Получив представление о средствах Delphi, поддерживающих разработку объектов ActiveX, рассмотрим инструмент Delphi для создания объектов ActiveX. Как это ни странно, но начать придется не с кодирования, а с документации. Если быть более точным, то сначала придется создать библиотеку типов, которая будет использоваться в Delphi для генерации шаблон кода, базирующегося на иерархии классов среды DAX. Позже созданный шаблон будет заполнен, откомпилирован, зарегистрирован и т.д. Следовательно, прежде чем приступить к созданию объектов ActiveX, следует усвоить, что такое информаци о типах и как использовать редактор библиотек типов (Type Library Editor) Delphi. Обозначенные аспекты описаны в следуй щем разделе.
Файловый тип
Тип file предназначен для доступа к линейной последовательности элементов, которые могут представлять данные любого типа, кроме содержащих типы file и class. Объявление файлового типа подобно объявлению массива, только без указания числа элементов.
file of Typel // Файл определенного типа, содержащий
// записи фиксированной длины.
file // Файл без типа или "блочный".
textfile // Файл с записями переменной длины, разделенными символами CR
//и LF ("возврат каретки" и "новая строка").
Механизм ввода-вывода информации как никакой другой аспект программирования зависит от языка и реализации. В большинстве случаев предполагается, что программисту незачем вникать во внутреннюю структуру переменных, управляющих вводом-выводом, и при передаче информации следует полностью полагаться на предназначенные для этого процедуры. Их реализация должна оставаться чем-то наподобие черной магии. В Basic файлы обозначаются числовыми значениями — дескрипторами. В C/C++ программисты манипулируют указателями на структуру FILE. И только в Delphi файловая структура — это переменная.
Фиксированные записи
В фиксированной части записи определяется одно или несколько независимых полей. Каждому полю обязательно присваивается имя и тип:
record
fieldnamel: fieldtypel;
fieldname2, fieldname3: fieldtype2;
end;
Имея доступ к информации в записи, можно обрабатывать всю запись целиком (все поля одновременно) или только отдельное поле. Для обращения к отдельному полю наберите имя записи, точку и идентификатор поля, например
MyRec.Fieldnamel
Для доступа ко всей записи просто укажите ее имя.
Совет: В языке С эквивалентом фиксированного типа record из Delphi является struct. В C++ также определен тип struct, синтаксис которого совместим с типом struct из С. Однако в C++ этот тип имеет дополнительные особенности, благодаря чему напоминает тип Class из Delphi.
Forms
Раскрывающийся список Main form определяет главную форму вашего приложения, которую Delphi выводит первой и закрывает, когда приложение завершает работу.
Два списка. Auto-create forms и Available forms, позволяют определить автоматически создаваемые формы.
Forms и FormCount
Эти свойства возвращают список форм и их количество. Работа с ними ничем не отличается от работы со списком дочерних окон, описанных в разделе "MDIChildren и MDIChildCount".
FormStyle
Свойство FormStyle перечислимого типа определяет, как форма взаимодействует с вашим приложением и Windows.
Существует два основных стиля форм — MDI (Multiple Document Interface — многодокументный интерфейс) и не MDI. Имеется два MDI-стиля (fsMDIForm и fsMDIChild), которые рассматриваются ниже. Не MDI
формы существуют также в двух вариантах— fsNormal и fsStayOnTop. Наиболее популярен стиль fsNormal, который создает стандартный стиль, используемый для диалогов, панелей инструментов и SDI-приложений.
Стиль fsStayOnTop применяется реже и создает форму, всегда остающуюся поверх других форм и приложений, что может быть полезно при выводе системной информации и использовании ресурсов. Примером такого окна является окно программа Chat, используемой при работе в сети.
Вот как можно реализовать, подобно программе Chat, установку вывода поверх других окон путем выбора пункта меню.
procedure TFormI.mnuAlwaysOnTopClick(Sender: TObject);
begin
with mnuAlwaysOnTop do
begin
{Переключаем отметку выбора пункта меню.}
Checked:= not Checked;
{Проверка установок меню.}
if Checked then
(Устанавливаем стиль fsStayOnTop.)
FormStyle:= fsStayOnTop
else
{Возвращаем нормальный стиль.}
FormStyle:= fsNormal;
end;
end;
Совет: Изменение свойства FormStyle вызывает событие OnShow.
Функции Windows API для консольного приложения
Вы можете делать гораздо больше в консольном приложении, чем просто считывать и выводить текст. Вам доступно около 40 функций Windows API для работы с дисплеем, например изменение атрибутов выводимых символов или изменение размеров консоли.
В листинге 1.1 изменяется текст, выводимый в заголовке консольного окна. Вы можете найти этот пример на дополнительно распространяемой дискете в папке EgConsoleTitle.
Листинг 1.1. Изменение заголовка консольного окна
program EgConsoleTitle;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils;
{$R *.RES}
var
sNewTitle, sErrMsg: String;
begin
sNewTitle:= 'Welcome to Con5ole World';
if not SetConsoleTitle(PChar(sNewTitle)) then
begin
sErrMsg:= 'Unable to set caption - '+SysErrorMessage(GetLastError);
MessageBox(0,PChar(sErrMsg),'Error',MB_ICONEXCLAMATION+MB_OK);
end;
ReadLn;
end.
Здесь функция API SetConsoleTitle возвращает False, если назначить новый заголовок невозможно. GetLastError возвращает числовое значение последней ошибки API, которое SysErrorMessage конвертирует в строку для вывода на экран.
Совет: Поставляемая с Delphi система справки по Win32 содержит функции консольного API. Для доступа к ним выведите пункт Console Reference и щелкните на кнопке.
Чаще всего Delphi используется для
Создание приложений
Чаще всего Delphi используется для создания приложений. Вы можете создавать приложения любого типа — от утилит командной строки до программы электронной почты или многопользовательской финансовой базы данных.
В этом пункте Вы познакомитесь с созданием приложений, и с тремя основными типами приложений. В конце будет приведено несколько советов о том, как ускорить создание программ и сделать их более профессиональными.
Как пользователь Windows вы, конечно
Тестирование и отладка
Как пользователь Windows вы, конечно же, сталкивались с множеством чужих ошибок в программах. Теперь пора и вам как разработчику программного обеспечения наделать массу ошибок.
Вот он, решающий момент: вы последний раз ударили по клавишам, и ваша,
несомненно, выдающаяся программа,
готова! Она принесет вам известность и славу, и, как маленькому ребенку, вам хочется закричать: "А теперь хвалите меня!". Но первый восторг проходит вместе с первым запуском программы — похоже, она не делает того, чего вы хотели... Здесь явно неправильный вывод на экран, тут операционная система сообщает, что лучше бы вам заняться более спокойным и доходным, по сравнению с программированием, делом и не приводить ее в состояние недоумения... Что же делать?
Но вы— счастливчик: вы работаете с Delphi! Интегрированная среда разработки предоставляет не одну возможность упростить тестирование и отладку приложения. В этой главе вы познакомитесь с ними, так что пользователи вашей программы не будут расточать в ваш адрес не самые лестные предположения о вашей квалификации программиста.
Height и Width
Это наиболее полезные свойства, возвращающие высоту и ширину экрана в пикселях. Они могут применяться во многих ситуациях, например при определении местоположения формы. Вот как поместить форму в центре экрана.
Left:= (Screen.Width - Width) div 2;
Top:= (Screen.Height - Height) div 2;
Эти свойства определяют высоту и ширину формы в пикселях и обычно используются для изменения размеров формы во время работы на дисплеях разной разрешающей способности. Вот пример увеличения размеров формы до размеров всего экрана.
{Перемещаем форму в верхний левый угол экрана.}
Left:= 0;
Тор:= 0;
(Изменяем размеры формы.)
Width:= Screen.Width;
Height:= Screen.Height;
(Класс TScreen, о котором будет сказано ниже, и его экземпляр Screen предоставляют доступ к информации о размерах всего экрана.)
Приведенный код, конечно, работает, но плохо, так как требуется четыре обновления формы. На самом деле лучше использовать метод SetBounds, определенный у потомков TWinControl:
SetBounds(0, 0, Screen.Width, Screen.Height);
Hint и ShowHint
В свойстве Hint содержится текст, который будет выведен после запуска события OnHint.
Свойство ShowHint используется для определения, выводится ли подсказка "на лету". Установка свойства равным False отключает систему подсказок для всех элементов в приложении независимо от их индивидуальных установок. Обычно оно используется совместно с пунктом меню, включающим или отключающим подсказки. Вот примерный код.
procedure TFormI.mnuToggleHintsClick(Sender: TObject);
begin
{Переключение текущего состояния.}
mnuToggleHints.Checked:= not mnuToggleHintsChecked;
{Обновление свойства ShowHint.} Application.ShowHint:= mnuToggleHints.Checked;
end;
HintColor, HintPause, HintHidePause и HintShortPause
HintColor определяет цвет окна всплывающей подсказки, например
Application.HintColor:= cILime;
HintPause и HintHidePause определяют временные задержки при показе подсказок следующим образом.
Указатель мыши помещается над потомком TControl. Событие OnHint вызывается сразу же после установки указателя мыши на TControl.
Delphi ожидает HintPause миллисекунд перед выводом окна подсказки.
Указатель остается над TControl.
Delphi ожидает HintHidePause миллисекунд перед закрытием окна подсказки.
Свойство HintShowPause определяет задержку перед отображением подсказки, если активна подсказка другого элемента.
Icon
Свойство Icon позволяет изменить пиктограмму, представляющую приложение в панели задач во время работы. Это полезно, если необходимо отмечать,
таким образом, изменение состояния приложения. Следующий код назначает пиктограмму из файла INACTIVE.ICO:
Application.Icon.LoadFromFile('INACTIVE.ICO');
Свойство Icon определяет пиктограмму, выводимую Windows при сворачивании вашей формы. В интерфейсе Windows 95 эта пиктограмма также выводится в левом верхнем углу формы на кнопке системного меню. Если вы не определите значения для этого свойства, будет использоваться свойство Icon глобального объекта Application.
Информация о библиотеке типов
Каждая библиотека типов включает раздел, описывающий саму библиотеку, — элемент библиотеки типов. Когда этот элемент выбран в панели Object List (см. рис. 3.1), в правой части экрана редактора библиотеки типов появляются две вкладки: Attributes и Uses. Два следующих раздела описывают назначение вкладок Attributes и Uses в элементе библиотеки типов.
Использование директивы Assert
Оператор Assert— новый оператор в Delphi 4. В действительности это просто тест на логическую истину/ложь. При использовании этого оператора вы убеждаетесь, что логическое выражение истинно, если при выполнении выражение становится ложным, генерируется исключительная ситуация. Синтаксис использования оператора таков:
Assert (<логическое выражение)
Вы можете использовать проверку, например, в начале процедуры для выяснения корректности параметров, как показано ниже.
procedure Foo(Count: Cardinal);
begin
Assert(Count < SizeOf(Word));
end;
Если выражение окажется ложным, появится сообщение об ошибке, подобное показанному на рис. 2.3. Конечно же, у вас уже вертится на языке вопрос, чем же это отличается от конструкции if... else. Дело в том, что управлять генерацией кода для оператора Assert очень легко и просто с помощью директивы компилятора. Для применения описанных возможностей используйте директиву $ASSERTIONS ON или $С
+, а для отключения действия Assert— $ASSERTIONS OFF или $С - (при этом компилятор игнорирует операторы Assert и код для них не генерируется).
![](image/ris2-3.jpg)
Рис. 2.3. Сообщение об ошибке Assert
Поскольку вы явно захотите включить эту возможность в отладочную версию и исключить ее из коммерческой, используйте код, подобный приведенному ниже.
{$ifdef Debug}
($ASSERTIONS ON)
{$else}
($ASSERTIONS OFF)
{$endif}
Какого типа выражения могут использоваться в операторе Assert? Любого (конечно, если оно возвращает логическое значение). Однако тут есть свои маленькие подводные камушки, о которые легко поцарапаться. Представьте себе, что у вас есть некоторая функция, например выясняющая, сколько раз она была вызвана.
function CountMe: Integer;
const ReferenceCount: Integer = 0;
begin
Inc(ReferenceCount);
Result:= ReferenceCount;
end;
Предположим, что вы вызываете ее в операторе Assert. Таким образом, в коммерческой версии, которая игнорирует все операторы Assert, количество вызовов функции будет не таким, как в отладочной версии. Так что будьте внимательны и осторожны.
Использование модулей выполнения
Наиболее важный момент в этом процессе — распространение модулей выполнения (runtime packages). Если элемент управления ActiveX или форма ActiveForm использует модули, то следует включить опцию Deploy Required Packages.
Использование наследования форм
В хранилище объектов содержится несколько примеров наследования форм. Для того чтобы наследовать одну форму из другой, выполните следующие действия.
Выберите команду File/New Application. При этом появится пустое приложение.
Выберите команду File/New, и будет выведено диалоговое окно New Items.
Щелкните на вкладке Dialogs, и будет выведена страница диалогов.
Выберите диалог с пиктограммой Help, кнопки которого выровнены вертикально по правой стороне формы.
Выберите опцию Inherit.
Щелкните на кнопке ОК, и Delphi выведет новую диалоговую форму.
Заголовок нового диалогового окна— OKHelpRightDlg2. Почему Delphi создает это диалоговое окно как OKHelpRightDIg? Ответ заключается в наследовании форм. В списке форм вашего проекта содержится четыре объекта— Form1, OKHelpRightDIg, OKHelpRightDlg2 и OKRightDlg. Поскольку вы наследуете новую форму из OKHelpRightDIg, Delphi включает его в ваш проект для компиляции вашей программы. Это и приводит к наименованию новой формы как OKHelpRightDlg2. К тому же это позволяет избежать конфликта имен. В свою очередь, OKHelpRightDIg — наследник OKRightDlg, а потому последний также включен в проект.
ПРЕДОСТЕРЕЖЕНИЕ: Две родительские формы, OKHelpRightDIg и OKRightDlg, связываются с проектом так же, как и опция Use, поэтому, решив их изменить, вы измените объекты, хранящиеся в Object Repository.
Цепочка наследования отражена в автоматически генерируемом коде. Описание класса OKHelpRightDlg2 выглядит так.
TOKHelpRightDlg2 = class (TOKHelpRightDIg) private
{Закрытые объявления.}
public
{Открытые объявления.}
end;
Совет: Описание класса или типа начинается с буквы Т.
Это объявление не назовешь чересчур информативным. Поскольку вы не добавляли ни новых компонентов, ни кода, OKHelpRightDlg2 не определяет ни новых свойств, ни методов или событий. Определение класса TOKHelpRightDIg несколько интереснее.
TOKHelpRightDIg = class (TOKRightDIg)
HelpBtn: TButton;
procedure HelpBtnClick(Sender: TObject);
private
{Закрытые объявления.}
public
{Открытые объявления.}
end;
Как вы можете видеть, OKHelpRightDIg получает компоненты и код от OKRightDIg и добавляет объект HelpBtn типа TButton, а также обработчик события HelpBtnClick.
Использование отладчика TD32.EXE
Может случиться, что, несмотря на все возможности отладчика Delphi 4, вы столкнетесь с совершенно неотслежимаемой ошибкой. Если это произойдет, примите мои искренние соболезнования. Можете попытаться использовать отдельный отладчик фирмы Borland (TD32.EXE), поставляемый в комплекте Turbo Assembler или Borland C++. В дополнении ко всему, что есть в отладчике Delphi, TD32 имеет и то, чего в Delphi нет. В частности, TD32 позволяет установить аппаратные точки останова, что означает, например, останов при обращении к портам ввода-вывода или к памяти. Это тяжелая работа, и я могу только посочувствовать вам, если вы за нее беретесь. И учтите, что такая работа требует знания как системного программного, так и аппаратного обеспечения.
Использование подписей кода
Если вы хотите подписать проект элемента управления ActiveX или формы ActiveForm, то сначала включите опцию Code sign project, а после этого во вкладке Code Signing диалогового окна Web Deployment Options введите следующий текст.
Have obtained a Software Publishing Certification file (.SPC)
Private Key (.PVK)
Что такое подпись кода? Это технология, встроенная в Microsoft Internet Explorer, известная как Authenti-code™. Она позволяет приложению Internet Explorer вместо стандартного предупреждения об использовании неизвестного приложения отображать сообщение о сертификате подлинности программного обеспечения в момент загрузки выполняемого кода, например программ установки через Internet, элементов управления ActiveX или форм ActiveForm. Подпись кода—это цифровой идентификатор (Digital ID) в компании VeriSign (www.verisign.com) с целью получения сертификата на публикацию программного обеспечения Software Publishing Certificate и частного ключа Private Key, используемого для подписи всех распространяемых компанией выполняемых файлов. С помощью подписи кода разработчик может обеспечить пользователей информацией и страховкой при загрузке программного обеспечения из Internet.
Никаких требований, заставляющих разработчиков подписывать выполняемый код, не существует, но эта процедура предоставляет способ повышения надежности загрузки программного обеспечения из Internet. Более подробную информацию о получении цифрового идентификатора VeriSign Software Publisher Digital ID можно получить на Web-узле компании VeriSign по адресу http://www.verisign.com. Внимание! Пожалуйста, запомните, что регистрация программного обеспечения производится для выбранного компьютера. Это значит, что регистрироваться для получения идентификатора Digital ID, получать идентификатор Digital ID и использовать этот идентификатор нужно на одном компьютере и в одной версии Internet Explorer. Если службу Authenticode планируется использовать более чем на одном компьютере, то нужно получить более чем один идентификатор Digital ID. Если установлена новая версия Internet Explorer, то нужно выполнить повторную регистрацию.
Использование шаблонов форм
Приведенные ниже опции позволяют использовать шаблоны форм.
Copy. Эта опция добавляет копию шаблона формы в ваш проект. Изменения объекта в проекте не влияют на другие объекты.
Use. Эта опция связывает шаблон непосредственно с вашим проектом. Изменения в проекте воздействуют на объект, находящийся в хранилище, и наоборот.
Для иллюстрации сказанного добавим в проект новую форму, основанную на шаблоне About box, следующим образом.
Выберите команду File/New Application. Появится пустое приложение.
Выберите команду File/New. Появится диалоговое окно New Items.
Щелкните на вкладке Forms вверху диалогового окна. Delphi выведет доступные шаблоны форм, как показано на рис. 1.6.
Убедитесь, что выбран метод Copy или Use.
Щелкните на кнопке ОК. Новая форма About box будет добавлена в ваш проект.
Если вы выбрали опцию Copy, новая форма будет дубликатом шаблона и дальнейшая работа с ней не отразится на шаблоне-оригинале. При использовании Use все изменения в одном проекте через хранилище форм будут переданы во все проекты, применяющие эту форму с опцией Use.
Использование шаблонов проектов
Delphi поставляется с тремя шаблонами проектов.
MDI Application создает полностью функциональный MDI-проект. Родительская форма включает меню, кнопки Speed Button и строку состояния. Проект также содержит замещаемый код, реализующий функции меню и управляющий сообщениями в строке состояния.
SDI Application содержит простой SDI-проект. Основная форма содержит меню, кнопки Speed Button и строку состояния. В проект также включено диалоговое окно About и реализующий его код.
Win95 Logo Application создает проект, моделирующий основные принципы, которые установлены Microsoft для нее Win95 Logo certification. Если вы будете придерживаться этого стиля и получите сертификат Microsoft, то сможете вывести логотип "Designed for Win95".
Для создания нового SDI-поиложения с использованием шаблона выполните следующие действия.
Выберите команду File/New, и появится диалоговое окно New Items (см. рис. 1.6).
Щелкните на вкладке Projects, что приведет к появлению соответствующей страницы.
Выберите пиктограмму SDI Application, щелкните на кнопке ОК, и появится диалоговое окно Select Directory, показанное на рис. 1.16.
Определите каталог для нового проекта. Если вы выберете несуществующий каталог, Delphi создаст его для вас.
Щелкните на кнопке ОК, и новый проект будет создан. При создании проекта доступна только опция Copy. Все файлы проекта копируются в ваш каталог и изменения в них не приведут к изменению шаблона проекта в хранилище.
На странице Projects содержится еще одна пиктограмма— Application Expert. Эксперт приложений, показанный на рис. 1.17, проведет вас через все этапы создания нового проекта.
![](image/ris1-22.jpg)
Рис. 1.16. Диалоговое окно Select Directory позволяет выбрать каталог для нового проекта.
![](image/ris1-23.jpg)
Рис. 1.17. Application Expert поможет вам создать новый проект.
Использование сжатия CAB
Пользователю предоставляется возможность использовать опцию Use CAB file compression, которая позволяет сжать элемент управления ActiveX или форму ActiveForm и любые дополнительные файлы, такие как файлы DPL или файлы лицензий. Эта возможность поддерживается только при использовании броузера Internet Explorer 3.01. На сегодняшний день броузер Netscape Navigator не поддерживает САВ-файлы. По умолчанию библиотека ActiveX, модули (если такие есть) и дополнительные файлы упаковываются в три САВ-файла. Возможна также упаковка всех файлов в один САВ-файл, но делать это не рекомендуется. Разделяя файлы по различным архивам CAB, вы можете избежать загрузки излишних файлов, которые уже установлены на компьютере пользователя.
Элементы Interface и Displnterface в библиотеках типов
Интерфейс в библиотеке типов — это коллекция определении свойств и методов. Клиент может получить доступ к интерфейсам либо посредством таблицы виртуальных методов, либо с помощью специального интерфейса OLE I Dispatch, который позволяет использовать свойства и методы объектов через уникальный идентификатор или DispID. Элемент Displnterface определяет интерфейс, доступ к которому можно получить только через интерфейс IDispatch. Двойной интерфейс (dual interface) — это интерфейс, доступ к которому можно получить и через таблицу виртуальных методов, и через интерфейс IDispatch. В следующих двух разделах рассматривается назначение вкладок Attributes и Members в описании интерфейсов.
KeyPreview
Объект TForm наследует от класса TWinControl обработку событий OnKeyDown, OnKeyUp и OnKeyPress, и свойство KeyPreview определяет ситуации, в которых эти сообщения запускаются. Если значение KeyPreview равно False, события клавиатуры пересылаются только тому управляющему элементу, который имеет фокус ввода. В неординарном случае, когда в форме нет управляющих элементов,
событие передается форме. Если же значение свойства установлено равным True, событие сначала пересылается форме, а затем — управляющему элементу, имеющему фокус ввода.
Совет: Поскольку клавиша
<Tab> используется для передачи фокуса другому управляющему элементу, она не вызывает генерации события.
Обычно свойство используется KeyPreview для обработки функциональных клавиш, которые должны быть переданы форме независимо от текущего активного элемента.
Без этого свойства обработка функциональных клавиш сводится к написанию для каждого элемента дополнительного обработчика, который должен отслеживать нажатие функциональных клавиш. Более элегантным является использование разделяемого обработчика событий, так что лучше всего применять свойство KeyPressed.
При этом все нажатия клавиш отсылаются обработчикам событий OnKeyDown, OnKeyUp и OnKeyPress автоматически и для "отлова" функциональной клавиши надо написать только один обработчик события OnKeyDown формы. Вот пример закрытия формы при нажатии клавиши <F2.
procedure TFormI.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState):
begin
{Проверить, нажата ли клавиша <F2.}
if Key = VK_F2 then
{Закрыть форму.}
Close;
end;
Рассматривая принцип работы этого кода, имейте в виду, что события OnKeyDown и OnKeyUp используют виртуальные коды (все они перечислены в файле WINDOWS.PAS).