Учебник по Delphi 4

         

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).
 



Компонент TApplication



Компонент TApplication инкапсулирует приложения при выполнении. Delphi автоматически создает экземпляр Application класса TApplication при выполнении приложения. Для использования этого объекта включите модуль Forms в раздел uses.



Компонент TScreen



    Класс TScreen инкапсулирует состояние экрана или выводимой области. Delphi во время работы автоматически создаст экземпляр класса Screen. Для его использования в раздел uses нужно включить модуль Forms.



Linker



    Опция Map file полезна для тех программистов, которые интересуются технической информацией, например адресами сегментов, стартовым адресом программы и т.п.


    Linker output определяет, что именно будет выдавать компилятор — Delphi Compiled Unit (DCU) или объектные файлы (OBJ). Последние могут применяться, например, при разработке программ с использованием двух языков.


    Опции ЕХЕ и DLL позволяют создавать консольные приложения, описанные в разделе "Создание консольного приложения", и включать отладочную информацию, о которой подробно рассказывается в главе 2, "Тестирование и отладка".


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


    ЕХЕ Description представляет возможность внести в ЕХЕ или DLL строку описания приложения (что-то вроде "MixFix (С) 1993-1997 KIV without Co").



Main


Учебник по Delphi

Глава 1. Что нового в Delphi4


Глава 2. Палитра компонентов


Глава 3. Типы данных

Простые типы данных


Строковые типы


Структурные типы


Указательные типы


Процедурные типы

Глава 4. Создание приложений

Работа с формами


Создание приложений SDI


Создание приложений MDI


Создание консольного приложения


Повторное использование приложений


Опции проекта


Передовые технологии программирования

Глава 5. Создание элементов управления ActiveX

Среда разработки Delphi ActiveX (DAX)


Библиотеки типов


Элементы управления ActiveX


Регистрация и установка элемента управления ActiveX


Создание формActiveForm


Распространение элементов управления ActiveX и форм ActiveForm в Web

Глава 6. Тестирование и отладка

Тестирование


Интегральный отладчик Delphi


Силовая отладка


Обработка ошибок



Make_ActiveForm


 Создание форм ActiveForm

    Форма ActiveForm — это набор визуальных или невизуальных компонентов для создания смешанного элемента управления ActiveX. Другими словами, визуальные элементы управления ActiveX можно совмещать для создания простого комбинированного элемента ActiveX. Кроме того, можно создавать целые приложения, обладающие одной формой. которые будут распространяться как формы ActiveForm.
    Использование невизуальных элементов означает, что в формах ActiveForm можно использовать объекты BDE для доступа к базам данных, или, что еще лучше, для доступа к данным можно использовать технологию брокеров данных производства Borland (Data Broker), которая разрабатывалась специально для доступа к распределенным множествам данных в рамках сети, такой как Internet.
    Что касается выполняемых в формах ActiveForm действий, то тут нет каких-то особых ограничений. Единственным отличием от стандартных форм Delphi является то, что клиентам предоставляются только те свойства, методы и события, которые связаны непосредственно с формой ActiveX. Это означает, что все свойства, методы и события компонентов VCL, используемых в форме, не будут предоставляться клиентам. Названные элементы являются внутренними по отношению к форме ActiveForm.
    Если необходимо предоставить клиентам доступ к внутренним свойствам компонентов VCL, то следует добавить в форму ActiveForm новые свойства и методы, как в процессе создания элемента управления ActiveX. За исключением таких случаев, методы свойства Get и Set будут получать и устанавливать значения внутренних компонентов, а не основ-ного элемента управления VCL.
Процесс создания формы ActiveForm в основном совпадает с процессом создания элемента управления ActiveX, но для ясности ниже перечислены основные его этапы:

Мастера ActiveForm можно запустить с помощью команды File/New и двойного щелчка на пиктограмме ActiveForm, расположенной во вкладке ActiveX. Форма ActiveForm всегда "облачается" в компонент TActiveForm, следовательно, от пользователя требуется только указать имя создаваемого элемента ActiveX, имя модуля реализации, имя проекта, включить или отключить лицензирование и т.п. После щелчка на кнопке OK Delphi создаст библиотеку типов, в которую войдут все общедоступные и опубликованные свойства, методы и события класса TActiveForm. Кроме того, Delphi создаст два файла исходного кода. Один — с информацией из библиотеки типов (интерфейсы. диспинтерфейсы и т.д.), второй —для реализации методов интерфейса, объявленных в первом файле.


Вставьте в форму ActiveForm один или несколько визуальных или невизуальных компонентов.

После этого добавьте в форму одно или несколько свойств, методов или событий. Для этого откройте редактор библиотек типов (View/Type Library) и внесите необходимые изменения. Затем щелкните на кнопке Refresh, расположенной на панели инструментов редактора библиотек типов. Это позволит Delphi создать код оболочки для добавленных в библиотеку типов элементов.

Создайте код для всех методов Get и Set, функциональность которых не реализована полностью или которые оставлены пустыми для дополнений библиотеки типов. Это относится и к обработчикам событий.

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

Откомпилируйте и зарегистрируйте созданный элемент управления.

Теперь созданный файл ОСХ можно импортировать в любую среду программирования, которая поддерживает элемент управления ActiveX.


Make_ActiveX


 Создание элементов управления ActiveX

    Большинству пользователей устышавших термин АсtiveX на ум сразу приходят элементы управления ОСХ по-новому названные в очередном маркетинговом трюке компании Microsoft. В некотором смысле это так Microsoft действительно использует термин ActiveX дтя обозначения технологии базирующихся на модели СОМ. Но аббревиатура OLE уже не охватывает всех этих технологий. Microsoft настолько расширила определение OLE, что разработчики уже чавно считают сопутствующие технологии чем-то отдельным от OLE. Поэтому в профессиональную лексику был введен термин ActiveX, используемый для обозначения всех базирующихся на СОМ технологии, которые существуют на данный момент и будут созданы в будущем. На сегодняшний день ActiveX включает следующие технологии:
 

Библиотеки ActiveX (внутренние серверы)

Серверы автоматизации (внутренние и внешние серверы)

Элементы управления ActiveX

Формы ActiveForm (комбинированные элементы управления ActiveX)

Страницы свойств



Массивы



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

    array [ordinal_type] of type_definition;
    array [ordinal typel, ordinal type2] of type definition;

    Каждый массив содержит некоторое количество элементов информации одного типа. Для обращения к элементу массива надо указать имя массива и индекс элемента, заключенный в квадратные скобки. Обратите внимание, что число элементов массива в каждом измерении задается порядковым типом (ordinal_type). Для этого можно воспользоваться идентификатором некоторого типа (например, Boolean или AnsiChar), однако на практике обычно явно задается поддиапазон целых.
    Количество элементов массива равно произведению количеств элементов во всех измерениях.
Для обращения к элементу массива укажите имя этого массива и индекс элемента в квадратных скобках. Пусть, например, массив определен следующим образом:

    var MyArray: Array [1..10] of Integer;

    Тогда обращение к его третьему элементу будет выглядеть, как MyArray[З], и выполняться, как к переменной Integer.

Совет: Понятие массива существует в большинстве языков программирования, однако синтаксис, как правило, в каждом случае свой. В языках Basic и FORTRAN вместо квадратных скобок применяются круглые. В С и  C++ элементы массива нумеруются с нуля, в FORTRAN — с единицы. В Basic нумерация начинается с нуля или единицы, в зависимости от результата последнего выполнения оператора OPTION BASE. В некоторых версиях Basic можно задавать верхнее и нижнее значения индексов, как это делается в Delphi. В С и C++ обращение к массиву эквивалентно обращению к его первому (нулевому) элементу. В Delphi это будет обращением ко всему массиву.



MDI-методы TForm



    Специфичные для MDI-форм методы перечислены ниже.


Arrangelcons выстраивает пиктограммы минимизированных дочерних форм в нижней части родительской формы.


Cascade располагает дочерние формы каскадом, так что видны все их заголовки.


Next и Previous переходит от одной дочерней формы к другой, как будто вы нажали <Ctrl+Tab>

или <Ctrl+Shift+Tab>.
Tile выстраивает дочерние формы так, что они не перекрываются.
 



MDI-события TForm



В MDI-приложении событие OnActivate запускается только при переключении между дочерними формами. Если фокус ввода передается из не MDI-формы в MDI-форму, генерируется событие OnActivate родительской формы, хотя ее свойство Active никогда и не устанавливается равным True. Эта странность на самом деле строго логична: ведь, если бы OnActivate генерировался только для дочерних форм, не было бы никакой возможности узнать о переходе фокуса ввода от другого приложения.



MDI-свойства TForm



    Объект TForm имеет несколько свойств, специфичных для MDI-приложений.



MDIChildren и MDIChildCount



    Свойство MDIChildren является массивом объектов TForm, предоставляющих доступ к созданным дочерним формам. MDIChildCount возвращает количество элементов в массиве MDIChildren.


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

формами. Вот код сворачивания всех дочерних форм командой Minimize All.

    procedure TFormI.mnuMinimizeAllClick(Sender: TObject);


    var


        iCount: Integers;


    begin


        for iCount:= MDIChildCount-1 downto 0 do


            MDIChildren[iCount].WindowState:= wsMinimized;


    end;

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



Menu



    Это свойство определяет компонент TMainMenu, который предоставляет главное меню формы. Свойство Menu позволяет сделать меню контекстно-зависимым и часто используется в OLE-приложениях при замене вашего исходного меню на меню приложения-сервера. На рис. 1.5 показан документ Wordpad с внедренным объектом MediaClip. Обратите внимание, что меню и панель инструментов при этом те же, что и у Media Player.

Рис. 1.5. Вы можете создать контекстно-зависимое меню с помощью свойства Menu

    Для изменения свойства Menu просто присвойте ему новое значение (TMainMenu или его потомок):

    Menu:= mnuMainMenu;


 



Minimize и Maximize



   Эти методы заставляют приложение принять свернутый и развернутый вид. Вы можете удивиться, зачем это необходимо при наличии свойства WindowState объекта TForm. Однако так вы можете минимизировать форму на рабочем столе, но не в панели задач. Описываемый здесь метод осуществляет эту операцию более корректно.



Множества



Зарезервированное слово set (множество) определяет множество не более чем из 256 порядковых значений:

    Set of ordinal type

    Минимальный и максимальный порядковые номера исходного типа (на основе которого определяется множественный тип) должны быть в пределах между 0 и 255. Переменная множественного типа содержит (или не содержит) любое значение исходного порядкового типа. Каждое значение из заданного диапазона может принадлежать или не принадлежать множеству. Рассмотрим следующий пример.

    Type CharSet = set of AnsiChar; // Тип множества символов. ANSI.
    var MyAlphaSet: CharSet;           // Переменная типа CharSet.

    Переменная set может содержать все элементы множества или не содержать ни одного. При присвоении значения переменной множественного типа элементы множества (порядковые значения) указываются в квадратных скобках:

    MyAlphaSet := ['А', 'Е', 'Г, 'О', 'U', 'Y']; // Все прописные гласные.

    Пустые квадратные скобки задают пустое множество, не содержащее ни одного элемента. Это относится ко всем множественными типам.

Совет: Во многих языках структурный множественный тип отсутствует. Вместо него можно применять что-либо наподобие битовых образов или битовых полей.



Модульное тестирование



    Тема модульного тестирования обширна и многообразна, и писать о ней можно много, но я ограничусь буквально несколькими словами. Кстати, когда речь идет о модульном тестировании, слово модуль не имеет отношения к концепции модулей Delphi и подразумевает функцию, подсистему или другой хорошо определенный программный модуль.


    Коротко говоря, идея модульного тестирования состоит в разбивке приложения на функциональные единицы и тестировании каждой из них по отдельности. Это часто означает написание одного или нескольких небольших приложений-оболочек, цель создания которых — отработать один из модулей вашего приложения.

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

Рис. 2.4. О чем думают пользователи, когда ваша программа выводит сообщение об ошибке?..

    Ну, и наконец,

философское замечание о следствии из закона Мэрфи для программирования "В любой работающей программе есть хотя бы одна ошибка, при исправлении которой вносится, по крайней мере,

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



Написание кода



    Создав интерфейс, перейдем к написанию исходного текста приложения, который будет очень похож на код для SDI-приложения.


    Сначала загрузим изображение. Введите следующий код в обработчик события OnClick компонента spbtnLoad.

    procedure TfrmMDIParent.spbtnLoadClick(Sender: TObject);


    begin


        if opndlgLoad.Execute then


            with TfrmMDIChild.Create(Application) do


            begin


                Caption:= opndlgLoad.FileName;


                imgMain.Picture.LoadFromFile(opndlgLoad.FileName);


                ClientWidth:= imgMain.Picture.Width;


                ClientHeight:= imgMain.Picture.Height;


            end;


      end;

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

После загрузки размеры дочерней формы изменяются так, чтобы можно было видеть все изображение.


    Еще пара штрихов— и приложение заработает, как и предусматривалось. Поскольку модуль ссылается на тип TfrmMDIChild, находящийся в модуле MDIChild, после строки implementation следует добавить еще одну строку:

    uses MDIChild;

    Теперь можно приступить к компиляции и запуску приложения. Однако заметьте, что, когда вы щелкаете на кнопке Close, дочерняя форма не закрывается, а сворачивается в пиктограмму. Чтобы заставить ее закрыться, следует добавить в код обработчика OnClose класса TfrmMDIChild маленькую деталь— изменить свойство Action:


    Action:= caFree;

    Компоненты TSpeedButton Stretch и Center выполняют те же функции, что и в SDI-приложении, однако их обработчики события OnClick следует изменить следующим образом

if not (ActiveMDIChild = Nil) then

     if ActiveMDIChild 15 TfrmMDIChild then

        TfrmMDIChild(ActiveMDIChild).imgMain.Stretch:= spbthStretch.Down;

и

if not (ActiveMDIChild = Nil) then

    if ActiveMDIChild is TfrmMDIChild then

        TfrmMDIChild(ActiveMDIChild).imgMain.Center:= spbthCenter.Down;

    Остается последняя проблема — состояния кнопок Stretch и Center одинаковы для всех дочерних форм Для решения этой задачи добавьте в обработчик события OnActivate класса TfrmMDIChild строки.

    frmMDIParent.spbtnStretch.Down:= imgMain.Stretch;

    frmMDIParent.spbtnCenter.Down:= imgMain.Center;

    И, наконец, самый последний из последних штрихов— в модуле MDIChild добавьте после строки implementation строку.

    uses MDIParent;

    Компилируйте, запускайте и смотрите. MDI-приложение создано!

ПРЕДОСТЕРЕЖЕНИЕ: В этом примере присвоение нового значения свойству Down класса TSpeedButton вызывало событие Оn-click. Будьте осторожны при написании кода обработчика события, который генерирует новое событие путем присвоения значения свойству, ведь при этом можно создать бесконечную рекурсию. 


Наследование форм



    Наследование форм воплощает лучшие возможности повторного использования форм Use и Copy. При копировании вы создаете дубликат формы и добавляете в него необходимые компоненты и код. Неудобство этого метода состоит в том, что изменения не вносятся в шаблон. При использовании Use изменения вносятся не только в шаблон, но и во все объекты в других проектах.


    Наследование позволяет создать множество экземпляров шаблона, которые могут отличаться один от другого, как при использовании Copy. Оно так же автоматически вносит изменения в объект хранилища, как и при использовании Use.


 



Настройка IDE для отладки



Для работы со встроенным отладчиком Delphi 4 его интегрированная среда разработки (IDE) предлагает целую серию установок, большинство из которых вам лучше не трогать, а оставить, как есть (по умолчанию). Однако если вы все-таки решили изменить установки, выберите команду Tools/Options и в появившемся диалоговом окне Environment Options щелкните на вкладке Preferences (она показана на рис 2.5)


    Ниже перечислены опции вкладки Preferences и их функции.

Integrated Debugging. Позволяет включать и отключать встроенный отладчик. Если вы отключите отладчик, отладочные команды в меню Run станут недоступными.

Совет: Если у вас возникли проблемы при запуске приложения из интегрированной среды, возможно, это вызвано конфликтом встроенного отладчика с другими приложениями, запущенными в системе. Попробуйте отключить встроенный отладчик и, если это поможет, будьте уверены — проблема кроется в одном из уже запущенных в системе приложений. Лучшим решением будет перезагрузка и последующий запуск только абсолютно необходимых приложений.

Рис. 2.5. Использование вкладки Preferences для настройки интегрированного отладчика Delphi.

Step Program Block. Эта опция определяет, должен ли отладчик останавливаться перед началом выполнения основного блока begin. . . end при трассировке программы. Обычно данная опция отключена, и включать ее имеет смысл при добавлении кода в основной блок программы либо при отладке консольного приложения.

Hide Designers on Run. Когда эта опция включена, окно Object Inspector и формы, использующиеся при разработке приложения, перед запуском программы на выполнение закрываются. Отключение опции позволяет запускать программу быстрее, но эффект перекрывается используемыми незакрытыми ресурсами приложения. Впрочем, будет ли выбрана эта опция, зависит от пользователя.

Break on Exception. При включенной опции IDE всегда перехватывает исключительные ситуации и выводит окно сообщения, даже если в программе исключительная ситуация обрабатывается блоком try. . .except. Включение этой опции упростит отладку, так как выводимые сообщения при этом будут более информативными, чем сообщения обработчика, установленные по умолчанию (сравните рис. 2.6 и 2.7). Помимо этого, IDE размещает окно редактора поверх остальных и выделяет строку, вызвавшую исключительную ситуацию.


 


Рис. 2.6. Сообщение об исключительной ситуации при включенной опции Break on Exception

 


Рис. 2.7. Сообщение об исключительной ситуации, выводимое обработчиком по умолчанию

 

Совет: Конечно, опция Break on Exception полезна, но может привести в растерянность новичка в Delphi, особенно когда сообщается об исключительной ситуации, которую должен обработать блок try. . .except. Вы можете либо отключить эту опцию, либо запустить приложение не из среды Delphi, чтобы увидеть его работу глазами конечного пользователя.

  Minimize on Run Опция сворачивает окно IDE при запуске приложения Подобно опции Hide Designers on Run, ее установка зависит исключительно от личных предпочтений программиста

    На странице Display диалогового окна Environment Options есть еще одна установка— опция Visible Gutter. Она включает или отключает отображение серой вертикальной полосы, расположенной слева от окна редактирования (рис. 2.8), на которой мнемоническими значками отображается отладочная информация


Невидимые компоненты



    Не каждый компонент виден на форме во время запуска программы. Например, размещение на форме компонента MainMenu приводит к появлению в разра-батываемом приложении меню, но соответствующая пиктограмма во время запуска программы не отображается. Компоненты, представляющие диалоговые окна общего назначения, вообше никак не визуализируются во время работы программы. Размеры невидимого компонента в процессе разработки не изменяются — он всегда отображается в виде пиктограммы.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 



Объекты ActiveX в среде DAX



Ниже показана иерархия классов среды DAX, которые поддерживают объекты СОМ, типизированные объекты СОМ, серверы автоматизации, элементы управления ActiveX и формы ActiveForm.

    TComObject
        TTypedComObject
            TAutoObject
                TActiveXControl

    TCustomForm
        TActiveForm

    Класс TCustomForm вместо класса TForm использован в качестве предка класса TActiveForm, так как в TCustomForm включены только свойства и методы, уместные для формы ActiveX.



Обработка событий TApplication



Поскольку при создании TApplication недоступен, установка его обработчика события затруднена из-за невозможности использования инспектора объектов (Object Inspector).


    Сначала опишем обработчик события. Поскольку событие распознается и запускается объектом, обработчик должен быть методом объекта. Он также должен соответствовать соглашению о вызовах события, которое обычно описано в системе справки. Например, из файлов справки можно узнать, что событие OnActivate типа TNotifyEvent является наиболее общим типом. Его описание его выглядит так:

    TNotifyEvent = procedure (Sender: TObject) of Object;

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


    Создадим новое приложение и модифицируем описание TForm1.

        type


            TForm1 = class(TForm)


            private


                {Закрытые объявления.}


                procedure OnActivateHandler(Sender: TObject);


            public


                {Открытые объявления.}


            end;

    Описание обработчика как protected не несет особой нагрузки и принято по умолчанию. Важно лишь, чтобы он был методом класса.


    Теперь, когда мы описали обработчик, определим его. Добавьте следующий код в раздел implementation вашего модуля.

    procedure TFormI.OnActivateHandler(Sender: TObject);


    begin


        {Код вашего обработчика.}


    end;

Совет: Определение процедуры или функции не требует перечисления списка параметров, так как он был дан при описании. Вы можете его повторить для повышения удобочитаемости и ясности программы.


    Наконец, назначим обработчик событию. Обычно это выполняется в событии OnCreate главной формы. Измените обработчик события OnCreate класса Tform1 следующим образом.

    procedure TFormI.FormCreate(Sender: TObject);


    begin


        Application.OnActivate:= OnActivateHandler;


    end;



Окно Call Stack



В этом окне представлен список всех функций и процедур, вызванных к моменту достижения точки выполнения и работа которых приостановлена. Для открытия этого окна, показанного на рис 2.19, используйте команду View/Call Stack.

Рис. 2.18. Использование окна Modules для вывода списка модулей, используемых приложением.

Рис. 2.19 Использование окна Call Stack для определения всех вызванных функций и процедур.

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



Окно CPU (дизассемблер)



    Окно CPU предоставляет возможность увидеть работу приложения на уровне языка ассемблера.

Те, кто использовали отладчик Turbo Debugger for Windows, должны знать возможности, предоставляемые таким окном. Эффективное его использование предполагает знание ассемблера Intel x86 и архитектуры процессора, так что, если вы не вполне уверенно себя чувствуете, можете пропустить этот раздел.


    Окно CPU требуется крайне редко, но если в нем возникла необходимость, значит, это действительно необходимость. Это — ultima ratio, последний довод, и используется он в безвыходных положениях, когда обычная трассировка кода не позволяет найти, понять и исправить ошибки. Только в таких случаях окно CPU и проход по ассемблерным инструкциям может приподнять завесу над причиной возникновения ошибок.


Чтобы использовать окно CPU необходимо его включить (по умолчанию оно отключено). Для этого придется использовать программу RegEdit из поставки Windows 95 (Windows NT). Запустите RegEdit и пробирайтесь по иерархическому дереву папок. Сначала откройте папку HKEY_CURRENT_USER. Во вложенной ветви зайдите в папку Software, затем — в Borland, Delphi и, наконец, в 4.


    Одна из папок называется Debugging. Щелкните на ней и, когда она откроется, появится список пар Имя/Данные в окошке справа. Добавьте новое значение с именем EnableCPU и значением 1.


    При следующем запуске Delphi вы увидите новый подпункт меню View/CPU Window.


    Для вывода окна выберите View/CPU Window.

Перечислим панели

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


Register pane. В панели регистров отображается содержимое 16 регистров процессора. Значения регистров, изменившиеся в результате выполнения последней операции, выделены красным цветом.

Flags pane. Панель флагов показывает состояние 14 флагов процессора. Установленный флаг представляется значением 1, сброшенный флаг значением 0. В зависимости от процессора некоторые флаги могут быть недоступными.

Stack pane. Панель стека показывает содержимое стека приложения. Вы можете изменять представление содержимого стека с помощью контекстного меню.

Data pane. По умолчанию в панели данных выводится содержимое глобального сегмента данных приложения. Ее вид можно изменить так же, как и вид панели стека.

    Каждая из панелей в окне CPU имеет собственное контекстное меню. Вы можете поэкспериментировать с пунктами меню и получить более полное представление о возможностях манипулирования панелями.


Окно Modules



    В окне Modules отображаются все модели (ЕХЕ-файл вашего приложения и все используемые динамические библиотеки), которые располагаются в адресном пространстве приложения. В него входят непосредственно подключенные DLL и библиотеки, подключенные через другие библиотеки, а также библиотеки, загруженные операционной системой. Чтобы увидеть это окно, изображенное на рис 2.18. выберите команду View/Modules. В окне информация выводится в трех столбцах Name (имя модуля), Address

(адрес начала кода модуля) и Path (полный путь каталога, из которого был загружен модуль). Информация о каталоге может быть важна, если возможна загрузка модуля не из того каталога, из которого ожидалась, например, в более старой версии. Информация об адресе обычно используется при отладке в окне CPU.



Окно состояния подзадач.



Окна Thread Status, Modules и Call Stack предоставляют дополнительную информацию, которая может быть полезна при отладке приложения.


    В окне Thread Status перечислены все активные подзадачи текущего процесса. Для просмотра состояния подзадач выберите команду View/Threads, и на экране появится окно Thread Status (рис 2.17).


 

Рис 2.17. Использование окна Thread Status для просмотра атрибутов подзадач в приложении

    В четырех колонках окна представлена следующая информация:

Thread ID. Уникальный идентификатор подзадачи, присвоенный ей операционной системой.

State. Состояние подзадачи, обычно — Running или Stopped. Если ваше приложение запущено, но ожидает ввода от пользователя, состояние выводится как Runnable.

Status. Статус подзадачи может иметь одно из четырех значений. Breakpoint означает, что поток остановлен в точке останова. Stepped— подзадача находится в режиме пошагового выполнения. Faulted— остановка подзадачи из-за исключительной ситуации и Unknown — статус неизвестен.

Location. В этой колонке выводится строка исходного кода, соответствующего текущей точке выполнения подзадачи. Если отладчик не в состоянии определить строку исходного текста, выводится 32-битовый адрес точки выполнения.

    Если вами разработано приложение с несколькими подзадачами, и вы хотите отладить одну из подзадач, можете сделать ее основной с помощью окна Thread Status. Выберите подзадачу, которою вы хотите сделать текущей, и щелкните на ней правой кнопкой мыши. Выберите из контекстного меню команду Make Current. При этом фокус выполнения будет передан выбранной подзадаче, и вы сможете отлаживать ее как основную задачу.
    В контекстном меню окна содержатся две команды — View Source и Go to Source. Они могут пригодиться для того, чтобы проследить за точкой выполнения другой подзадачи без передачи ей фокуса.



OLE Automation



    Вариантные переменные удобно применять для изменения свойств объектов OLE Automation и вызова методов этого объекта. Чтобы инициировать эту возможность, необходимо подключить модуль OleAuto.
Синтаксис вызова метода или обращения к свойству объекта OLE Automation такой же, как вызова из созданного класса. Есть, однако, несколько важных отличии. Во-первых, вызов метода объекта OLE Automation происходит по схеме позднего связывания, т.е. компилятор не проверяет, существует ли данный метод и правильно ли определены типы параметров. Для компилятора приемлемы любой идентификатор метода и любое число параметров разных типов. А это означает, что при выполнении вызванного таким образом метода может произойти ошибка.
    Что же касается идентификаторов методов объекта OLE Automation, то они могут содержать любые алфавитные символы из международного набора, в том числе а, ь и ш.
 
 
 
 
 
 
 
 
 
 
 
  



OnActivate и OnDeactivate



    Эти события оповещают программу об изменении свойства Active.



OnActiveControlChange



Это событие возникает при передаче фокуса ввода от одного управляющего элемента к другому. Свойство


ActiveControl обновляется непосредственно перед вызовом события. Вы можете использовать событие, например, для вывода текста подсказки в строке состояния.

    procedure TFormI.ActiveControlChangeHandler(Sender: TObject);


    begin


        if (not Application.Terminated) then


        pnlStatus.Caption:= ActiveControl.Hint;


    end;

    Проверка связана с тем, что событие генерируется и при закрытии приложения, а при этом обращение к уже уничтоженному объекту вызовет исключительную ситуацию.



OnActiveFormChange



    Событие генерируется при создании новой формы или передаче фокуса ввода от одной формы к другой. Обычно это событие используется в MDI-приложениях для обновления доступных функций меню и кнопок-ускорителей. Ниже приведен пример из шаблона MDI-приложения.

    procedure TMainForm.UpdateMenuItems(Sender: TObject);


    begin


        FileCloseItem.Enabled:= MDIChildCount 0;


        FileSaveItem.Enabled:= MDIChildCount 0;


        FileSaveAsItem.Enabled:= MDIChildCount 0;


    end;

    Процедура UpdateMenuItems назначена в качестве обработчика событию OnActiveFormChange в обработчике


OnCreate.

    procedure TMainForm.FormCreate(Sender: TObject);


    begin


        Application.OnHint:= ShowHint;


        Screen.OnActiveFormChange:= UpdateMenuItems;


    end;



OnException



Событие вызывается при необработанной исключительной ситуации.



OnHint



    Событие генерируется при перемещении указателя мыши над объектом— потомком TControl, если его свойство Hint равно значению, которое отличается от пустой строки.



Onldle



Событие генерируется, когда приложение ожидает ввода и не занято обработкой события. Обычно оно используется для выполнения фоновых задач наподобие загрузки базы данных или обработки изображения.


    Обработчик получает логический параметр Done, по умолчанию равный True. Если вы оставляете его равным True, обработчик не запустится до тех пор, пока не будет получено и обработано очередное сообщение. Если вы установили Done равным False, обработчик будет запускаться во время ожидания сообщения.


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


    Ниже приведен код использования обработчика для вывода текущего времени в объекте TPanel.

    procedure TFormI.OnIdleHandler(Sender: TObject; var Done: Boolean);


    begin


        pnlTime.Caption:= TimeToStr(Now);


    end;


 



Отладка DLL



В предыдущих версиях Delphi для отладки библиотек динамической компоновки требовался внешний отладчик (Turbo Debugger for Windows). Delphi 4 внесла возможность отладки DLL в список своих возможностей. Windows не может загрузить DLL без предварительной загрузки использующего ее ЕХЕ, поэтому вам с начало придется набросать простенькую программку, использующую интересующую вас DLL. В главном меню выберите команду Run/Parameters для вывода диалогового окна Run Parameters. Если текущий проект— DLL (DPR-файл начинается ключевым словом library, а не program), поле Host Application будет доступно, и в нем вам надо либо ввести имя использующей DLL программы, либо выбрать его с помощью кнопки Browse.


    После выбора приложения запуск и отладка DLL становятся обычной рутинной работой со всеми возможностями, используемыми при отладке программ, — установкой точек останова, просмотром значений переменных и т.д.


    Точно так же вы будете отлаживать и свои компоненты ActiveX, и объекты автоматизации OLE.



Отладочная и коммерческая версии кода



    Те, кто участвовали в "полевых испытаниях" (известных как бета-тестрирование) коммерческих программ, наверняка обратили внимание, что такие версии программ более медлительны, гораздо более "разговорчивы" и размером побольше окончательных версий программ. Может быть, разработчик спешил и выпустил "сырой" продукт, который будет улучшать перед выпуском окончательного варианта? Так тоже бывает, но главная причина в другом: в бета-версии содержится тестовый и отладочный коды, используемые разработчиком для проверки корректности работы программы.


    Delphi позволяет очень легко внести тестовый и отладочный коды в приложение. Например, вы хотите создать приложение работы с базой данных и использовать быстрый, но, возможно, несколько рискованный алгоритм сортировки данных. Как же убедиться в корректности его работы? Один из путей — использовать в приложении два алгоритма одновременно (быстрый, но рискованный, и медленный, но проверенный), затем сравнить результаты работы обоих алгоритмов. Конечно же, этот вариант используется только в бета-версии, и после всестороннего тестирования, если все работает отлично и без сбоев, в конечной версии продукта останется только быстрый (и после такого тестирования — уже не рискованный) метод сортировки.


Для этого вам вовсе не надо использовать два разных текста программ — воспользуйтесь возможностью условного компилирования. Вы можете определить символ (я обычно использую Debug, но вы свободны в вашем выборе) для переключения между коммерческой и отладочной версиями вашего кода с использованием директив $IFDEF, $IFNDEF, $ELSE и $ENDIF. Вот пример использования "медленного" алгоритма в отладочной версии.

DataSet:= GetData; //Получение данных для сортировки.


    {$ifdef Debug}


    TestResultSet:= Sort_Tortoise(DataSet); //Медленно и надежно.


    {$endif}


    ResultSet:= Sort_Hare(DataSet); //Быстро и рискованно.



    {$ifdef Debug}

    if not CompareData(ResultSet, TestResultSet) then

        //Результаты совпали?

    Raise Exception.Create('Сортировка в DataSorting некорректна');

    {$endif}

    Если определен символ Debug, код принимает следующий вид.

DataSet:= GetData; //Получение данных для сортировки.

    TestResultSet:= Sort_Tortoise(DataSet); //Медленно и надежно.

    ResultSet:= Sort Hare(DataSet); //Быстро и рискованно.

    if not CompareData(ResultSet, TestResultSet) then

        //Результаты совпали?

    Raise Exception.Create('Сортировка в DataSorting некорректна');

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

DataSet:= GetData; //Получение данных для сортировки.

    Re5ultSet:= Sort_Hare(DataSet); //Быстро и рискованно.

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

Выберите команду Project/Options и в диалоговом окне Project Options, во вкладке Directories/Conditionals, введите символ в поле Conditional defines.

На рис 2.1 показано определение двух символов (Debug и Alpha) Щелкните на кнопке ОК для подтверждения вашего ввода

Совет: Изменив символы условной компиляции, перекомпилируйте проект с помощью команды Project/Build All для того, чтобы учесть внесенные изменения.

    Другой метод определения символа условной компиляции — вставить в ваш исходный код директиву.

    {$define Debug}

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



Для этого используйте в файле директиву

    {$undef Debug}

    Она отключает действие директивы Debug до тех пор, пока не встретится соответствующая директива $DEFINE или  конец текущего файла.

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

    Помимо директив условной компиляции, есть еще немало других директив, которые могут использоваться в отладочной версии приложения. Я говорю "могут", поскольку эти директивы могут внести определенные различия в код коммерческой и тестовой версий, так что будьте осторожны при их применении. Эти опции перечислены во вкладке Compiler диалогового окна Project Options, приведенного на рис 2.2

 


Рис. 2.1. Использование диалогового окна Project Options для определения символов условной компиляции



Рис 2.2. Использование диалогового окна Project Options для изменения отладочных опций компилятора

    Ниже приведено описание этих опций.

Optimization. Эта опция управляет оптимизацией компилятора. Рекомендуется оставить эту опцию включенной и выключать ее, если вы полагаете, что оптимизация вносит ошибки в вашу программу. Управлять оптимизацией локально вы можете с помощью директив компилятора $0+ и $0-.

Stack Frames. Если эта установка включена, компилятор всегда включает в функцию код для генерации кадра стека, даже если код не использует стек. Как и в случае оптимизации, вам вряд ли стоит изменять эту установку. Локальные директивы компилятора— $W-t и $W-.

Range Checking. Проверка диапазона перехватывает ошибки, вызванные выходом за пределы массива или строки. Однако дополнительный код сдерживает выполнение программы и, по всей видимости, вы отключите эту опцию в коммерческой версии. Директивы компилятора для включения и отключения проверки— $R+ и $R-.

Assertions (С). Эта опция более полно описана в следующем разделе. Использование данного типа проверок позволяет быстро и просто добавить проверки в код Естественно, в коммерческой версии вы захотите отключить эту возможность. Директивы компилятора— $С+ и $С-.

Overflow checking (Q). Проверка на переполнение позволяет выяснить, не является ли результат выполнения целочисленной операции слишком большим для размещения его в переменной. Подобно опции Range Checking, данная опция полезна только при отладке, и в коммерческой версии, как правило, отключается. Директивы компилятора— $Q+ и $Q-.

    Отладочная версия вашего кода, вероятно, будет больше по размеру и медленнее коммерческой версии. Поэтому не передайте случайно конечному пользователю отладочную версию!


Packages



    Вкладка Packages позволяет определить, какие пакеты доступны для использования при разработке приложения, и прилинковать их при создании результирующего файла.


Группа Design packages предоставляет список зарегистрированных пакетов, которые можно выбрать для использования в приложении.


    Группа Runtime packages дает возможность определить, какие пакеты компоновщик будет использовать при построении выходного файла. По умолчанию опция Build with runtime packages отключена, а это означает, что все объекты из VCL будут скомпонованы с вашим приложением. Включение опции означает, что ваше приложение будет разделять с другими приложениями Delphi одну копию пакетов.


 


 


 


 


 


 


 
 
 
 
 
 
 
 
 
 



Параметр Sender



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



Перечисления (Enum) в библиотеках типов



Перечисления в библиотеках типов практически не отличаются от перечислений языка Object Pascal. Перечисление в библиотеке типов — это коллекция связанных констант, используемая как тип данных во всех остальных элементах библиотеки для определения свойств или методов. Кроме того, в зависимости от среды программирования константы перечисления могут использоваться с объектом ActiveX внутри среды программирования. В следующих двух разделах рассматривается назначение вкладок Attributes и Members в описании перечислений.



Перечислимые типы



Type enum type = (first value, value2, value3, last value);
    Обычно данные перечислимых типов содержат дискретные значения, представляемые не числами, а именами. Тип Boolean— простейший перечислимый тип в Object Pascal. Булевы переменные могут принимать два значения, выражаемые именами True и False, а сам тип определен в Object Pascal так, как будто он объявлен следующим образом:
    Type Boolean = (False, True);
    С помощью типа Boolean в Object Pascal выполняются сравнения, большинство же перечислимых типов — это просто списки уникальных имен или идентификаторов, зарезервированных с конкретной целью. Например, можно создать тип MyColor (мой цвет) со значениями myRed, myGreen и myBlue (мой красный, мой зеленый, мой синий). Это делается совсем просто:
    Type MyColor = (myRed, myGreen, myBlue);
    В этой строке объявлены четыре новых идентификатора: MyColor, myRed, myGreen и myBlue. идентификатором MyColor обозначен порядковый тип, следовательно, в синтаксисе Object Pascal можно применять этот идентификатор везде, где разрешены перечислимые типы. Остальные три идентификатора— это значения типа MyColor. Подобно символьным и булевым типам перечислимые не являются числами, и использовать их наподобие чисел не имеет смысла. Однако перечислимые типы относятся к порядковым, так что значения любого такого типа упорядочены. Идентификаторам в списке присваиваются в качестве порядковых номеров последовательные числа. Первому имени присваивается порядковый номер 0, второму — 1 и т.д.


Совет: В С и C++ есть тип enema, аналогичный перечислимому типу Delphi. Но в этих языках можно произвольно присваивать идентификаторам постоянные значения. В Delphi же соответствие имен и их значений фиксиро-вано: первому имени присваивается значение 0, каждому последующему — на единицу больше. В С тип enum применяется лишь как средство быстрого определения набора целых постоянных. В C++ объявленные в перечислимом типе идентификаторы можно присваивать только переменным того же типа.



Поддиапазонные типы



    Переменные поддиапазонного типа содержат информацию, соответствующую некоторому pаданному диапазону значений исходного типа, представляющего любой порядковый тип, кроме поддиапазонного. Синтаксис определения поддиапазонного типа имеет следующий вид:

    Type subrange type = low value...high value;

    Поддиапазонные переменные сохраняют все особенности исходного типа. Единственное отличие состоит в том, что переменной поддиапазонного типа можно присваивать только значения, входящие в заданный поддиапазон. Контроль за соблюдением этого условия задается командой проверки диапазона (range checking).
    Необходимость явно определять поддиапазонный тип возникает нечасто, но все программисты неявно применяют эту конструкцию при определении массивов. Именно в форме поддиапазонной конструкции задается схема нумерации элементов массива.



Поиск по заголовкам окон



    При создании экземпляра окна Windows требует зарегистрировать имя класса окна (window class name). Delphi использует класс формы в качестве имени класса окна, например, когда Delphi создает экземпляр Form1 класса TForm1, TForm1 используется в качестве имени для регистрации окна Form1. Каждая форма имеет свойство Caption, известное как заголовок окна (window title). Эти два параметра позволяют искать окно с помощью функции Windows API FindWindow, возвращающей дескриптор найденного окна.


    Эту функцию нельзя вызывать из класса TForm1, так как к тому времени окно уже будет создано, и вы окажетесь в глупом положении, найдя сами себя. Вот код, который должен находиться в файле проекта.

begin


        Application.Initialize;


        if FindWindow('TFormi','Formi') о 0 then Application.Terminate;


        Application.Create Form(TForm1,Form1);


        Application.Run;


     end.

    Поскольку вы используете функцию Windows API, проследите, чтобы был подключен модуль Windows.


Если вы запускаете это приложение из Delphi, учтите, что Form Designer уже создал такое окно, и вы всегда сможете его найти. Это приложение следует запускать отдельно, закрыв Delphi.


    Изменив свойство Caption или Name, вы рискуете не найти своего окна и придется повозиться с кодом программы, чтобы отследить эти изменения. Может возникнуть ситуация, когда простое совпадение приведет к тому, что окно будет найдено в совсем другом приложении, которое будет опознано как свое.



Порядковые типы



Из простых типов данных порядковые — самые простые. В этих типах информация представляется в виде отдельных элементов. Связь между отдельными элементами и их представлением в памяти определяет естественные отношения порядка между этими элементами. Отсюда и название порядковые.
    В Object Pascal определены три группы порядковых типов и два типа, определяемых пользователем. Группы — это целые, символьные и булевы типы. Порядковые типы, задаваемые пользователем, — это перечисления и поддиапазоны.
    Все значения любого порядкового типа образуют упорядоченную последовательность, и значение переменной порядкового типа определяется его местом в этой последовательности. За исключением переменных целых типов, значения которых могут быть как положительными, так и отрицательными, первый элемент любого порядкового типа имеет номер 0, второй элемент — номер 1 и т.д. Порядковый номер целого значения равен самому значению. Отношение порядка определяет общие для данных всех порядковых типов операции. Некоторые стандартные функции такого вида встроены в Object Pascal. Они представлены в табл. 1.1.
 

    Для всех порядковых типов в Object Pascal существует операция задания типа для преобразования целых значений в значения соответствующих порядковых типов. Если Т — имя порядкового типа, а Х — целое выражение, то Т (X) воз-вращает значение Т с порядковым номером X.


Совет: Программисты, работающие на С и C++, для приращения или уменьшения значений переменных привыкли заметку   использовать операторы "++" и "--", возвращающие следующее и предыдущее значения. Программисты Delphi всегда разбивают эти операции на более простые составляющие с помощью функций Pred, Succ. Dec и Inc.


  Таблица 1.1. Операции над порядковыми типами

 

Операция  Описание
Low (T) Минимальное значение порядкового типа Т
High(T)  Максимальное значение порядкового типа Т
Ord(X)  Порядковый номер значения выражения порядкового типа. Для целого выражения — просто его значение. Для остальных порядковых типов Ord возвращает физическое представление результата выражения, трактуемое как целое число. Возвращаемое значение всегда принадлежит одному из целых типов
Pred(X) Предыдущее по порядку значение. Для целых выражений эквивалентно Х-1
Succ(X)  Следующее по порядку значение. Для целых выражений эквивалентно Х+1
Dec(V)  Уменьшает значение переменной на 1. Эквивалентно V := Pred(V)
Inc(V)  Увеличивает значение переменной на 1. Эквивалентно V := Succ(V)

 



Пошаговая отладка



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


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


    Интегрированная среда Delphi предоставляет пользователю несколько команд пошаговой отладки доступных в меню Run (рис 2.10)


 

 

Рис 2.10 Используйте меню Run для выполнения команд отладки

    Ниже перечислены команды отладки.

Run. Выбор этой команды запускает приложение на выполнение в обычном режиме. Вы можете использовать ее как для запуска приложения, так и для продолжения его работы после какого-либо прерывания выполнения (например, по точке останова). Если включена опция Break on Exception, используйте команду для продолжения работы после получения сообщения об исключительной ситуации

Step Over. Когда точка выполнения находится на строке содержащей вызов процедуры или функции, используйте эту команду для выполнения строки, включая вызовы в один шаг, без прохождения отдельных строк вызываемых функций. Точка выполнения перемещается при выполнении на следующую строку

Trace Into. В отличие от предыдущей команды, эта опция отработает пошаговую отладку вызываемых процедур и функций. Другими словами, если, например, в строке вызывается некая процедура, то при выполнении этой команды точка выполнения перейдет на первую строку процедуры. Однако если в строке нет таких вызовов, значит, последние две команды идентичны. Будьте осторожны при пошаговой трассировке обработчика события OnPaint. Поскольку при пошаговой отладке окно редактора размещается поверх других окон, требуется перерисовка окна приложения, для чего вызывается обработчик события OnPaint... Вы попадаете в замкнутый круг, точнее— в бесконечный цикл вызовов одного и того же обработчика. Тем не менее, стоит лишь проследить, чтобы окна приложения и редактора не перекрывались, и проблема разрешится сама собой.


Trace to Next Source Line. Иногда ваш код вызывает другой код косвенно, например, при вызове функции, которая запускает обработчик события, или при вызове функции Windows API, которая, в свою очередь, запускает функцию косвенного вызова. Поскольку такие вызовы косвенные, отладчик не видит вызова и не отслеживает пошагового выполнения таких вызовов.

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

I Run to Cursor. Зачастую вам вовсе не хочется в поисках ошибки, местоположение которой с какой-то точностью вам известно, пошагово добираться до нужного места через сотни, а то и тысячи строк кода. В таком случае просто поместите курсор на нужную вам строку программы в окне редактирования и используйте команду Run to Cursor. Эти действия эквивалентны временному помещению точки останова в необходимую вам строку программы, и после выполнения предшествующего строке кода работа программы приостанавливается. Если вы пытаетесь выполнить программу до позиции курсора, который находится в строке, не содержащей отладочной информации, вы получите сообщение об ошибке, показанное на рис. 2.11.

   


Рис. 2.11. Это сообщение о том, что вы пытаетесь остановить выполнение программа на строке, не содержащей отладочной информации.

Show Execution Point. Эта команда заставляет среду разработки открыть окно редактора и показать выполняемую в настоящее время строку программы. Она полезна в случаях, когда вы, например, закрыли или свернули окно редактора во время отладки (обычно при нормальном состоянии окна отладчик делает это автоматически).

Program Pause. Выбор этой команды немедленно останавливает выполнение программы. Она особенно полезна при зацикливании программы.

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

    Многие команды имеют связанные с ними комбинации клавиш, например <F9 для Run. Однако назначения клавиш могут быть изменены во вкладке Editor диалогового окна Options. Например, команде Step Over назначена клавиша <F8, но при выборе назначений клавиш в стиле редактора BRIEF назначенной комбинацией клавиш становится <Ctrl+Fl1. Вы можете увидеть назначенные клавиши непосредственно в меню Run, как показано на рис. 2.10. Помимо этого, на панели инструментов есть кнопки, вызывающие некоторые из этих команд (вы имеете возможность также удалить некоторые из них или добавить новые).


Position



Position — это свойство перечислимого типа, определяющее размещение формы при запуске приложения.


Значение по умолчанию (poDesigned) заставляет форму выводиться в месте, определенном при разработке приложения. Положение и размер формы при этом берутся из свойств Left, Top, Height и Width. Поскольку вы не можете знать заранее, в какой системе будет запущено ваше приложение, может оказаться, что на мониторе с низким разрешением при использовании этого значения свойства будет видна только часть формы.


    Более полезно значение poScreenCenter, использующее заданные вами при создании приложения значения Width и Height, но оно так изменяет Left и Тор, что форма выводится в центре экрана.


    Если вы установите Position равным poDefault, Windows автоматически установит размеры и положение формы, но вы при этом лишитесь возможности контролировать ее размеры. Можете создать форму размером 200х200, которая будет выведена как 640х480. Из-за этого, в частности, не допускается применение данного значения для MDI-форм.


    Значение poDefaultPosOnly более полезно, так как оно автоматически определяет расположение формы, но не ее размеры (а потому рекомендуется для MDI-форм, в которых требуются определенные размеры дочерних форм).


    Последнее значение свойства (poDefaultSizeOnly) автоматически определяет размер, но не расположение формы. Это значение может использоваться там, где важно положение формы на экране, а не ее размер.


    Хотя свойство Position позволяет определить, каким образом будет выводиться форма, профессионально сделанные приложения сами запоминают свое расположение на экране и при следующем запуске выводятся в той же позиции и с тем же размером. Это осуществимо, например, благодаря записи положения окна в Registry или в INI-файле, в том же каталоге, где находится приложение. Обычно сохранение позиции и размеров экрана выполняется в самый последний момент — при уничтожении формы.

    procedure TForml.FormDestroy(Sender: TObject);



    var

        sAppPath: String;

        iniSettings: TINIFile;

    begin

        {Получить путь к ЕХЕ-файлу приложения.}

        sAppPath:= ExtractFilePath(Application.EXEName);

        {Создаем объект TINIFile.}

        iniSettings:= TINIFile.Create(sAppPath + 'SETTINGS.INI');

        try

            {Записываем свойства в INI-файл.}

            iniSettings.Writelnteger(Name,'Left',Left);

            iniSettings.Writelnteger(Name,'Top',Top);

            iniSettings.Writelnteger(Name,'Width',Width);

            iniSettings.Writelnteger(Name,'Height',Height);

        finally

            iniSettings.Free;

        end;

    end;

Совет: Для компиляции примера не забудьте включить в раздел uses модуль INIFiles.

    После выполнения кода ваш INI-файл будет содержать нечто вроде

 

   

[Form1]

    Left=108

    Тор=174

    Width=540

    Height=165

    Заметьте, что для строки раздела используется свойство Name вашей формы.

    Восстановить положение формы на экране немного сложнее (главным образом из-за того, что следует отработать ситуацию, когда INI-файла нет).

    procedure TFormI.Create(Sender: TObject);

    const




        CNOTFOUND = -1;

    var

        sAppPath: String;

        iniSettings: TINIFile;

        liValue: Longint;

    begin

        {Получаем путь к ЕХЕ-файлу приложения.}

        sAppPath:= ExtractFilePath(Application.ExeName);

        {Создаем объект TINIFile.}

        iniSettings:= TINIFile.Create(sAppPath + 'SETTINGS.INI');

    try

        { Пытаемся считать значение Left.}

        liValue:= iniSettings.Readlnteger(Name,'Left',cNOTFOUND);

        {Проверяем, считано ли значение.}

        if liValue = cNOTFOUND then

        begin

            {Свойства в INI-файле не найдены — центруем форму.}

            Left:= (Screen.Width - Width) div 2;

            Top:= (Screen.Height - Height) div 2;

        end

        else

        begin

            {Считываем значения из INI-файла.}

            Left:= iniSettings.Readlnteger(Name,'Left',Left);

            Top:= iniSettings.Readlnteger(Name,'Top',Top);

            Height:= iniSettings.Readlnteger(Name,'Height',Height);

            Width:= iniSettings.Readlnteger(Name,'Width'.Width);

        end;

    finally

        iniSettings.Free;

    end:

end;


Построение интерфейса



    Обычно первым шагом построения программы является создание интерфейса. Не будем отступать от традиций,

и выполним следующие действия.

    1. Выберите команду File/New Application, и появится пустое приложение.


 

Совет: Delphi по умолчанию создает именно SDI-приложение. Однако хранилище объектов предоставляет возможность назначить новый шаблон проекта по умолчанию.

    2. Установите следующие свойства форм.


        Свойство                                          Значение


        Caption                                              Image Viewer
        Name                                                    frmMain
        ShowHint                                                 True

    3. Поместите компонент TPanel в форму. Установите следующие его свойства.


        Свойство                                           Значение



        Align                                                        alTop
        Caption                                                       -

    4. Поместите три компонента TSpeedButton в TPanel и назовите их spbtnLoad, spbtnStretch и spbtnCenter. Установите следующие их свойства.

        Свойство                                          Значение

        spbtnLoad.Hint                                       Load
        spbtnLoad.Left                                          8
        spbtnLoad.Top                                          8
        spbtnStretch.AllowAlIUp                         True
        spbtnStretch.Grouplndex                            1
        spbtnStretch.Hint                                    Stretch
        spbtnStretch.Left                                       48
        spbtnStretch.Top                                        8
        spbtnCenter.AllowAlIUp                          True
        spbtnCenter.Grouplndex                             2
        spbtnCenter.Hint                                     Center
        spbtnCenter.Left                                         80
        spbtnCenter.Top                                          8



    5. Поместите еще одну TPanel в форму и установите следующие ее свойства.

        Свойство                                             Значение

        Align                                                       alClient
        Caption                                                        -

    6. Поместите компонент ТImage во вновь созданную ТPanel и установите следующие его свойства.

        Свойство                                             Значение

        Align                                                       alClient
        Name                                                      imgMain



    7. Добавьте в форму TOpenDialog со следующими свойствами.

        Свойство                                             Значение

        Filter                                                      Bitmaps (*.bmp)|*.bmp
        Name                                                     opndlgLoad
        Options                                                  [ofPathMustExist,ofFileMustExist]

    Delphi предоставляет вам множество значков для компонента TSpeedButton; они находятся в каталоге IMAGES\BUTTONS. Для нас вполне подойдут следующие установки свойств Glyph.

        Свойство                                             Значение




        spbtnLoad.Glyph                                    FLDROPEN.BMP
        spbtnStretch.Glyph                                 FONTSIZE.BMP
        spbtnCenter.Glyph                                 PICTURE.BMP

    Теперь самое время сохранить проект, выбрав в меню команду File/Save Project As. Сохраните Unit1

как Main, а проект — как EgSDIApp.


Повторное использование форм



    К этому моменту вы уже должны быть хорошо знакомы с объектно-ориентированной природой Delphi. Поскольку TForm представляет собой класс, он может повторно использоваться, расширяться и изменяться. Повторное применение форм поддерживается через шаблоны форм и наследование. Оба эти метода используют Object Repository


 



Преимущества наследования форм



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


  Выберите команду File/New Application, и появится пустое приложение.

 Закройте главную форму, окно которой озаглавлено Forml.

 Выберите команду File/New, и будет выведено диалоговое окно New Items.

 Щелкните на вкладке Dialogs, и будет выведена страница диалогов.

 Выберите стандартный (Standard) диалог с кнопками, выровненными вертикально по правой стороне.

 Выберите опцию Inherit.

 Щелкните на кнопке ОК, и Delphi выведет новую диалоговую форму OKRightDlg2.

 Выберите из меню View/Forms, и будет выведено диалоговое окно View Form.

 Выберите шаблонную форму OKRightDIg, щелкните на кнопке ОК, и Delphi выведет новую шаблонную форму, озаглавленную Dialog и расположенную точно поверх новой формы.

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


    Однако в обратном направлении изменения не передаются. Чтобы убедиться в этом, выполните следующие действия.

Выберите команду View/Forms, и появится диалоговое окно View Form.

Выберите OKRightDlg2 и щелкните на ОК.

Переместите OKRightDlg2 в нижнюю часть экрана.

    Ваш экран должен выглядеть примерно так, как на рис. 1.11.

Рис. 1.11 Изменение распространяются только в одном направлении - от родителей к потомкам

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



Пример консольного приложения



Лучший способ изучить консольные приложения— создать пресловутое "Hello, world!". Для создания его вручную сделайте следующее.

        1. Выберите команду File/New Application.


        2. Выберите команду File/Remove From Project, и появится диалоговое окно, Remove From Project, показанное на рис. 1.15.


        3. В проекте содержится один модуль формы. Выберете его и щелкните на кнопке ОК. Появится диалоговое окно Save changes to Unit1.pas?


         4. Щелкните на кнопке No, и форма будет удалена из проекта.


        Сохраните проект как EgConsoleHello.


 

Рис. 1.15. Диалоговое окно Remove From Project позволяет удалять модули и формы из проекта.

    Хотя мы создаем "бесформенное" приложение, оно все еще не является консольным и использует GUI, а значит, сравнимо по размеру с бронтозавром. Выберите команду View/Project Source, и в редакторе появится следующий текст.

    program EgConsoleHello;


    uses


        Forms;


        {$R *.RES}


    begin


        Application.Initialize;


        Application.Run;


    end;

    Этого слишком много, чтобы быть достаточным. Вы видите, что подключен модуль Forms, однако он не используется, поэтому данную строку можно удалить. Строки с Application используются для инициализации OLE-сервера и вывода главной формы. Поскольку мы не используем ни того, ни другого, удалите и эти строки. Последнее действие — объяснить компилятору, что мы хотим создать обычное, простое, незамысловатое консольное приложение. Этого можно достичь с помощью команды $APPTYPE. Код в результате будет выглядеть так.

    program EgConsoleHello;


        {$APPTYPE CONSOLE}


        {$R *.RES}


    begin


    end;

    Ax да! Мы же собирались вывести свое приветствие! Для этого добавьте между begin и end строку

    WriteLn ('Hello, world!');

    Сохраните, скомпилируйте и запустите проект из командной строки. Надеюсь, вам понравилось? И еще одно замечание — консольные приложения используют стандартные потоки ввода-вывода, а значит, вы можете использовать функции Read, ReadLn, Write и WriteLn.



Пример MDI-приложения



В этом разделе мы расширим возможности созданной ранее программы просмотра изображений.



Пример SDI-приложения



Для демонстрации SDI создадим простую программу просмотра изображения.
.



Процедуры обработки вариантных массивов



В табл. 1.9 перечислены стандартные процедуры и функции обработки вариантных массивов, определенные в модуле System.

Таблица 1.9. Процедуры и функции обработки вариантных массивов
  

Процедура/функция Описание
VarArrayCreate Создает вариантный массив с заданными пределами и типом
VarArrayDimCount Возвращает число измерений данного вариантного массива
VarArrayHighBound Возвращает верхний предел измерения вариантного массива
VarArrayLock Фиксирует вариантный массив
VarArrayLowBound Возвращает нижний предел измерения вариантного массива
VarArrayOf Возвращает вариантный массив с указанными элементами
VarArrayRedim Изменяет верхний предел вариантного массива
VarArrayUnlock Отменяет фиксацию вариантного массива
VarAsType  Преобразует вариантную переменную в указанный тип
VarCast Преобразует вариантную переменную в указанный тип и записывает значение
VarClear Сбрасывает значение вариантной переменной
VarCopy Копирует одну вариантную переменную в другую 
VarFromDateTime Возвращает вариантную переменную, содержащую переменную даты/времени 
VarIsArray Возвращает True, если вариантная переменная является массивом
VarIsEmpty Возвращает True, если вариантная переменная содержит Unassigned
VarIsNull  Возвращает True, если вариантная переменная содержит Null
VarToDateTime Преобразует вариантную переменную в значение даты/времени
VarType Преобразует вариантную переменную в указанный тип и записывает значение

 
    В табл. 1.10 перечислены типы значении, которые можно присваивать вариантным переменным, и вариантные типы результата.

Таблица 1.10. Вариантные типы
 

Тип выражения  Вариантный тип
Целый  varlnteger
Действительный, кроме Currency varDouble
Currency varCurrency
Строковый и символьный varString
Булев  varBoolean

    Вариантные переменные в отношении операции присвоения совместимы с элементарными типами данных Object Pascal (Integer, Real, String и Boolean). Все нужные преобразования Delphi выполняет автоматически. При необходимости конкретно указать, что вариантное значение надо интерпретировать как целое, действительное, строковое или булево, следует задать тип в форме TypeName (V), где TypeName — идентификатор соответствующего типа, V— выражение Variant. Задание типа изменяет только способ считывания значения из вариантной переменной, а не само значение внутри ее. Внутреннее же представление изменяется с помощью процедур VarAsType и VarCast.