0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

84
Д. Н. Лясин, С. Г.Саньков Основы программирования в среде C++Builder

Transcript of 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

Page 1: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

Д. Н. Лясин, С. Г.Саньков

Основы программирования в

среде C++Builder

Page 2: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ

ВОЛЖСКИЙ ПОЛИТЕХНИЧЕСКИЙ ИНСТИТУТ (филиал) ВОЛГОГРАДСКОГОГОСУДАРСТВЕННОГО ТЕХНИЧЕСКОГО УНИВЕРСИТЕТА

Д.Н. Лясин, С.Г.Саньков

Основы программирования в среде C++Builder

Учебное пособие

РПК «Политехник»Волгоград 2007

Page 3: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

УДК 004.056 Рецензенты Волжский филиал «Московский энергетический институт (техническийуниверситет)», доктор технических наук, профессор, заведующий кафедрой«Автоматизации технологических процессов» Шевчук В.П.

Волжский гуманитарный институт (филиал) Волгоградского государственногоуниверситета, доктор технических наук, заведующий кафедрой «Прикладнойматематики» Мирецкий И.Ю.

Лясин Д.Н., Саньков С.Г.Основы программирования в среде C++Builder. Учебное пособие./

ВолгГТУ, Волгоград, 2007. – 83 с.

ISBN – 5-230-04-900-6

В учебном пособии рассматриваются вопросы разработки приложений дляоперационной системы Windows в среде программирования C++Builder. Дан обзоросновных инструментов разработки приложений, рассмотрены особенностикомпонентного подхода к проектированию программ и визуальной технологиипрограммирования. Большое внимание уделено практическому аспекту разработкиприложений, дан обзор основных компонент C++Builder, приведены примеры ихиспользования для разработки приложений под ОС Windows с учетом особенностейработы операционной системы. Рассмотрены также способы разработкисобственных компонент. Предназначены для студентов, обучающихся по направлению 5528 "Инфор-матика и вычислительная техника" и специальности 2201 "Вычислительныемашины, комплексы, системы и сети" всех форм обучения в рамках курсов«Спецкурс по языкам программирования» и «Инструментальные средствапрограммирования».

Ил. 12. Табл. 5. Библиогр.: - 6 назв.

Печатается по решению редакционно-издательского совета Волгоградскогогосударственного технического университета

ISBN – 5-230-04-900-6

© Волгоградскийгосударственный технический

Университет, 2007

Page 4: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

3

Оглавление

1. Введение в C++Builder ………………………………….…………... 5 1.1. Эволюция систем программирования …………………………….. 51.2. Основные достоинства системы программирования C++

Builder…………………………………………………………………………… 7Вывод ……………………………………………………………………... 11

2. Состав системы программирования C++Builder ………..…………. 112.1. Панель инструментов и главное меню системы ………………….. 122.2. Палитра компонент ………………………………………………. 132.3. Инспектор объектов ………………...…………………….………… 142.4. Редактор форм ………………………..……………………………… 152.5. Редактор кода ……………….……………………………………….. 162.6. Окно дерева объектов ….……………………………………………. 172.7. Менеджер проекта ………….……………………………………….. 182.8. Хранилище объектов… …….……………………………………….. 19Вывод………………… ………….……………………………………….. 20

3. Проект приложения в C++Builder………………………………………… 20Вывод………………………………………………………………………. 28

4. Библиотека визуальных компонент С++Builder………………………... 284.1. Общие сведения о библиотеке VCL………………………………… 284.2. Иерархия классов VCL…………………………………….………… 34Вывод……………………………………………………………………… 47

5. Работа с формами в C++Builder…………………………………………… 475.1. Создание и уничтожение форм…………………………………….. 475.2. Модальный режим работы форм…………………………………… 535.3. Многодокументный интерфейс (MDI)……………………………... 55Вывод……………………………………………………………………… 57

6. Работа с клавиатурой и мышью в среде C++ Builder………………….. 586.1. Интерфейс работы с мышью в C++Builder………………………… 596.2. Интерфейс работы с клавиатурой в C++Builder…………………... 60

Page 5: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

4

6.3. Пример использования событий мыши и клавиатуры вC++Builder………………………………………………………………………. 61

Вывод………………………………………………………………………. 657. Графика в C++Builder………………………………………………………. 65

7.1. Основы графического интерфейса Windows……………………….. 657.2. Обзор графических компонент C++Builder………………………… 677.3. Компонент TCanvas…………………………………….…………. 687.4. Компоненты для работы с изображениями………………………… 72Вывод………………………………………………………………………. 74

8. Разработка компонент в C++ Builder……………………………………... 748.1. Процедура разработки компонента C++Builder…………………… 758.2. Определение свойств и событий компонента……………………… 77Вывод………………………………………………………………………. 81

Список литературы…………………………………………………………….. 82

Page 6: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

5

1. Введение в C++Builder

1.1. Эволюция систем программирования

Средства разработки приложений для ЭВМ как основной инструмент

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

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

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

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

далеко не всякой инструментальной системе программирования (ИСП).

Разработчики ИСП прошли довольно долгий путь совершенствования, прежде чем

достичь той вершины, представителем которой является описываемая в настоящем

пособии система программирования C++ Builder. Рассмотрим основные этапы

эволюции ИСП на основе языка С [4].

Первой ступенью эволюции систем программирования стало появление

языка программирования C++ и библиотек классов C++, которые заключали в

себе сотни строк кода, необходимых даже для простейшего отображения окна на

экране, однако обращение к этим классам занимало в программе на C++ всего

несколько строк. Этот этап эволюции характеризуется наличием раздельных

элементов системы программирования – текстового редактора, компилятора,

линковщика, отладчика, справочника по функциям языка С. Процесс разработки

приложения здесь заключается в последовательном вызове этих элементов из

командной строки операционной системы. Это, очевидно, сильно замедляет

процесс программирования.

Вторым поколением средств разработки для Windows стало появление

средств интегрированной среды разработки (Integrated Development Environment,

IDE). Эти средства позволяют программисту редактировать, компилировать,

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

Интегрированные средства отладки появились чуть позже и были быстро взяты на

вооружение программистами. Практически все современные ИСП строятся по

принципу IDE.

Page 7: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

6

Следующий шаг эволюции средств разработки стал результатом развития кон-

цепции каркасов (framework). Каркас — это основа, скелет вашего приложения, на

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

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

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

Каркасы представляют собой библиотеки классов, которые предлагаются

разработчику как строительные блоки для создания его приложения. Каждый класс

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

программного или пользовательского интерфейса приложения (окно, меню, таймер).

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

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

очевидны – типовые элементы приложения предоставляются программисту в

готовом виде, и вместо многих десятков строк кода, создающих, например, обычное

окно, он может воспользоваться классом «Окно», который содержит в себе все

необходимые для работы окна методы и данные. В качестве примера каркасов можно

назвать библиотеки MFC (Microsoft Foundation Class), OWL (Object Windows Library).

Настоящей проблемой технологии каркасов являются их ограничения. Несмотря

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

распоряжение разработчика многие из основных функций нормального Windows-

приложения, они сразу же встают на пути приложения, которое не укладывается в

привычные рамки, требует нестандартного решения, не предусмотренного

разработчиками каркаса. Еще одно неудобство каркасных технологий – плохая

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

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

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

Развитием концепции каркасов стало появление компонентной модели ИСП,

применяемой в таких системах, как Delphi, C++ Builder. В основу программирования

здесь также положена библиотека, но это уже библиотека компонент (VCL, Visual

Component Library). Компоненты не диктуют строгую структуру программы, они

могут использоваться программистом по его усмотрению для достижения

поставленной цели. Благодаря своей многофункциональной внутренней

Page 8: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

7

архитектуре, основанной на использовании свойств и событий, компоненты можно

гораздо гибче адаптировать к требованиям той или иной задачи. Помимо

использования компонентной модели, многие современные ИСП строятся по

технологии RAD (Rapid Application Development), характеризующейся наличием

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

приложения весь его графический интерфейс в виде, аналогичном тому, каким он

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

форме (в инспекторе объектов) задаются основные свойства компонент, связи

компонент друг с другом. По данным фирмы Borland, в современных программах

около 97% кода приходится на оформление внешнего вида, и лишь 2-3% на

основную функциональность программы. Здесь-то и приходит на помощь

концепция RAD. Благодаря мощным инструментальным средствам, входящим в

средства программирования, поддерживающие RAD, можно значительно

автоматизировать процесс создания компонентов оформления и интерфейса,

разгрузив программиста, избавив его от рутины, и дав возможность

сконцентрировать усилия и внимание на основных функциях программы.

1.2. Основные достоинства системы программирования C++ Builder

Система объектно-ориентированного программирования C++Builder

производства корпорации Borland предназначена для операционных систем

платформы Win32. С++Builder –это законченный, гибкий инструмент RAD,

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

визуальной разработки приложений, достоинства компонентного подхода к

проектированию с открытыми возможностями пополнения имеющихся в

распоряжении разработчика компонент[2].

Интегрированная среда разработки объединяет редактор форм, инспектор

объектов, палитру компонент, администратор проекта и полностью

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

программных приложений, обеспечивающие полный контроль над кодом и

ресурсами.

Page 9: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

8

Профессиональные средства языка C++ интегрированы в визуальную среду

разработки. C++Builder предоставляет быстродействующий компилятор языка

Borland C++, соответствующий стандарту ANSI. Для повышения скорости работы в

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

отладки как на уровне исходных инструкций, так и на уровне ассемблерных команд.

Компилятор системы С++Builder поддерживает технологии шаблонов (templates),

именованных областей видимости (namespaces), обработки исключительных

ситуаций (exception handling), библиотеки стандартных шаблонов STL (Standard

Template Library), информации о типах времени выполнения RTTI (Run Time Type

Information). Инкрементальный компилятор и линковщик системы обрабатывают

при повторной сборке проекта только те его строки, которые изменялись с момента

предыдущей компиляции, тем самым экономя время сборки приложения.

Конструирование по способу "drag-and-drop" позволяет создавать

приложение простым перетаскиванием захваченных мышью визуальных компонент

из палитры компонент на форму приложения. Инспектор объектов предоставляет

возможность оперировать со свойствами и событиями компонент уже на этапе

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

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

кодом.

Механизмы двунаправленной разработки (two-way-tools) позволяют

синхронизировать процесс визуального проектирования форм и генерацию

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

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

программы, объявлений объектов программы.

Библиотека Визуальных Компонент VCL. Компоненты библиотеки VCL

составляют основу программного инструментария программиста на С++Builder.

Компонент – это объект, который своими свойствами, методами и событиями

описывает поведение некоторого элемента пользовательского (кнопка, список строк

в окне, меню) или программного (соединение с базой данных, сокет, таймер)

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

программным объектом, то, конструируя свое приложение как совокупность

Page 10: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

9

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

большие фрагменты кода – они уже реализованы разработчиками компонент.

Находясь в среде объектно-ориентированного программирования C++Builder,

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

поведение или порождать производные элементы, обладающие нужными

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

наличие исходных текстов библиотеки визуальных компонент, что облегчает

разработку новых компонент на базе готовых примеров. C++Builder 6 версии

Standard содержит более 80 компонент, версии Professional – более 150 компонент,

версии Enterprise – более 200 компонент [4]. Благодаря открытости архитектуры

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

сторонних разработчиков, так и компонентами собственной разработки.

Использование модели “свойства-методы-события” PEM , реализованное в

С++ Builder как расширение языка С++, определяет внутреннюю структуру

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

Компонент в этой модели является расширением понятия «класс» стандартного

языка С++ с добавлением понятий «свойство» и «событие». Свойство является

расширением понятия «компонентные данные класса», оно устанавливает способ

получения и сохранения значений характеристик компонент при манипулировании

ими как на этапе проектирования, так и в процессе работы программы. Событие

определяет способ реакции компонента на внешние «раздражители», которыми

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

операционной системы. Для поддержки модели PEM в язык внесены такие

ключевые слова, как __property, _published, _closure и др. Подробнее о свойствах и

событиях речь пойдет в главах 4 и 8.

Доступ к функциям API позволяет расширять функциональность

разрабатываемых приложений за счет возможностей, предусмотренных

операционной системой, которые, возможно, не реализованы компонентами VCL,

но которые, таким образом, не выпадают из арсенала программиста.

Хранилище объектов является инструментом новой методики хранения и

повторного использования модулей данных, объектов, форм и программной бизнес-

Page 11: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

10

логики. Поскольку построение нового приложения на существующем фундаменте

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

повторного использования готовые структуры: формы и законченные программные

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

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

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

Поддержка промышленных стандартов ActiveX, OLE, СОМ, MAPI,

Windows Sockets TCP/IP, ISAPI, NSAPI, ODBC, Unicode и MBCS существенно

повышает функциональную мощь системы программирования, превращает ее в

универсальное средство разработки приложений различной практической

направленности.

Возможности работы с базами данных. С++Builder содержит полный набор

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

программирования. Разработка по способу "drag-and-drop" многократно упрощает и

ускоряет обычно трудоемкий процесс программирования СУБД в архитектуре

клиент/сервер. Широкий выбор компонент управления визуализацией и

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

поведение программы. Механизм BDE (Borland Database Engine) поддерживает

высокопроизводительный 32-разрядный доступ к базам данных dBASE, Paradox,

Sybase, Oracle, DB2, Microsoft SQL Server, Informix, InterBase, MySQL. C++Builder

использует контроллер ODBC (Open Database Connectivity) производства Microsoft

для связи с серверами баз данных Excel, Access, FoxPro. Начиная с версии 6

поддерживается технология SOAP для многоуровневых приложений баз данных,

добавлен независимый от архитектуры BDE набор компонентов dbExress,

позволяющий создавать приложения клиент/сервер, работающие с базами данных

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

Все это в сочетании с большим количеством визуальных компонент отображения

информации из баз данных делает C++Builder мощной и гибкой средой

программирования баз данных на языке С++.

Page 12: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

11

Вывод

Система программирования С++Builder является современным средством

разработки приложений, поддерживающим компонентный подход и построенный

по принципу визуального проектирования. Удобные встроенные средства

проектирования и поддержка большинства современных технологий в области

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

превращают С++Builder в универсальный инструмент программиста любой

специализации.

2. Состав системы программирования C++Builder

C++Builder представляет собой визуальную интегрированную среду

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

приложений для операционной системы Windows. После запуска системы

программирования она разворачивается в вид, представленный на рис. 2.1. (для

C++Builder 6.0).

Можно выделить следующие основные элементы системы:

1. Палитра инструментов и главное меню системы, содержащие основные

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

2. Палитра компонент – содержит список компонентов, доступных

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

3. Инспектор объектов – инструмент, предназначенный для управления

свойствами и обработчиками событий компонент проекта на этапе

разработки приложения.

4. Редактор форм – инструмент визуального представления видимых и

невидимых компонент и манипулирования ими на этапе проектирования.

5. Редактор кода – отображает код проекта, позволяет вносить в него

изменения, для чего имеются удобные встроенные средства.

Page 13: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

12

6. Окно дерева объектов – удобный инструмент отображения компонент

проекта в иерархии “владелец-подчиненный».

Помимо этого, достойны упоминания элементы среды, которые не

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

дополнительно. К таким элементам можно отнести хранилище объектов и менеджер

проекта.

2.1. Панель инструментов и главное меню системы

Панель инструментов представляет программисту набор кнопок для быстрой

подачи основных команд управления проектом: открытия и сохранения файлов,

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

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

программиста в пункте меню View | Toolbars. Полный список команд системы

содержится в пунктах главного меню. Размер пособия не позволяет описать все

1 2

3

4

5

Рис. 2.1. Внешний вид среды программирования C++Builder 6.0

6

Page 14: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

13

пункты меню системы C++Builder, но в процессе изложения будут рассмотрены

основные пункты, использующиеся для решения типовых задач проектировщика.

2.2. Палитра компонент

Палитра компонент представляет собой хранилище всех компонент,

зарегистрированных в системе. Компоненты объединены в группы, каждая из

которых хранится на отдельной закладке, название группы указывается в заголовке

закладки (рис.2.2.).

Набор закладок в палитре, а также компонент в каждой закладке может быть

изменен, система открыта для добавления новых компонент, разработанных как в

самой системе, так и сторонними производителями. В таблице 2.1. перечислены

основные группы компонент.

Таблица 2.1.

Перечень групп компонент системы программирования C++Builder 6.0

Название закладки Группа компонент

Standard Стандартные компоненты пользовательского интерфейсаWindows (кнопки, строки ввода, списки и т.п.)

Additional Дополнительные стандартные компонентыспециализированного дизайна или функциональности

Win32 Компоненты пользовательского интерфейса платформыWin32 (закладки, полоса прогресса, панели)

System Компоненты, обеспечивающие доступ к системнымфункциям Windows (таймер, DDE-обмен, технология OLE)

Data Access Компоненты для доступа к базам данных

Data Controls Компоненты для отображения информации из баз данных

BDE Компоненты для доступа к базам данных с использованиемBDE

Internet Компоненты для создания Web-приложений

Рис. 2.2. Палитра компонент C++Builder

Page 15: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

14

Продолжение таблицы 2.1Qreport Компоненты для создания отчетов

Dialogs Компоненты для доступа к стандартным диалоговым окнамWindows (открытия, сохранения файлов, печати и т.п.)

Win 3.1 Компоненты пользовательского интерфейса Win 3.1(оставлены для совместимости с ранними проектами)

ActiveX Управляющие компоненты ActiveX

FastNet Компоненты, реализующие основные Internet-протоколы(FTP, POP3, SMTP и др.)

Office2k Оболочки VCL для распространенных серверов СОМофисных приложений Microsoft

Помимо перечисленных групп в палитре присутствуют несколько

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

специфичных технологий работы с базами данных (ADO, dbExpress, DataSnap,

доступ к InterBase).

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

выбрать его в палитре, а затем щелкнуть левой кнопкой мыши на том месте на

форме, где необходимо его поместить. Дальнейшая работа с компонентом

осуществляется в редакторе форм и инспекторе объектов.

2.3. Инспектор объектов

В окне инспектора объектов (Object Inspector) отображаются значения свойств

компонент, а также названия сопоставленных различным событиям компонента

обработчиков. Инспектор объектов отображает свойства выбранного в редакторе

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

раскрывающийся список в верхней части инспектора.

Инспектор объектов состоит из двух частей – окна свойств (Properties) и окна

событий (Events). Окно свойств содержит список опубликованных (published)

свойств компонента, а также присвоенных этим свойствам значений. Значение

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

простейшем случае представляет собой строку ввода, но для некоторых свойств он

выглядит как раскрывающийся список или диалоговое окно. Измененные значения

Page 16: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

15

свойства обрабатываются системой уже на этапе проектирования, так, например,

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

редакторе форм изменится согласно присвоенной ширине.

Окно событий отображает опубликованные события компонента, а также

сопоставленные им функции-обработчики. По умолчанию событиям не

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

обработчика события, то это приведет к генерации пустой функции-обработчика

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

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

сопоставить событию в раскрывающемся списке.

Показать инспектор объектов, если его нет на экране, можно командой View |

Object Inspector (F11).

2.4. Редактор форм

Редактор форм представляет на экране формы приложения в том виде, какой

они будут иметь на стадии работы приложения. Форма – это компонент С++Builder,

который объединяет в себе свойства, методы и события, описывающие окно ОС

Windows. Форма выступает владельцем хранящихся на ней управляющих

элементов. Редактор форм предоставляет возможность манипулирования внешним

видом формы и ее управляющими элементами: изменения размера и

месторасположения, выбора для изменения свойств в инспекторе объектов,

добавления и удаления компонент на форму (рис. 2.3).

Рис.2.3. Форма на этапе проектирования

Page 17: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

16

При этом редактор форм не является сугубо визуальным инструментом,

позволяющим только конструировать внешний вид окна программы. В соответствии

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

производит с компонентами формы в редакторе форм (добавляет, удаляет),

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

2.5. Редактор кода

Какими бы удобными ни были инструменты визуального проектирования

приложений, они не могут полностью сформировать код приложения, некоторую

его часть приходится вводить вручную. Система C++Builder предлагает для этого

удобный инструмент – редактор кода (рис.2.4).

Редактор кода позволяет редактировать одновременно несколько файлов,

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

В редакторе кода C++Builder можно редактировать файлы следующих типов[4]:

· Заголовочные файлы и файлы на языке С++ (расширения .h, .hpp, .cpp).

· Файлы на языке Pascal (.pas).

· Текстовые файлы (.txt).

· Файлы из проекта C++Builder (.dfm, .bpr).

· Выражения на языке SQL для компонент типа TQuery.

Рис.2.4. Внешний вид редактора кода C++ Builder

Page 18: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

17

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

дополнительное средство Code Insight. Оно позволяет получать быструю подсказку

по свойствам и методам того объекта, имя которого введено в редакторе кода (рис.

2.5). Для ввода требуемого свойства или метода необходимо лишь выбрать его из

предлагаемого списка. Еще одна функция Code Insight – подсказка по набору

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

программы.

2.6. Окно дерева объектов

Окно дерева объектов (Object Tree View) предназначено для представления

компонент активной формы в иерархии «владелец-подчиненный». Его

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

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

мышью затруднительно.

С помощью окна дерева объектов программист может редактировать

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

копии того или иного компонента. Показать окно дерева объектов, если его нет на

экране, можно командой View | Object TreeView (Shift-Alt-F11).

Рис.2.5. Подсказки Code Insight

Page 19: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

18

2.7. Менеджер проекта

Менеджер проекта (рис. 2.8) предназначен для управления файлами,

входящими в проект C++Builder. Он позволяет просмотреть, какие файлы включены

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

файлами. Для этих целей используются кнопки панели инструментов менеджера или

команды контекстного меню. Отобразить менеджер проекта на экране можно,

используя команду View | Project Manager (Ctrl-Alt-F11).

Рис.2.7. Окно Object Tree View

Рис.2.8. Окно менеджера проекта

Page 20: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

19

2.8. Хранилище объектов

Хранилище объектов выполняет в системе программирования C++Builder

важную функцию повторного использования объектов, когда однажды

спроектированные формы, модули данных, проекты могут использоваться

многократно при разработке различных приложений. Вид окна хранилища объектов

представлен на рис. 2.9. Открыть его можно, выбрав команду File | New |Other. В

появившемся окне можно выбрать тот или иной объект для добавления к своему

проекту. Объекты объединены в группы, переключение между которыми возможно

с использованием закладок в верхней части окна. В качестве объектов здесь

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

закладки Dialogs можно добавить в проект диалоговое окно ввода пароля Password

dialog, которое содержит все необходимые подобному окну управляющие элементы

(строка для ввода пароля, кнопки подтверждения и отмены). В итоге программист

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

обработки введенного пароля.

Хранилище объектов открыто для модификации. Если щелкнуть на форме

правой кнопкой мыши, то в контекстном меню можно увидеть команду Add to

Repository (Добавить в Хранилище), которая позволяет поместить данную форму в

хранилище объектов и использовать ее в дальнейшем в других проектах. Для

Рис. 2.9. Хранилище объектов

Page 21: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

20

добавления в хранилище всего проекта используется команда Project | Add to

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

для будущих разработок.

Вывод

Система программирования Borland C++Builder предоставляет программисту

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

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

построению программы со стандартными средствами систем программирования

(редактор кода, отладчик, встроенная помощь).

3. Проект приложения в C++Builder

Проект в визуальной среде проектирования С++Builder состоит из нескольких

файлов и необходим для корректного проектирования и компиляции приложения. В

общем случае состав проекта зависит от типа разрабатываемого приложения

(графическое приложение, консольное приложение, динамическая библиотека,

системная служба, WEB приложение). Рассмотрим состав проекта для графического

(WIN32 GUI) приложения, поскольку именно с таким чаще всего приходится

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

разделить на две группы: файлы проекта и файлы форм. По умолчанию файлы

проекта имеют имя project1, а файлы форм unit1, unit2 и т.д. К файлам проекта

относятся следующие типы файлов: главный файл проекта, исходный файл проекта,

файл ресурсов проекта. Главный файл проекта имеет расширение *.bpr и необходим

при разработке любых приложений в среде С++Builder. Данный файл содержит

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

выходного модуля приложения. Этот файл является аналогом файла makefile,

используемого во многих системах программирования, базирующихся на С++. Для

получения файла *.mak из главного файла проекта можно использовать пункт

Page 22: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

21

главного меню Project | Export Makefile. Сам главный файл проекта представлен в

формате XML и состоит из нескольких секций: MACROS, OPTIONS, LINKER,

FILELIST, IDEOPTIONS, содержание которых определяет состав проекта, опции

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

т.п. Фрагмент главного файла проекта приведен в листинге 3.1. Для просмотра

файла можно использовать пункт главного меню среды разработки Project|Edit

Option Source. Однако ручное редактирование данного файла не рекомендуется, и

все изменения в данный файл вносятся автоматически при изменении опций проекта

(пункт меню Project|Options или комбинация клавиш Shift-Ctrl-F11), а также при

добавлении и удалении файлов в проект. Для добавления файлов в проект можно

использовать пункт главного меню Project|Add to Project (комбинация клавиш Shift-

F11). Для удаления файлов из проекта можно использовать пункт главного меню

Project|Remove from Project.

Листинг 3.1. Файл проекта C++Builder<?xml version='1.0' encoding='utf-8' ?>

<!-- C++Builder XML Project -->

<PROJECT>

<MACROS>

<VERSION value="BCB.06.00"/>

<PROJECT value="Project1.exe"/>

<OBJFILES value="Project1.obj &quot; С:\Program

Files\Borland\CBuilder6\ Bin\ Unit1.obj&quot;"/>

<RESFILES value="Project1.res"/>

<SPARELIBS value="vcl.lib rtl.lib"/>

<PACKAGES value="vcl.bpi rtl.bpi dbrtl.bpi adortl.bpi

vcldb.bpi vclx.bpi vcldbx.bpi ibxpress.bpi cds.bpi dsnap.bpi

bdecds.bpi qrpt.bpi teeui.bpi teedb.bpi tee.bpi dss.bpi teeqr.bpi

visualclx.bpi visualdbclx.bpi bcbsmp.bpi vclie.bpi xmlrtl.bpi inet.bpi

inetdbbde.bpi inetdbxpress.bpi inetdb.bpi nmfast.bpi webdsnap.bpi

bcbie.bpi dclocx.bpi dbexpress.bpi dbxcds.bpi indy.bpi

bcb2kaxserver.bpi dclusr.bpi vclshlctrls.bpi"/>

. . .

</MACROS>

<LINKER>

Page 23: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

22

<ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj

$(OBJFILES)"/>

<ALLRES value="$(RESFILES)"/>

<ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib

cp32mti.lib"/>

<OTHERFILES value=""/>

</LINKER>

<FILELIST>

<FILE FILENAME="Project1.res" FORMNAME=""

UNITNAME="Project1.res" CONTAINERID="ResTool" DESIGNCLASS=""

LOCALCOMMAND=""/>

<FILE FILENAME="Project1.cpp" FORMNAME=""

UNITNAME="Project1" CONTAINERID="CCompiler" DESIGNCLASS=""

LOCALCOMMAND=""/>

<FILE FILENAME="C:\Program

Files\Borland\CBuilder6\Bin\Unit1.cpp" FORMNAME="Form1"

UNITNAME="Unit1" CONTAINERID="CCompiler" DESIGNCLASS=""

LOCALCOMMAND=""/>

</FILELIST>

. . .

</PROJECT>

Исходный файл проекта имеет расширение *.cpp и для графического

приложения содержит функцию WinMain, которая является точкой входа при

запуске приложения. Для просмотра исходного файла проекта можно использовать

пункт главного меню среды разработки Project|View Source. В данном файле

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

код для создания автоматически создаваемых форм приложения, обработка

исключительных ситуаций, а также код для организации цикла обработки

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

WinMain, то в данный файл целесообразно добавить код, который необходимо

выполнить еще до отображения главной формы приложения. Например, обработка

ключей запуска приложения, запрещение запуска второй копии приложения,

отображения окна splash screen во время загрузки приложения. Пример исходного

файла проекта приведен в листинге 3.2.

Page 24: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

23

Листинг 3.2. Файл проекта (project1.cpp)#include <vcl.h>

#pragma hdrstop

USEFORM("С:\Program Files\Borland\CBuilder6\Bin\Unit1.cpp",

Form1);

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

{ try

{ Application->Initialize();

Application->CreateForm(__classid(Tform1), &Form1);

Application->Run(); }

catch (Exception &exception)

{ Application->ShowException(&exception); }

catch (...)

{ try

{ throw Exception(""); }

catch (Exception &exception)

{ Application->ShowException(&exception); }

}

return 0;}

Двоичный файл ресурсов проекта имеет расширение *.res и содержит ресурсы

приложения. По умолчанию в данном файле находится один ресурс типа ICON с

именем MAINICON, содержащий пиктограмму главного окна приложения. Также в

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

случае файл ресурсов может содержать различные типы ресурсов, например,

BITMAP, CURSOR, DIALOG, MENU, STRINGTABLE и др. Данный файл создается

автоматически при компиляции приложения и его ручное редактирование

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

ресурсов необходимо добавить в проект с помощью пункта меню Project| Add to

project дополнительный исходный файл ресурсов с расширением *.rc или

откомпилированный файл ресурсов с расширением *.res. Например, добавить в

файл ресурсов myres.rc пиктограмму из файла “earth.ico” можно следующим

образом:

MYICON ICON "EARTH.ICO"

Page 25: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

24

После сборки приложения данная пиктограмма будет храниться в готовом

модуле (exe или dll). В коде приложения доступ к ней можно получить следующим

образом:Application->Icon->Handle=LoadIcon(HInstance,"MYICON");

Глобальная переменная HInstance в приложениях C++Builder содержит

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

передается системой в качестве первого параметра функции WinMain.

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

File|New|Form. Каждая форма приложения содержит следующие типы файлов: файл

формы, файл модуля формы, заголовочный файл формы. Файл формы имеет

расширение *.dfm и содержит информацию о компонентах, помещенных на форму.

Начиная с 5-ой версии С++Builder, файл формы имеет текстовый вид, в ранних

версиях использовался двоичный файл формы. Для совместимости с предыдущими

версиями можно вернуться к двоичному файлу, отключив опцию Text DFM в

контекстном меню редактора форм. Файл формы используется редактором форм,

изменения в него вносятся автоматически при проектировании приложения и его

ручное редактирование не рекомендуется. Для просмотра файла формы можно

использовать пункт контекстного меню View as Text редактора форм. Для возврата в

режим редактора формы можно использовать пункт контекстного меню View as

Form. Фрагмент файла формы приведен в листинге 3.3.

Листинг 3.3. Файл формыobject Form1: TForm1

Left = 192

Top = 107

BorderStyle = bsDialog

Caption = 'Test'

object Image1: TImage

Left = 40

Top = 64

Width = 105

Height = 81

end

object Button1: TButton

Page 26: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

25

Left = 24

Top = 24

Width = 75

Height = 25

Caption = 'Close'

TabOrder = 0

end

end

Из листинга видно, что файл формы хранит значения свойств и событий

компонент формы, присвоенных им в инспекторе объектов. Это необходимо для

восстановления данных значений при последующих загрузках проекта.

Исходный файл формы имеет расширение *.cpp и содержит реализацию всех

методов класса формы и обработчиков событий. Данный файл также называется

модулем формы или form unit.

Листинг 3.4. Модуль формы#include <vcl.h>

#pragma hdrstop

#include "Unit1.h"

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{}

void __fastcall TForm1::FormCreate(TObject *Sender)

{ date d;

getdate(&d);

Form1->Caption="Сегодня"+IntToStr(d.da_day)+"."+

IntToStr(d.da_mon)+"."+IntToStr(d.da_year);}

В листинге 3.4 приведен фрагмент возможного содержимого файла модуля

формы. В данном примере файл содержит конструктор формы TForm1 и обработчик

события создания формы FormCreate. При генерации в инспекторе объектов новых

обработчиков их определение с пустым телом автоматически добавляется в файл

модуля формы, а задача программиста – в наполнении тела обработчика кодом.

Page 27: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

26

Заголовочный файл формы имеет расширение *.h и содержит описание класса

формы (листинг 3.5). Заголовочный файл подключается к исходному файлу формы с

помощью директивы препроцессора #include. Для предотвращения повторного

определения класса код заголовочного файла обрамлен директивами препроцессора#ifndef Unit1H

#define Unit1H

// код

#endif

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

переключения между исходным файлом формы и заголовочным файлом можно

использовать пункт контекстного меню редактора кода Open Source/Header File

(комбинация клавиш Ctrl-F6). Необходимо также отметить, что в заголовочном

файле также находится внешнее определение указателя на класс формы.extern PACKAGE TForm1 *Form1;

Поэтому для использования данной формы из других форм приложения в

исходных файлах этих форм необходимо просто подключить заголовочный файл

формы с помощью директивы препроцессора #include. Аналогичные действия

производятся автоматически при выборе пункта главного меню File| Include Unit Hdr

(комбинация клавиш Alt-F11). Ниже приведен пример исходного файла проекта.

Листинг 3.5. Заголовочный файл формы#ifndef Unit1H

#define Unit1H

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <ExtCtrls.hpp>

#include <Graphics.hpp>

class TForm1 : public TForm

{__published: // IDE-managed Components

TButton *Button1;

TImage *Image1;

void __fastcall FormCreate(TObject *Sender);

private: // User declarations

Page 28: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

27

public: // User declarations

__fastcall TForm1(TComponent* Owner);};

extern PACKAGE TForm1 *Form1;

#endif

Содержимое заголовочного файла может формироваться как автоматически

при работе программиста с редактором форм и инспектором объектов, так и самим

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

добавлены компоненты TButton и TImage, а в инспекторе объектов был создан

обработчик события FormCreate.

Для сохранения файлов проекта можно использовать пункт главного меню

File | Save Project As. Для сохранения файлов формы можно использовать пункт

главного меню File | Save As. При этом можно задать новые имена для файлов

проекта и файлов форм. Для сохранения изменений во всех файлах можно

использовать пункт главного меню File | Save All (комбинация клавиш Shift-Ctrl-S).

Для закрытия проекта можно использовать пункт меню File | Close All. Для

открытия проекта можно использовать пункт меню File | Open Project (комбинация

клавиш Ctrl-F11).

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

(например, при разработке клиент/серверных систем) можно использовать группу

проектов. Для добавления новых и существующих проектов в группу можно

использовать пункты главного меню Project | Add New Project и Project | Add Existing

Project соответственно. Выбор текущего проекта можно произвести в менеджере

проектов, доступного через пункт главного меню View | Project Manager

(комбинация клавиш Ctrl-Alt-F11). Файл группы проектов имеет расширение *.bpg и

содержит информацию о проектах, входящих в группу.

В процессе компиляции создаются некоторые временные файлы. Файлы,

расширение которых начинается с символа “~”, являются резервными копиями

соответствующих файлов. Файлы с расширением *.obj объектные файлы

приложения и форм. Файл с расширением *.tds содержит информацию для

отладчика и инкрементного линковщика.

Page 29: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

28

Кроме того существуют несколько дополнительных типов файлов,

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

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

Вывод

Проект приложения в среде C++Builder состоит из нескольких файлов,

основными из которых являются: главный файл проекта (с расширением .bpr),

исходный файл проекта (по умолчанию называется project1.cpp), а также для каждой

формы приложения файл формы (расширение .dfm), заголовочный файл

(расширение .h) и модуль формы (расширение .cpp). Помимо этого в состав проекта

могут входить файлы ресурсов, внешние библиотеки, пакеты. При работе с

проектом система создает также некоторые дополнительные файлы, необходимые

для сборки приложения.

4. Библиотека визуальных компонент С++Builder

4.1. Общие сведения о библиотеке VCL

Визуальная среда проектирования С++Builder, начиная с 6-ой версии,

поддерживает две библиотеки программных компонент. Visual Component Library

(VCL) и Component Library for Cross Platform (CLX). Библиотека VCL

поддерживается во всех версиях Borland Builder и содержит большой набор

компонент, предназначенных для разработки приложений, работающих под

управлением операционных систем семейства Windows. Библиотека CLX является

платформенно-независимой и позволяет разрабатывать приложения, работающие

под управлением операционных систем семейства Windows и Unix. Например,

графическое приложение, разработанное с помощью этой библиотеки, может быть

откомпилировано в среде Builder для работы в операционной системе Windows и

откомпилировано в среде Kylix для работы в графической системе X-Window

операционной системы Linux. Следует отметить, что система Kylix поддерживает

Page 30: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

29

лишь ограниченный набор систем семейства Unix. Для систем Unix существуют

другие платформенно-независимые системы, которые поддерживают практически

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

система визуального проектирования QT. Кроме того, библиотека CLX не

поддерживает некоторых возможностей, специфичных для приложений Windows,

например, технологии ADO, OLE, COM+. Все эти и некоторые другие технологии

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

работающих под управлением операционных систем семейства Windows, более

целесообразно использовать библиотеку VCL. В дальнейшем будем рассматривать

компоненты библиотеки VCL.

Имена большинства компонентов VCL начинаются с буквы T, имена классов

исключительных ситуаций начинаются с буквы E. Компоненты являются

дальнейшим развитием классов и объектно-ориентированного программирования. В

отличие от объектов класса компоненты существуют не только на этапе выполнения

приложения, но и на этапе проектирования приложения. Поведение компонент

может различаться на этих двух этапах, например, форма на этапе проектирования

отображается с точечной сеткой и двойной щелчок левой кнопкой мыши на

свободной области формы приводит к переходу в редактор кода. Кроме того, в

дополнение к компонентным данным и компонентным функциям класса в

компонентах появляются свойства и события. Свойства являются дополнительным

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

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

размер и т.д. Изменение значений свойств приводит к изменению каких-либо

внутренних данных компонента. Значения свойств могут устанавливаться как на

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

инспектора объектов на закладке Properties. Для того, чтобы свойства были

доступны в инспекторе объектов они должны быть опубликованы. Для этого их

определение в классе должно быть размещено в секции __published. Данная секция

относится к атрибутам видимости полей класса (private, protected, public). На этапе

выполнения работа со свойствами практически ничем не отличается от работы с

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

Page 31: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

30

TestButton->Caption=”New Text”;

if (TestButton->Color==clButton) TestLabel->Color=clBlack;

Необходимо помнить, что свойство - это интерфейс для доступа к полям

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

переменных, для свойств недоступны. Например, код Form1->Caption+=”*”

некорректен, а код Form1->Caption= Form1->Caption+”*” корректен.

События вызываются компонентом для сигнализации о каких-либо

изменениях, связанных с состоянием этого компонента. События могут быть

вызваны действиями пользователя, операционной системой или самим

компонентом. Например, щелчок кнопкой мыши на области компонента,

уничтожение компонента, срабатывание таймера и т.д. С каждым событием

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

функцию-обработчик события. Функция-обработчик должна быть методом какого-

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

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

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

Большинство сообщений операционной системы Windows оформлены в библиотеке

VCL в виде соответствующих событий. Например, сообщения от клавиатуры,

мыши, сообщения Drag-&-Drop, сообщения органов управления Windows и т.д.

Более подробно внутренняя реализация свойств и событий будет рассмотрена в

главе 8. Здесь лишь отметим, что событие на самом деле содержит в себе указатель

на функцию обработчик. В С++Builder определен специальный тип события с

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

класса, дополнительно содержащий указатель на конкретный экземпляр класса.

Например, событие TNotifyEvent описывается следующим образом:

typedef void __fastcall (__closure *TNotifyEvent)(System::TObject*Sender);

Параметр Sender присутствует для каждого события и содержит указатель на

экземпляр компонента, для которого произошло событие. Кроме этого параметра

события могут содержать и другие специфичные для себя параметры, отвечающие,

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

Page 32: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

31

этапе проектирования можно воспользоваться инспектором объектов (закладка

Events). Каждый компонент имеет так называемое событие по умолчанию (чаще

всего OnClick). При двойном щелчке левой кнопкой мыши на компоненте на этапе

проектирования происходит переход в редактор кода для определения кода

обработки этого события. На этапе выполнения событие по умолчанию никак не

отличается от остальных событий компонента. Обработчик события может быть

назначен или убран также и на этапе выполнения. Например, в unit1.h:

__published:

void __fastcall StartClick(TObject *Sender);

void __fastcall StopClick(TObject *Sender);

в unit1.cpp

void __fastcall TForm1::StartClick(TObject *Sender)

{// выполнение какого-либо кода

ButtonStartStop->Caption="stop";

ButtonStartStop->OnClick=StopClick;

}

void __fastcall TForm1::StopClick(TObject *Sender)

{// выполнение какого-либо кода

ButtonStartStop->Caption="start";

ButtonStartStop->OnClick=StartClick;

}

В данном примере для кнопки ButtonStartStop попеременно назначаются

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

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

быть назначен нескольким событиям различных компонентов. Например, при

разработке графической клавиатурной панели, у нас есть 10 кнопок с

соответствующими цифрами. При нажатии на кнопки соответствующая цифра

должна быть добавлена в поле ввода. Поскольку все обработчики события OnCliсk в

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

обработчик всем кнопкам. Внутри обработчика определить, для какой именно

кнопки было сгенерировано событие, позволяет параметр Sender. Следует отметить,

что Sender имеет тип указателя на базовый класс библиотеки VCL TObject и может

содержать указатель на объект любого производного класса. В нашем случае

Page 33: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

32

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

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

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

Статическое приведение типов выглядит как обычное приведение типов языка С++

и происходит на этапе компиляции.void __fastcall TForm1::ButtonkbClick(TObject *Sender)

{ Edit1->Text=Edit1->Text+((TButton *)Sender)->Caption; }

В этом случае соответствие типов проверяется на этапе компиляции и

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

имеющий тип указателя на класс TObject, может быть преобразован к любому

производному классу от TObject. В результате нет возможности проверить

соответствие типов во время выполнения. Например, Sender может содержать

указатель на экземпляр класса TLabel и будет предпринята попытка преобразовать

его к TButton. В этом случае при вызове каких-либо методов характерных для

класса TButton произойдет ошибка во время выполнения программы, причем

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

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

происходит на этапе выполнения, а не на этапе компиляции. В C++Builder для

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

dynamic_cast, который используется следующим образомdynamic_cast< T > (ptr),

где T это тип класса, к которому производится преобразование указателя ptr. (T

также может быть указателем или void *). При успешном выполнении оператора

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

неудачного приведения типов возвращается NULL.void __fastcall TForm1::ButtonkbClick(TObject *Sender)

{TButton *TempButton;

TempButton=dynamic_cast<TButton *>(Sender);

If (TempButton) Edit1->Text=Edit1->Text+TempButton->Caption; }

Оператор dynamic_cast доступен только при использовании механизма RTTI.

RTTI (Run-Time Туре Identification) это идентификация типов при выполнении

программы. По умолчанию механизм RTTI разрешен в C++Builder. Принудительно

Page 34: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

33

запретить его можно, указав -RT- при компиляции, и разрешить, указав -RT. Кроме

того, для каждого класса можно включить RTTI (если он будет по умолчанию

выключен) с помощью ключевого слова __rtti. Механизм RTTI также позволяет

проверять, имеет ли объект некоторый определенный тип, или принадлежат ли два

объекта одному и тому же типу. Оператор typeid определяет фактический тип

аргумента и возвращает указатель на объект класса typeinfo, который этот тип

описывает. Кроме того, для этого класса перегружены операции == и !=, которые

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

Следует отметить, что все экземпляры всех компонент в С++Builder могут

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

к компоненту, должна быть указателем на класс. Для всех компонент, помещенных

на форму, такие переменные будут созданы автоматически, кроме того,

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

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

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

создать экземпляр класса при помощи оператора new. При этом вызывается

конструктор соответствующего класса в качестве параметра, которому необходимо

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

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

этого параметра this:TLabel *MyLabel;

MyLabel=new TLabel(this);

MyLabel->Parent=MyPanel;

Став владельцем, форма становится ответственной за удаление компонента.

При своем закрытии она вызовет деструктор для данного компонента

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

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

оператор delete для вызова деструктора: delete MyLabel. Свойство Parent отвечает за

старший или родительский компонент и подробнее будет рассмотрено ниже.

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

статически, так и динамически. Например:

Page 35: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

34

AnsiString Str1;

Str1=”Static Str”;

AnsiString *Str2;

Str2=new AnsiString();

*Str2=”Dynamic Str”;

ShowMessage(Str1+"\n"+*Str2);

delete Str2;

В С++Builder также существует специальный тип метакласс (metaclass) или

ссылка на тип класса, который определяется следующим образомclass PACKAGE TMetaClass;

typedef TMetaClass* TClass;

Можно определить переменную этого типа, которая будет содержать ссылку

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

класса. Для стандартных классов доступ к метаклассу можно получить с помощью

ключевого слова __classid(ClassName). Например, __classid(TButton).

4.2. Иерархия классов VCL

Все компоненты VCL находятся в иерархии классов, основу которой

составляют базовые классы. Каждый базовый класс имеет некоторый набор

методов, событий и свойств и специальное назначение. От этих базовых классов

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

базовыми классами-предками, находящимися выше них в иерархии. Базовые классы

библиотеки VCL иногда называют абстрактными, однако они не являются

абстрактными классами с точки зрения языка С++. Эти классы не имеют чистых

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

для этих классов нельзя создать полноценно работающие объекты, поскольку в них

содержатся лишь общие характеристики, которые затем должны уточняться и

переопределяться в классах-потомках. Тем не менее, эти классы полезны в качестве

базовых при создании пользовательских компонент, так как содержат общие

характеристики, присущие всем классам данного семейства. Кроме того, указателю

Page 36: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

35

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

Полная иерархия базовых классов библиотеки VCL представлена на рисунке.

Рис. 4.1. Фрагмент схемы иерархии классов библиотеки VCL

Основой иерархий являются классы TObject, TPersistent, TComponent,

TControl, TGraphicControl, TWinControl. TObject является базовым классом для всех

порождаемых классов библиотеки VCL, TComponent является базовым классом для

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

TComponent. Отображаемые компоненты имеют общего предка TControl, при этом

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

класса TWinControl. Причем компоненты, инкапсулирующие стандартные органы

управления Windows, произведены непосредственно от класса TWinControl, а

оригинальные компоненты от класса TCustomControl. Рассмотрим основные

базовые классы более подробно.

Класс TObject инкапсулирует общее функциональное поведение для всех

классов системы С++Builder, а именно:

- возможность создания, управления и уничтожения экземпляров объекта;

- поддержка информации RTTI об имени и типе объекта;

- поддержка механизма обработки сообщений.

Большинство этих методов предназначены для внутреннего использования

системой С++Builder. Часть методов TObject объявлены как статические (с

ключевым словом static). Таким образом, к ним можно обращаться, не создавая

экземпляр класса, используя лишь имя класса или метакласс. Рассмотрим некоторые

часто используемые методы объекта TObject.

Page 37: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

36

ShortString TObject::ClassName(void) - статический метод, который возвращает

строку с именем класса.

TMetaClass * TObject::ClassType(void) - статический метод, который

возвращает указатель на метакласс.

TMetaClass * TObject::ClassParent(void) - статический метод, который

возвращает указатель на метакласс предка (для TObject возвращает NULL).

bool TObject::InheritsFrom(TMetaClass *) возвращает true, если объект является

экземпляром указанного в качестве параметра класса или класса потомка.

Например:

if (Sender->InheritsFrom(__classid(TWinControl)))

ShowMessage(«Экземпляр потомка TWinControl»);

void TObject::Dispatch (void* Message) - виртуальный метод, посылает

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

идентификатору сообщения, расположенному в 2-х первых байтах по адресу,

переданному в качестве параметра. В классах потомках в качестве параметра

передается указатель на структуру TMessage. Сначала просматриваются

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

предках. Если обработчик так и не был найден, вызывается DefaultHandler.

void TObject::DefaultHandler(void* Message) - виртуальный метод, обработчик

сообщения по умолчанию. Для TObject не выполняет никаких действий (для

TWinControl вызывает стандартную API-функцию DefWndProc, которая выполняет

обработку сообщений Windows по умолчанию).

int TObject::Free(void) вызывает деструктор для уничтожения объекта.

Аналогичные действия могут быть выполнены с помощью оператора delete.

Ниже приведен пример, позволяющий вывести диалоговое окно, содержащее

иерархию для объекта переданного в качестве параметра Sender.void __fastcall TForm1::ControlClick(TObject *Sender)

{AnsiString Str;

TClass tcl;

tcl=Sender->ClassType();

while (tcl)

{ Str+=AnsiString(tcl->ClassName())+"\n";

Page 38: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

37

tcl=tcl->ClassParent();

}

ShowMessage(Str);}

Кроме рассмотренных выше методов существуют еще несколько сервисных

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

FieldAddress, MethodAddress, MethodName, InitInstance, FreeInstance, InstanceSize и

т.д. От TObject наследуются в основном простые объекты, которые не являются

компонентами и не нуждаются в поточности и присваивании.

Класс TPersistent является предком всех классов, поддерживающих работу со

свойствами. Являясь потомками TPersistent, производные классы приобретают

способность поточности и присваивания, а именно:

- возможность сохранения и чтения из потока неопубликованных свойств;

- возможность присвоения значений свойствам;

- возможность присвоения данных одного объекта другому.

Запись и чтение из потока производится в формате dfm. Таким образом, под

записью/чтением в поток подразумевается возможность сохранения/загрузки

значений свойств в файл формы. В общем случае поточность предоставляет классам

возможность помещения в память и загрузки из памяти, например, при переносе

компонентов через буфер обмена. Несмотря на то, что поточность появляется,

начиная с класса TPersistent, используют эту возможность в основном компоненты,

т.е. классы, наследованные от TComponent. Большинство методов TPersistent

перегружаются в потомках. Рассмотрим методы этого класса.

void TPersistent::Assign(TPersistent *Source) позволяет данному объекту

присвоить значения свойств и атрибутов другого объекта, заданного в качестве

параметра. Например, Destination->Assign(Source);

void TPersistent::AssignTo (TPersistent* Destination) позволяет присваивать

значения свойств и атрибутов текущего объекта другому объекту, указанному в

качестве параметра. У TPersistent этот метод является виртуальным и защищенным.

Этот метод необходим при разработке новых классов для обеспечения возможности

присваивания их стандартным классам. Если метод Assign объекта A не знает как

выполнить присваивание параметров объекта B, то его метод Assign автоматически

Page 39: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

38

вызывает метод AssignTo объекта B. Т.е. если A->Assign(B) не может выполниться

для типа объекта B, то внутри метода Assign вызывается B->AssignTo(A).

void TPersistent::DefineProperties(TFiler *Filer) позволяет определить

процедуру загрузки и сохранения в потоке неопубликованных свойств. По

умолчанию сохраняются только опубликованные свойства, т.е. объявленные в

секции __published. У TPersistent этот метод является виртуальным и защищенным.

От TPersistent наследуются классы, которые не являются компонентами, но

нуждаются в поточности и присваивании.

Класс TComponent является предком всех компонент. TComponent

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

С++Builder, а именно:

-возможность помещения на форму из палитры компонент и манипуляции в

окне редактора форм;

-способность владения и обслуживания других компонент;

-специальные характеристики поточности, с которыми может манипулировать

инспектор объектов на этапе проектирования.

На уровне TСomponent проявляется отношение "основной -

вспомогательный". Это отношение распространяется на все компоненты системы

С++Builder. Конструктор TСomponent, в отличие от конструкторов предыдущих

классов, имеет параметр AOwner типа TComponent *, указывающий основной

компонент для создаваемого компонента. Кроме того, TСomponent содержит ряд

свойств, характеризующих отношение "основной - вспомогательный".

Свойство TComponent* TComponent::Owner - указатель на основной

компонент. Доступно только для чтения и только во время выполнения приложения

(ReadOnly, RunTime). Форма является основной для всех помещенных на нее

компонент, приложение Application является основным для всех форм.

int TComponent::ComponentCount содержит количество вспомогательных

компонент для данного компонента (ReadOnly, RunTime).

int TComponent::ComponentIndex содержит индекс данного компонента в

списке основного компонента (ReadOnly, RunTime). Нумерация начинается с 0. При

отображении компоненты с меньшим индексом прорисовываются раньше. Изменить

Page 40: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

39

порядок для отображаемых компонент можно с помощью пунктов главного меню

Edit | Bring to Front и Edit | Send to Back, изменяющих также Z-порядок. Для

неотображаемых компонент с помощью пункта главного меню Edit | Creation Order.

TComponent* TComponent::Components[int Index] содержит массив указателей

вспомогательных компонент для данного компонента (ReadOnly, RunTime).

Нумерация начинается с 0. При вызове конструктора компонент помещается в

список Components компонента, указанного в качестве параметра. При вызове

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

компонент из списка с помощью методов void TComponent::InsertComponent

(TComponent* AComponent) и void TComponent::RemoveComponent (TComponent*

AComponent) соответственно. Внутренняя реализация этого массива представляет

собой два отдельных списка TList для отображаемых и неотображаемых компонент.

Отношение "основной - вспомогательный" отвечает за владение и удаление

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

вспомогательных компонент. При этом для всех компонент, помещенных на формы

в процессе проектирования, при освобождении обнуляются указатели на

соответствующие компоненты.

Свойство AnsiString TComponent::Name содержит имя компонента. При

помещении на форму имя компонента назначается автоматически на основе имени

класса. Например, Button1, Button2 и т.д. для класса TButton, это же имя будет

присвоено переменной, содержащей указатель на компонент. Рекомендуется

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

btnStop и т.д. Для динамически создаваемых во время выполнения компонент имя

может отличаться от имени переменной, допустимо значение NULL. Следует также

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

Caption или Text. Они содержат текстовые строки, отображаемые на самом

компоненте (название кнопки, содержимое поля ввода и т.д.). При добавлении

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

Однако они имеют принципиально другое назначение и используются лишь для

отображения компонента. Например, для нашего примера Caption может быть

«Старт» и «Стоп» для кнопок btnStart и btnStop.

Page 41: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

40

TComponent* TComponent::FindComponent (const AnsiString AName)

возвращает указатель экземпляра компонента с именем, указанным в качестве

параметра. Например:

void_fastcall TForm1::ButtonlClick(TObject *Sender)

{TEdit* EditInstance;

EditInstance = dynamic_cast<TEdit *>(FindComponent("Edit1"));

if (EditInstance) EditInstance->Text="new";}

TComponentState TComponent::ComponentState - текущее состояние

компонента. Список возможных значений: (csAncestor, csDesigning, csDestroying,

csFixups, csLoading, csReading, csUpdating,csWriting).

TComponentStyle TComponent::ComponentStyle - стиль, определяющий

поведение компонента (csInheritable, csCheckPropAvail).

int TComponent::Tag - свойство целого типа, которое не имеет

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

усмотрению программиста.

TComponent используется в качестве базового класса при создании невидимых

компонент.

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

элементы TControl обладают способностью отображать себя, некоторые свойства

этого класса оперируют с положением, размером и видом объекта (Top, Left, Width,

Height, BoundsRect, Cursor, Hint), а другие свойства относятся к параметрам

клиентской области (ClientRect, ClientWidth и ClientHeight). TControl также вводит

свойства, устанавливающие видимость, доступность, цвет и шрифт элементов

управления (Visible, Enabled, Color и Font). Свойства Text и Caption обеспечивают

установку редактируемых текстов и названий. Свойство ControlState задает

состояние органа управления (csLButtonDown, csClicked, csPalette, csReadingState,

csAlignmentNeeded, csFocusing, csCreating, csPaintCopy, csCustomPaint,

csDestroyingHandle, csDocking). Свойство ControlStyle определяет характеристики

органа управления (csAcceptsControls, csCaptureMouse, csDesignInteractive,

csClickEvents, csFramed, csSetCaption, csOpaque, csDoubleClicks, csFixedWidth,

csFixedHeight, csNoDesignVisible, csReplicatable, csNoStdEvents, csDisplayDragImage,

csReflector, csActionClient, csMenuEvents). Свойство Align задает выравнивание

Page 42: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

41

компонента относительно родительского компонента (alNone, alTop, alBottom,

alLeft, alRight, alClient), а свойство Anchor задает привязку к размерам

родительского компонента (множество из akLeft, akTop, akRight, akBottom).

Свойство Constraints позволяет задать максимальные и минимальные размеры

компонента. Метод SetBounds(int ALeft, int ATop, int AWidth, int AHeight) позволяет

изменить положение и размер компонента.

Все визуальные компоненты кроме отношения "основной-вспомогательный"

находятся также в отношении "старший-младший" или "родитель-ребенок". В

аналогичном отношении находятся все органы управления Windows. Поэтому уже у

TСontrol появляются некоторые свойства характеризующие это отношение.

Свойство TWinControl* TСontrol::Parent содержит указатель на родительский

компонент. Родительскими могут быть только оконные элементы управления, и

поэтому они должны быть производным от TWinControl. Сам компонент TControl не

может быть родителем, а может быть только дочерним компонентом. Для формы

значение свойства Parent задается как NULL.

Кроме того, имеются свойства ParentColor, ParentFont и ParentShowHint типа

bool которые определяют, будут ли в качестве значений свойств Color, Font и

ShowHint использоваться значения соответствующих свойств родительского

компонента.

Все координаты компонента задаются относительно родительского

компонента, при этом начало координат это левый верхний угол этого компонента

(так называемые локальные координаты). Существуют еще и глобальные

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

локальных координат в глобальные и наоборот используются функции TPoint

TControl::ClientToScreen(const TPoint &Point) и TPoint TControl::ScreenToClient(const

TPoint &Point) соответственно.

TControl содержит также методы ответственные за отображение органа

управления.

void TControl::Hide(void) делает текущий элемент управления невидимым, т.е.

устанавливает свойство Visible в false. При этом компонент всего лишь не

Page 43: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

42

отображается на экране, он не удаляется из динамической памяти и из списка

вспомогательного компонента, и все его методы и свойства остаются доступными.

void TControl::Show(void) отображает текущий элемент управления, т.е.

устанавливает свойство Visible в true.

void TControl::Repaint(void) перерисовывает текущий элемент управления.

Перерисовка происходит немедленно. При этом, если свойство ControlStyle

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

противном случае вызывается метод Invalidate, а затем Update для перерисовки

некоторой видимой части компонента.

void TControl::Refresh(void) вызывает метод Repaint.

void TControl::Invalidate(void) сообщает системе о том, что некоторая область

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

обработке сообщения о перерисовке после обработки всех сообщений находящихся

в очереди. Причем Invalidate может быть вызван несколько раз, до того момента как

произойдет непосредственно перерисовка.

void TControl::Update(void) позволяет немедленно обработать сообщение о

перерисовке. Таким образом, если для компонента до этого был вызван метод

Invalidate, это приведет к перерисовке.

Методы void TControl::BringToFront(void) и void TControl::SendToBack(void)

управляют Z-порядком компонента, помещая его на передний или задний план

соответственно.

Метод TControl::WndProc(TMessage &Message) обрабатывает поступившие

органу управления сообщения Message класса TMessage. Адрес этого метода

хранится в свойстве WindowProc, описанном в секции public. Это позволяет

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

каких-либо сообщений.

Таким образом, возможность обработки сообщений операционной системы

появляется уже в классе TControl. Этот класс обрабатывает только сообщения от

мыши, но его потомки способны обрабатывать и другие сообщения операционной

системы Windows. В результате обработки сообщений от мыши у класса TControl

появляются следующие события: OnClick, OnDblClick, OnMouseDown,

Page 44: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

43

OnMouseMove, OnMouseUp. Задав обработчики этих событий, можно определить

реакцию компонента на манипуляции мышью.

Кроме того, в классе TСontrol появляются также свойства, методы и события,

реализующие механизм Drag-and-Drop.

Класс TControl редко используется непосредственно, большинство компонент

являются производными от TWinControl или TGraphicControl.

Класс TWinControl является предком всех оконных элементов управления. С

каждым таким элементом управления связано окно («window») операционной

системы Windows. Производные от TWinControl компоненты обладают тремя

основными характеристиками: они имеют оконные дескрипторы (HWND), способны

принимать фокус ввода и могут являться родителями других элементов управления.

В классе TWinControl полностью определяется отношение "старший-младший", для

этого добавляются следующие свойства.

int TWinControl::ControlCount содержит количество младших элементов

управления для данного компонента (ReadOnly, RunTime).

TControl* TWinControl::Controls[int Index] содержит массив указателей

младших элементов управления для данного компонента (ReadOnly, RunTime).

Нумерация начинается с 0. Компонент добавляется и удаляется из соответствующих

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

компонента в список младших компонентов можно использовать методы void

TWinControl::InsertControl(TControl *AControl) и void TWinControl::RemoveControl

(TControl *AControl).

Метод bool TWinControl::ContainsControl(TControl* Control) определяет,

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

Control младшим для данного компонента непосредственно или косвенно.

TControl* TWinControl::ControlAtPos(TPoint &Pos, bool AllowDisabled)

возвращает указатель на младший компонент расположенный в заданных

координатах клиентской области данного компонента.

Таким образом, все компоненты С++Builder находятся в отношении

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

владение компонентами. Когда уничтожается основная компонента, уничтожаются

Page 45: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

44

и все вспомогательные компоненты. Для всех компонент, помещенных на форму,

основной является форма, для всех форм основным является приложение

Application, экземпляр класса TApplication. Таким образом, если приложение

завершается, то закрываются и все формы, и, соответственно, уничтожаются все

принадлежащие им компоненты. Причем для форм и приложения есть и обратное

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

в свойстве MainForm объекта Application. Обычно главной формой становится

первая созданная форма. Изменить главную форму можно в опциях проекта на

закладке Forms в поле MainForm. Закрытие главной формы приводит к завершению

приложения, что в свою очередь приводит к закрытию и всех остальных форм.

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

независимо от значения свойства Visible. Затем это форма может быть скрыта

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

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

закрытие пользователем всех остальных форм не приведет к завершению

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

приложения, то можно использовать свойство ShowMainForm объекта TApplication.

Все отображаемые компоненты связаны еще отношением "старший-младший".

Старшим компонентом может быть как сама форма, так и какой-либо

группирующий компонент, например TGroupBox. В общем случае старшим может

быть любой производный от TWinControl компонент, например TButton. Отношение

"старший-младший" отвечает за отображение компонентов. Таким образом, если

старший компонент перемещается, то перемещаются и все младшие, если он

скрывается, то скрываются и все младшие, если он становится недоступным, то

недоступны и все младшие. Все координаты компонента также задаются

относительно старшего компонента. Формы не имеют старшего компонента, и

значение свойства Parent у них равно NULL.

В классе TWinControl также появляются дополнительные характеристики,

отвечающие за отображение компонента.

Page 46: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

45

Свойство bool TWinControl::Showing определяет, может ли компонент быть

видимым, т.е. равно ли свойство Visible этого компонента и всех старших

компонент true.

Свойство bool TWinControl::CanFocus определяет, может ли компонент

принять фокус ввода, т.е. равны ли свойства Visible и Enabled этого компонента и

всех старших компонент true.

Свойство bool TWinControl::Focused возвращает значение true, если компонент

находится в фокусе ввода.

Метод void TWinControl::SetFocus(void) активизирует компонент, т.е. передает

ему фокус ввода.

Свойство bool TWinControl::TabStop – определяет, находится ли данный

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

при помощи клавиши TAB.

Свойство int TWinControl::TabOrder определяет положение в TAB-порядке

старшего компонента.

Свойство HWND TWinControl::Handle содержит оконный дескриптор объекта

Windows, который инкапсулирует компонент TWinControl. Этот дескриптор может

использоваться в Win32 API функциях для работы с компонентом как с обычным

окном системы Windows.

Кроме метода WndProc класс TWinControl имеет еще невиртуальный метод

void TWinControl::MainWndProc(TMessage &Message), который сообщается системе

Windows как функция окна. Внутри этого метода происходит попытка вызвать

метод, адрес которого хранится в свойстве WindowProc (по умолчанию WndProc), и

в случае неудачи вызывается Appliction->HandleException. В отличие от TControl,

класс TWinControl позволяет обрабатывать любые сообщения Windows. В частности

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

ввода, в результате чего у класса TWinControl появляются следующие события:

OnKeyDown, OnKeyPress, OnKeyUp, OnEnter и OnExit.

Метод void TWinControl::Broadcast(void *Message) используется для рассылки

сообщения Message всем младшим элементам управления. Благодаря этому методу

компоненты, наследованные от TControl, получают возможность обработки

Page 47: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

46

некоторых сообщений, например, сообщений от мыши, сообщений, связанных с

перерисовкой и т.д.

Большинство компонент не наследуются непосредственно от TWinControl.

Для стандартных органов управления существуют специализированные классы

TButtonControl, TCustomComboBox, TCustomEdit, TCustomListBox и т.д.

Дополнительные органы управления наследуются обычно от класса TCustomControl.

Компоненты, производные от класса TGraphicControl, в отличие от

TWinControl, не имеют оконного дескриптора, не имеют функции окна, не могут

принять фокус ввода и не могут являться родителями других элементов управления.

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

изобразить на форме текст или графику, не обращаясь к функциональным

возможностям обычных оконных элементов управления. Отметим следующие

достоинства такого подхода. Во-первых, TGraphicControl не пользуется системными

ресурсами Windows, так как не требует оконного дескриптора. Во-вторых, метод

рисования TGraphicControl исполняется немного быстрее за счет того, что

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

реализуется процессом рисования, заложенным в родителе данного компонента.

Свойство TCanvas * TGraphicControl::Canvas возвращает указатель на класс

TCanvas, предоставляющий холст для рисования. Класс TCanvas инкапсулирует GDI

возможности, предоставляемые операционной системой Windows. Он содержит

различные свойства и методы, позволяющие производить различные графические

операции. Свойство HDC TCanvas::Handle позволяет получить доступ к контексту

отображения, связанному с клиентской областью компонента. Этот дескриптор

может быть передан Win32 API GDI функциям для работы с контекстом

отображения непосредственно.

Метод void TGraphicControl::Paint(void) вызывается в ответ на сообщение

WM_PAINT, принимаемое родительским элементом управления. В классе

TGraphicControl этот метод является защищенным. Метод Paint переопределяется в

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

Основными потомками являются TСustomLabel, TShape, TImage.

Page 48: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

47

Класс TCustomControl, является непосредственным потомком TWinControl.

Однако подобно TGraphicControl в этом классе добавляются свойство Canvas и

метод Paint. Благодаря этому упрощается процедура рисования изображения

компонента.

Остальные компоненты в иерархии содержат специфичные свойства, методы

и события для различных групп компонентов (например, TButtonControl для кнопок)

и их рассмотрение выходит за рамки данного учебного пособия.

Вывод

Система С++Builder содержит большой набор различных компонент, основная

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

дальнейшим развитием классов, могут существовать как во время выполнения

приложения, так и на этапе проектирования. В дополнении к данным и функциям

класса, компоненты имеют также свойства и события. Все действия, доступные на

этапе проектирования (например, изменение значений свойств и назначение

обработчиков событий), программист может исполнять и на этапе выполнения. Все

компоненты находятся в отношении "основной-вспомогательный", все

отображаемые компоненты находятся в отношении "старший-младший".

Компоненты TWinControl позволяют обрабатывать любые сообщения Windows.

Любые функциональные возможности, предоставляемые системой и не

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

WIN32 API функций.

5. Работа с формами в C++Builder

5.1. Создание и уничтожение форм

Окна составляют основу функционирования практически любого приложения

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

несет важную функциональную нагрузку – именно функция окна в идеологии работы

Page 49: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

48

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

Поэтому форма системы C++Builder является основой любого приложения. При

создании нового проекта (пункт меню File | New | Application) форма добавляется в

проект автоматически. Большинство приложений используют несколько окон.

Включение в проект новой формы осуществляется командой File | New Form или

командой File | New | Other с последующим выбором формы в Хранилище, например,

из вкладок Forms или Dialogs. По умолчанию все формы создаются автоматически при

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

[1]. Главная форма отличается от прочих рядом свойств. Во-первых, именно этой

форме передается управление в начале выполнения приложения. Во-вторых,

закрытие пользователем главной формы означает завершение выполнения

приложения. В-третьих, существуют специальные соглашения о порядке скрытия

главной формы, о них говорилось в главе 4.2.

У программиста существует возможность изменения порядка создания

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

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

точки зрения расходования памяти. Если некоторое окно должно вызываться в

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

(например, диалоговое окно для изменения параметров системы), то хранить это

окно все время работы программы, просто не отображая его на экране, будет очень

неэффективным подходом. Для приложений, работающих в многооконном режиме

(MDI) вообще неизвестно заранее, сколько окон одновременно захочет открыть

пользователь при работе с программой.

Изменить принятые по умолчанию условия относительно форм можно в

окне опций проекта, которое вызывается командой Project | Options главного меню.

В открывшемся окне свойств проекта (Project Options) среди прочих есть закладка

Forms, которая определяет свойства добавленных в проект форм (рис 5.1).

Page 50: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

49

Рисунок 5.1 – Окно свойств проекта, закладка «Формы»

В этом окне можно определить, будет ли та или иная форма создаваться

автоматически (в этом случае ее название необходимо поместить в левый список Auto-

create forms) или будет доступной для создания уже в момент работы программы (правый

список, Available forms). Здесь же определяется, какая из форм будет считаться главной в

приложении (Main form). Главной может быть только форма из левого списка.

Согласно уже описанной выше технологии двунаправленной разработки,

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

Действительно, если посмотреть на содержимое основного файла проекта (Project1.cpp),

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

вставляется вызов макроса USEFORM. Назначение этого макроса – подключение файла с

кодом формы к проекту. Вызов макроса для формы Form1, например, будет выглядеть

следующим образом:USEFORM("Unit1.cpp", Form1);

Первый параметр макроса содержит имя файла модуля, соответствующего

форме (например, "Unit1.cpp"), а второй параметр — имя формы.

Помимо этого, в текст программы добавляются команды создания тех форм,

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

реализуются как вызовы метода CreateForm объекта Application:Application->CreateForm(__classid(TForm4), &Form4);

Page 51: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

50

Application->CreateForm(__classid(TForm3), &Form3);

При этом создание главной формы (для нашего примера – Form4) производится

первым. Остальные формы (Form1, Form2) в момент запуска программы не создаются, но

программист может в любой момент создать их, вызвав метод CreateForm. Например, из

файла модуля третьей или четвертой формы можно создать форму Form2 при помощи

следующего вызова:Application->CreateForm(__classid(TForm2), &Form2);

Такой вызов не сработает, если не предпринять дополнительных действий. Дело в

том, что файлы каждой формы обособлены, и для файла Unit3.cpp, в котором мы

предположительно создаем новую форму, класс TForm2 и указатель Form2 неизвестны, в

связи с чем возникнет ошибка на этапе его компиляции. Решением является

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

строки#include “Unit2.cpp”

Эту строку можно ввести в код вручную, а можно воспользоваться специальной

командной оболочки File | Include Unit Hdr, которая добавит эту строку автоматически.

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

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

одной из форм обращается к свойствам, событиям или методам другой формы.

После создания формы в нее приходит ряд стандартных сообщений Windows,

которые соответствую различным стадиям формирования окна – создание объекта

«окно» в памяти, отображение окна, установка размеров окна, отображение

клиентской области окна. Для формы программы, написанной в C++Builder, эти

сообщения проявляются в виде событий. Перечень событий в порядке их

возникновения в форме можно посмотреть в таблице 5.1.

Таблица 5.1.

События, возникающие при создании формы

Событие ОписаниеOnCreate создание формы и всех ее компонент

OnShow отображение формы на экране

Page 52: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

51

Продолжение таблицы 5.1.OnActivate фокус ввода передается форме

OnEnter фокус передается компоненту формы, первому впоследовательности табуляции

OnResize переустанавливаются размеры формыOn Paint прорисовка клиентской области формы

В отличие от остальных событий в таблице, событие OnCreate возникает

однократно для каждой формы. Это происходит в момент ее создания, когда ни

один компонент формы, ни сама она еще не отображены на экране. Этот факт

позволяет программистам в обработчике события OnCreate осуществлять

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

При этом, если свойство OldCreateOrder формы установлена в false, то событие

OnCreate возникнет после окончания работы конструкторов всех компонентов

формы.

Событие OnShow возникает, когда форма отображается на экране либо при

создании, либо при вызове методов Show и ShowModal. Скрыть форму можно

методом Hide, при этом возникает событие OnHide.

В любой момент форму можно закрыть, для этого используется метод Close.

При этом форма не закрывается автоматически, а происходит каскадный вызов

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

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

Первым при обработке команды Close возникает событие OnCloseQuery. Когда

срабатывает это событие, окно остается видимым на экране. Прототип

обработчика этого события выглядит следующим образом:void __fastcall TForm1::FormCloseQuery(TObject *Sender,

bool &CanClose);

Первый параметр, как и для большинства событий, передает адрес

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

может принимать значения true и false, причем, так как он определен в виде ссылки,

присвоенное ему значение будет выходным. В обработчике события OnCloseQuery

принимается решение – разрешить или нет процедуру закрытия окна. Это решение

может быть принято по текущему состоянию приложения, по запросу разрешения у

Page 53: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

52

пользователя, каким либо иным способом, но оформляется оно путем присвоения

значения параметру CanClose: если присвоить ему true, то процесс закрытия окна

разрешается, если false – запрещается. По умолчанию параметру CanClose

присваивается истинное значение. Следующий пример иллюстрирует, как

реализовать запрос на разрешение закрытия программы у пользователя:void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool

&CanClose){ if(MessageBox(NULL,"Действительно закрыть окно","Внимание!",

MB_OKCANCEL)!=IDOK) CanClose=false;}

Если в обработчике события OnCloseQuery разрешено закрытие окна или

этому событию вообще не сопоставлен обработчик, то возникает событие OnClose.

При срабатывании этого события форма по-прежнему отображена на экране,

поэтому отменить закрытие можно и в обработчике OnClose. Прототип обработчика

OnClose выглядит следующим образом:void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction

&Action)

Здесь особого внимания заслуживает параметр Action, который также

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

Параметр Action может принимать следующие значения:

caNone - не закрывать форму;

caHide - сделать форму невидимой;

caMinimize - свернуть форму в пиктограмму на панели задач;

caFree - уничтожить форму.

Если в обработчике события OnClose присвоить параметру значение caNone,

то процедура закрытия окна будет прекращена, и оно останется на экране в прежнем

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

перенести в обработчик OnClose:void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction&Action){if(MessageBox(NULL,"Действительно закрыть окно","Внимание!",

MB_OKCANCEL)!=IDOK) Action=caNone}

Page 54: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

53

Если параметру Action присвоить значение caHide, то окно станет невидимым,

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

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

например, метод Show. Необходимо отметить, что параметр Action по умолчанию

принимает значение caHide для всех окон, стиль которых в свойстве FormStyle задан

не как fsMDIForm или fsMDIChild. Поэтому, если необходимо уничтожить такое

окно, для него недостаточно просто вызвать метод Close, потому что окно скроется

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

добавление для формы обработчика события OnClose с обработчиком вида

Action=caFree, либо удаление формы после вызова метода Close стандартной

операцией delete (последнее замечание не относится к главной форме приложения,

которая удаляется при вызове метода Close).

Присвоение параметру Action значения caMinimize приводит к сворачиванию

окна в пиктограмму. Это значение присваивается по умолчанию для дочерних MDI-

окон.

Если же параметру Action присвоить значение caFree, то будет разрешено

удаление формы. После этого процесс удаления формы становится необратимым,

для формы сработает еще одно событие OnDestroy. В момент возникновения этого

события окно уже невидимо на экране, отменить его уничтожение невозможно,

основное назначение обработчика события OnDestroy – корректное завершение

работы формы, очистка памяти от объектов, ею использовавшихся. Уничтожить

форму можно, минуя последовательность событий OnCloseQuery, OnClose,

OnDestory. Если вызвать для формы метод Free или уничтожать ее операцией delete,

то сразу возникает событие OnDestroy и форма удалится из памяти.

5.2. Модальный режим работы форм

Если отобразить форму методом ShowModal, то она будет работать в

модальном режиме. Модальный режим означает, что весь фокус ввода в

приложении сосредоточен на данной форме, и пользователь не сможет работать с

другими формами приложения, пока не закроет модальное окно. Фактически, для

Page 55: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

54

модального окна система создает свою очередь сообщений, и все сообщения

приложения приходят только в это окно. Модальный режим чаще всего

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

Необходимо также отметить, что модальность – это режим работы окна, а не какое-

то его свойство, которое необходимо определить для него при проектировании.

Одна и та же форма может быть отображена как в нормальном режиме (методом

Show), так и в модальном (методом ShowModal).

Работа модального окна отличается от обычного окна только способом

закрытия окна. За закрытие модального окна отвечает свойство ModalResult.

Первоначально это свойство хранит нулевое значение. Изменение значения этого

свойства (присвоение ему ненулевого значения) приводит к закрытию формы. Всего

для свойства ModalResult предусмотрено 11 различных значений от 0 до 10 (в

C++Builder 6). Перечень этих значений приведен в таблице 5.2.

Таблица 5.2.

Возможные значения свойства ModalResult формы

Константа С++Builder Знач. Для чего используетсяmrNone 0 Значение по умолчаниюmrOk (idOk) 1 Форма закрыта нажатием кнопки OkmrCancel (idCancel) 2 Форма закрыта кнопкой Cancel, вызовом метода

Close либо кнопкой закрытия в заголовке окнаmrAbort (idAbort) 3 Форма закрыта нажатием кнопки AbortmrRetry (idRetry) 4 Форма закрыта нажатием кнопки RetrymrIgnore (idIgnore) 5 Форма закрыта нажатием кнопки IgnoremrYes (idYes) 6 Форма закрыта нажатием кнопки YesmrNo (idNo) 7 Форма закрыта нажатием кнопки NomrAll (idAll) 8 Форма закрыта нажатием кнопки AllmrNoToAll (idNoToAll) 9 Форма закрыта нажатием кнопки NoToAllmrYesToAll (idYesToAll) 10 Форма закрыта нажатием кнопки YesToAll

Таким образом, присвоение ModalResult значения от 1 до 10 имитирует

нажатие одной из кнопок закрытия окна из стандартного набора Windows. Окно,

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

этого необходимо сравнить результат, возвращаемый функцией ShowModal, с

Page 56: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

55

константами из таблицы 5.2 (этот метод, очевидно, прерывает работу кода до

момента закрытия модального окна):Application->CreateForm(__classid(TForm2), &Form2);

int mr=Form2->ShowModal(); if(mr==mrOk) {MessageBox(NULL,"Окно закрыто нажатием кнопкиОК","Внимание",MB_OK); //работа с компонентами формы Form2, измененными пользова //телем при работе с ней в модальном режиме } delete Form2;

В коде формы Form2 необходимо в таком случае в тот момент, когда

требуется закрыть форму, выполнить присваивание ModalResult=mrOk.

Альтернативным вариантом является использование свойства ModalResult кнопок

типа TButton или TBitBtn. Задав для этого свойства кнопки на форме одно из

значений из таблицы 5.2, программист определит, что при нажатии этой кнопки

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

ModalResult кнопки.

5.3. Многодокументный интерфейс (MDI)

Многие современные приложения поддерживают многооконный режим

работы, когда в каждом окне осуществляется работа с отдельным документом.

Подобный интерфейс имеет устоявшийся протокол взаимодействия окон, когда

одно из окон является главным, а остальные – дочерними. Назначение главного окна

– управлять дочерними окнами, меню этого окна обычно содержит команды

создания, удаления дочерних окон, изменения порядка их расположения в

клиентской области главного окна. Закрытие родительского окна ведет к

завершению работы всего приложения. Дочерние окна предназначены для

отображения редактируемого документа. В помощь программисту для реализации

подобного интерфейса приложения Windows поддерживает спецификацию MDI

(Multiple Document Interface). На уровне операционной системы MDI

поддерживается специальным набором API-функций и сообщений. Для

Page 57: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

56

программиста на C++Builder MDI интерфейс доступен как набор свойств и методов

все того же компонента TForm.

Для того, чтобы объявить форму родительской MDI-формой, необходимо

присвоить ее свойству FormStyle значение fsMDIForm. Для дочерней формы это

свойство необходимо установить в fsMDIChild. Дочернюю форму необходимо

отнести к доступным для создания формам (рис. 5.1), поскольку дочерние окна

должны создаваться пользователем в процессе работы программы. Тогда код

создания дочерней формы должен выглядеть следующим образом:void __fastcall TForm1::new1Click(TObject *Sender){ TForm2 *child=new TForm2(Application); child->Show();}Для управления созданными дочерними окнами можно использовать

несколько свойств и методов. Прежде всего, необходимо обратить внимание на

массив MDIChildren, который для главной MDI-формы хранит адреса всех

существующих на данный момент дочерних окон. При этом количество дочерних

окон можно получить из свойства MDIChildCount. Адрес активной дочерней формы

хранится в свойстве ActiveMDIChild. Пример переименования всех дочерних окон

приведен в следующем листинге:for(i=0;i<MDIChildCount;i++) MDIChildren[i]->Caption="Window"+IntToStr(i+1);

Порядок расположения дочерних окон в клиентской области родительского

окна можно изменять вызовами методов Tile и Cascade для главной формы. Метод

Tile выстраивает дочерние окна рядом друг с другом, в зависимости от значения

свойства TileMode они выстраиваются по горизонтали (tbHorizontal) или по

вертикали (tbVertical). Метод Cascade выстраивает дочерние окна каскадом. Для

упорядочивания свернутых в пиктограмму дочерних окон в клиентской области

родительского окна используется метод ArrangeIcons.

Особенностью работы дочерних MDI-окон является то, что при закрытии их

методом Close или нажатием кнопки закрытия окна в его заголовке они по

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

Page 58: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

57

только если в обработчике события OnClose дочернего MDI-окна присваивать

параметру Action значения caFree или caHide.

Еще одна особенность взаимодействия родительского и дочерних MDI-окон –

встраивание меню дочернего окна в состав родительского. Если для дочернего окна

спроектировано меню (чаще всего оно включает команды для работы с

документом), то оно будет встроено в меню родительского окна (которое обычно

содержит команды управления окнами). Порядок следования пунктов меню

дочернего окна в родительском меню, а, следовательно, и место встраивания меню

дочернего окна определяется значением свойства GroupIndex каждого раздела меню.

Именно поэтому, если не изменять значения свойства GroupIndex у меню

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

собой первое, что является очень распространенной ошибкой начинающих

программистов. Это происходит потому, что их свойствам GroupIndex по

умолчанию присваиваются одинаковые значения, и при появлении дочернего окна

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

родительского меню. Задача программиста – следить, чтобы пункты меню

родительского и дочернего окон имели различные значения свойства GroupIndex.

Вывод

Форма является основным компонентом в проекте приложения на C++Builder,

что обусловлено особенной ролью окна в ОС Windows. Формы C++Builder

реализуются на основе класса TForm, который позволяет программисту отслеживать

основные стадии работы окна: создание, отображение, перерисовка, закрытие,

уничтожение, а также управлять окном и его подчиненными элементами. Для форм

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

режиме фокусирует на себя весь ввод информации в приложение. Если приложение

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

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

Page 59: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

58

6. Работа с клавиатурой и мышью в среде C++Builder

Любое интерактивное приложение должно реагировать на события от

клавиатуры и мыши. Рассмотрим, каким образом можно работать с клавиатурой и

мышью в приложениях, разработанных в среде C++Builder. Для начала рассмотрим

общую схему аппаратного ввода, реализованную в операционных системах

семейства Windows. Все аппаратные события, связанные с клавиатурой и мышью,

обрабатываются драйверами соответствующих устройств и попадают в системную

очередь аппаратного ввода (system hardware input queue, SHIQ). При запуске

системы создается особый поток необработанного ввода (raw input thread, RIT),

который извлекает очередной элемент из очереди SHIQ и на его основе формирует

соответствующие сообщения Windows. Это сообщения: WM_KEYDOWN – нажата

клавиша на клавиатуре, WM_KEYUP – отпущена клавиша на клавиатуре,

MW_MOUSEMOVE – курсор мыши был перемещен, WM_?BUTTONDOWN –

нажата кнопка мыши, WM_?BUTTONUP – отпущена кнопка мыши,

WM_?BUTTONDBLCLK – двойное нажатие кнопки мыши (вместо ‘?’ могут быть

буквы L,R и M отвечающие, соответственно, за левую, правую и среднюю кнопку

мыши). Эти сообщения направляются в очереди виртуального ввода (virtualized

input queue, VIQ) нужного потока [3]. Далее они извлекаются в цикле обработки

сообщений приложения и поступают на обработку в соответствующую функцию

окна. В упрощенном виде необходимый поток выбирается следующим образом: для

событий мыши – это поток, создавший окно, над которым находится курсор мыши;

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

время.

В приложениях, разработанных в среде С++Builder, можно непосредственно

производить обработку соответствующих сообщений WM_*. Однако среда

С++Builder упрощает обработку аппаратного ввода для визуальных компонентов с

помощью механизма событий. Как уже отмечалось выше, все визуальные

компоненты (наследники TControl) имеют возможность обработки событий от

мыши. Все же оконные компоненты (наследники TWinControl) имеют также

Page 60: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

59

возможность обработки событий от клавиатуры. Рассмотрим основные из этих

событий более подробно.

6.1. Интерфейс работы с мышью в C++Builder

Событие void TControl::OnMouseMove (__fastcall * (__closure)(TObject*

Sender, TShiftState Shift, int X, int Y)) возникает при перемещении курсора мыши

над органом управления. Принцип работы механизма событий был описан в главе 4.

В отличие от стандартных событий, событие OnMouseMove имеет три

дополнительных параметра: Shift, X, Y. Параметры X и Y определяют координаты

курсора мыши в клиентской области объекта Sender. Параметр Shift - это

переменная типа множество, определяющая состояние функциональных клавиш Alt,

Ctrl и Shift, а также кнопок мыши в момент постановки сообщения в очередь.

Множество может содержать различные комбинации следующих флагов: ssShift –

нажата клавиша Shift, ssAlt - нажата клавиша Alt, ssCtrl - нажата клавиша Ctrl, ssLeft

- нажата левая кнопка мыши, ssRight - нажата правая кнопка мыши, ssMiddle -

нажата средняя кнопка мыши, ssDouble - произведено двойное нажатие кнопки

мыши.

Событие void TControl::OnMouseDown (__fastcall * (__closure)(TObject*

Sender, TMouseButton Button, TShiftState Shift, int X, int Y)) возникает при нажатии

кнопки мыши. Параметры Shift, X,Y аналогичны предыдущему событию. Параметр

Button - переменная типа перечисление, определяет, какая кнопка мыши была

нажата. Он может содержать один из следующих флагов: mbLeft - нажата левая

кнопка мыши, mbRight - нажата правая кнопка мыши, mbMiddle - нажата средняя

кнопка мыши.

Событие void TControl::OnMouseUp (__fastcall * (__closure)(TObject* Sender,

TMouseButton Button, TShiftState Shift, int X, int Y)) возникает при отпускании

кнопки мыши. Параметры аналогичны событию OnMouseDown.

Событие void TControl::OnDblClick (__fastcall * (__closure)(TObject* Sender))

возникает при двойном нажатии левой кнопки мыши над объектом Sender. Данное

событие доступно только для компонентов с установленным флагом csDoubleClicks

Page 61: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

60

в свойстве ControlStyle. В противном случае двойное нажатие будет

интерпретироваться как два одинарных нажатия кнопки мыши.

Событие void TControl::OnClick (__fastcall * (__closure)(TObject* Sender))

возникает когда пользователь выполняет действие “click” (щелчок) над объектом

Sender. Обычно это происходит при нажатии и отпускании левой кнопки мыши над

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

пользователя. Например, для кнопки это нажатие клавиши “Spacebar” если кнопка

находилась в фокусе ввода, для кнопки-переключателя (“CheckBox”) – изменение

значения свойства Checked. Таким образом, данное событие связано не только с

обработкой сообщений от мыши.

6.2. Интерфейс работы с клавиатурой в C++Builder

Событие void TWinControl::OnKeyDown (__fastcall * (__closure)(TObject*

Sender, unsigned short &Key, TShiftState Shift)) возникает при нажатии клавиши на

клавиатуре для компонента, имеющего фокус ввода. Параметр Shift аналогичен

одноименному параметру для событий от мыши. Параметр Key содержит код

нажатой клавиши. Для алфавитно-цифровых клавиш код совпадает с ASCII кодом

соответствующего клавише символа, приведенного к верхнему регистру. Например,

‘S’ , ‘7’ и т.д. Для остальных клавиш используется виртуальный код клавиши,

задаваемый константами VK_*. Например, VK_F1, VK_TAB , VK_RETURN и т.д.

Заметим, что параметр Key передается по ссылке и может быть изменен в

обработчике.

Событие void TWinControl::OnKeyUp (__fastcall * (__closure)(TObject* Sender,

unsigned short &Key, TShiftState Shift)) возникает при отпускании ранее нажатой

клавиши на клавиатуре. Параметры аналогичны предыдущему сообщению.

Событие void TWinControl::OnKeyPress (__fastcall * (__closure)(TObject*

Sender, char &Key)) возникает при нажатии и отпускании алфавитно-цифровой

клавиши на клавиатуре. Параметр Key содержит ASCII символ, сгенерированный в

результате нажатия клавиши. Заметим, что нажатие функциональных клавиш, таких

как Ctrl или F10 не приводит к генерации данного события. Кроме того, параметр

Page 62: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

61

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

получения. Например, нажатие комбинации клавиш Shift-‘S’ при выключенном

режиме CapsLock или клавиши ‘S’ при включенном приведут к генерации этого

события с ASCII кодом ‘S’. Причем нажатие клавиши Shift не приведет к генерации

OnKeyPress. Аналогично предыдущим событиям, параметр Key передается по

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

производить фильтрацию ввода и ограничить набор доступных для ввода символов.

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

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

который имеет фокус ввода. Таким образом, клавиатурные события для формы

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

фокуса ввода. Однако существует специальное свойство KeyPreview компонента

TForm. Если оно содержит значение true, то все клавиатурные события будут

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

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

6.3. Пример использования событий мыши и клавиатуры в C++Builder

Рассмотрим небольшой пример, показывающий практическое применение

всех рассмотренных выше событий. Форма содержит компонент TestStringGrid типа

TStringGrid, для которого определены обработчики OnMouseDown, OnMouseUp и

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

содержимого ячеек. Для этого необходимо, нажав клавиши Ctrl и Alt и удерживая

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

форме содержится компонент TestMemo типа TMemo, для которого определен

обработчик OnKeyDown. В данном обработчике реализованы следующие действия:

удаление текущей строки при нажатии комбинации Ctrl-Y, выделение всего текста

при нажатии комбинации Ctrl-A и изменение типа выравнивания текста при

нажатии клавиши F2. На форме содержится компонент TestEdit типа TEdit, для

которого определен обработчик OnKeyPress. Данный обработчик позволяет вводить

в поле ввода только цифры и буквы для шестнадцатеричного представления числа.

Page 63: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

62

Кроме того, ввод возможен как в русской, так и в английской раскладке и в любом

регистре. Во всех случаях ввод будет преобразован в прописные латинские

символы. А для самой формы определен обработчик OnKeyUp, который позволяет

завершить работу приложения при нажатии комбинации клавиш Ctrl-Alt-Q.

Свойство KeyPreview должно быть установлено в true. Ниже приведен исходный

код данного примера.

Листинг 6.1. Использование событий мыши и клавиатуры в приложениях//*************testinput.h *******************

typedef struct TTr

{char from;

char to;

} *PTr;

class TTestForm : public TForm

{__published: // IDE-managed Components

TStringGrid *TestStringGrid;

TMemo *TestMemo;

TEdit *TestEdit;

void __fastcall FormCreate(TObject *Sender);

void __fastcall TestStringGridMouseDown(TObject *Sender,

TMouseButton Button, TShiftState Shift, int X, int Y);

void __fastcall TestStringGridMouseMove(TObject *Sender,

TShiftState Shift, int X, int Y);

void __fastcall TestStringGridMouseUp(TObject *Sender,

TMouseButton Button, TShiftState Shift, int X, int Y);

void __fastcall TestEditKeyPress(TObject *Sender, char &Key);

void __fastcall TestMemoKeyDown(TObject *Sender, WORD &Key,

TShiftState Shift);

void __fastcall FormKeyUp(TObject *Sender, WORD &Key,

TShiftState Shift);

private: // User declarations

bool Moving;

TPoint MovedCell;

TTr TrChar[28];

TAlignment algn[3];

public: // User declarations

Page 64: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

63

__fastcall TTestForm(TComponent* Owner);

};

extern PACKAGE TTestForm *TestForm;

//*************testinput.cpp *******************

TTestForm *TestForm;

__fastcall TTestForm::TTestForm(TComponent* Owner) : TForm(Owner)

{ int i;

Moving=false;

MovedCell.x=0;MovedCell.y=0;

algn[0]=taLeftJustify;

algn[1]=taCenter;

algn[2]=taRightJustify;

for (i='a';i<='f';i++)

TrChar[i-'a'].from=i;

for (i='A';i<='F';i++)

{TrChar[i-'A'].to=i;TrChar[i-'A'+6].to=i;TrChar[i-'A'+12].to=i;}

TrChar[6].from='ф';TrChar[12].from='Ф';

TrChar[7].from='и';TrChar[13].from='И';

TrChar[8].from='с';TrChar[14].from='С';

TrChar[9].from='в';TrChar[15].from='В';

TrChar[10].from='у';TrChar[16].from='У';

TrChar[11].from='а';TrChar[17].from='А';

for (i='0';i<='9';i++)

{TrChar[i-'0'+18].from=i;TrChar[i-'0'+18].to=i;}

}

void __fastcall TTestForm::FormCreate(TObject *Sender)

{ randomize();

TestStringGrid->FixedCols=0;TestStringGrid->FixedRows=0;

for (int i=0 ;i<TestStringGrid->RowCount;i++)

for (int j=0 ;j<TestStringGrid->ColCount;j++)

TestStringGrid->Cells[i][j]=rand() %100;

}

void __fastcall TTestForm::TestStringGridMouseDown(TObject

*Sender, TMouseButton Button, TShiftState Shift, int X, int Y)

{ if (Button==mbRight && Shift.Contains(ssCtrl) &&

Shift.Contains(ssAlt))

Page 65: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

64

{ int tx,ty;

TGridRect tgr;

Moving=true;

TestStringGrid->MouseToCell(X,Y,tx,ty);

MovedCell.x=tx;MovedCell.y=ty;

tgr.Left=tx;tgr.Top=ty;tgr.Right=tx;tgr.Bottom=ty;

TestStringGrid->Selection=tgr;

}

}

void __fastcall TTestForm::TestStringGridMouseMove(TObject

*Sender, TShiftState Shift, int X, int Y)

{ if (Moving) TestStringGrid->Cursor=crHandPoint; }

void __fastcall TTestForm::TestStringGridMouseUp(TObject *Sender,

TMouseButton Button, TShiftState Shift, int X, int Y)

{ if (Moving && Button==mbRight)

{ int tx,ty;

AnsiString tstr;

Moving=false;

TestStringGrid->Cursor=crDefault;

TestStringGrid->MouseToCell(X,Y,tx,ty);

tstr=TestStringGrid->Cells[tx][ty];

TestStringGrid->Cells[tx][ty]=TestStringGrid->

Cells[MovedCell.x][MovedCell.y];

TestStringGrid->Cells[MovedCell.x][MovedCell.y]=tstr;

}

}

void __fastcall TTestForm::TestEditKeyPress(TObject *Sender, char

&Key)

{int i,n;

n=sizeof(TrChar)/sizeof(TrChar[0]);

for (i=0;i<n;i++)

if (Key==TrChar[i].from) {Key=TrChar[i].to;break;}

if (i==n)

{for (i=0;i<n;i++)

if (Key==TrChar[i].to) break;

if (i==n) Key=0;}}

Page 66: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

65

void __fastcall TTestForm::TestMemoKeyDown(TObject *Sender, WORD

&Key, TShiftState Shift)

{static int i=1;

if (Shift.Contains(ssCtrl))

{if (Key=='Y') TestMemo->Lines->Delete(TestMemo->CaretPos.y);

else if (Key=='A') TestMemo->SelectAll(); }

if (Key==VK_F2) TestMemo->Alignment=algn[i++%3];

}

void __fastcall TTestForm::FormKeyUp(TObject *Sender, WORD &Key,

TShiftState Shift)

{ if (Key=='Q' && Shift.Contains(ssAlt) &&

Shift.Contains(ssCtrl))

Application->Terminate();}

Вывод

Среда С++Builder предоставляет для программиста возможность обработки

большинства сообщений, отвечающих за аппаратный ввод в системах семейства

Windows. Эти сообщения доступны программисту в виде соответствующих

событий, упрощающих работу с клавиатурой и мышью. Кроме того, программист

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

сообщений Windows от клавиатуры и мыши для реализации каких-либо

специфичных функций приложения.

7. Графика в C++Builder

7.1. Основы графического интерфейса Windows

В операционной системе Windows за графический интерфейс отвечает группа

специализированных функций API, имеющая общее название GDI (Graphic Device

Interface) [6]. Эти функции отвечают за отображение графических примитивов на

устройстве отображения (окружности, линии, прямоугольники и т.п.), настройку

основных инструментов отображения (цвет, тип линий, шрифт), получение

Page 67: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

66

информации об устройстве отображения. Располагаются функции GDI в файлах

gdi.dll и gdi32.dll. Основным достоинством GDI является то, что посредством него

унифицируется работа с различными устройствами отображения. Это означает, что

вывод графической информации на экран монитора, принтер или плоттер

выполняется в приложении Windows совершенно единообразно, а особенности того

или иного устройства отображения учитываются уже самим модулем GDI в диалоге

с драйвером устройства. Подобная универсальность достигается за счет

использования контекста отображения для устройства. Контекст отображения

представляет собой структуру данных, описывающую основные характеристики

устройства, с которым он связан (размер, тип, разрешение, используемая система

координат и др.). Таким образом, для вывода информации на то или иное

устройство отображения (в том числе – в окно приложения), программист должен

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

Взаимодействие прикладной программы и устройства отображения в Windows

показано на рис. 7.1.

Еще одна важная функция GDI – работа с инструментами рисования. Для

отображения графической информации в Windows используется большое

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

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

стандартного, программист должен создать этот шрифт специальной GDI-функцией

и выбрать этот шрифт в контекст отображения. После этого функции вывода текста

будут использовать именно этот шрифт для формирования изображения. В листинге

7.1 приведен пример вывода информации в окно Windows с использованием

функций GDI.

Листинг 7.1. Пример работы с функциями GDIHDC hdc;HPEN hPen;HFONT hFont;

hdc=GetDC(hWnd); //Получить контекст окна с дескриптором hWnd

Прикладнаяпрограмма

Контекстотображения

Драйверустройства

Устройствоотображения

Рис. 7.1. Порядок вывода графической информации в Windows

Page 68: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

67

hPen=CreatePen(PS_SOLID,4,RGB(255,0,0)); //создать перо

SelectObject(hdc,hPen); //выбрать перо в контекст отображения

Ellipse(hdc,100,100,200,200); //нарисовать эллипс

hFont=CreateFont(20,10,0,0,FW_THIN,TRUE,TRUE,FALSE,ANSI_CHARSET,

OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,NULL);

//создать шрифт

SelectObject(hdc,hFont); //выбрать шрифт в контекст отображения

TextOut(hdc,150,150,"HELLO",5); //отобразить текст

ReleaseDC(hWnd,hdc); //освободить контекст отображения

DeleteObject(hPen); DeleteObject(hFont);//уничтожить GDI-объекты

7.2. Обзор графических компонент C++Builder

Приведенный в листинге 7.1 фрагмент программы иллюстрирует проблемы

программирования с использованием API: громоздкость кода для выполнения даже

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

требовательность к квалификации программиста. С++Builder предлагает ряд

компонент для отображения графической информации. Достоинства этих компонент

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

освобождения контекстов отображения, создания и удаления тех или иных

инструментов рисования они берут на себя, предоставляя программисту

возможность сосредоточиться на процессе формирования нужного ему

изображения.

Перечень основных графических компонент и их место в общей схеме

иерархии классов VCL приведен на рис.7.2 (графические компоненты выделены).

Графические компоненты С++Builder охватывают различные аспекты работы с

графикой. Компонент TCanvas предоставляет пользователю удобный интерфейс для

доступа к функциям GDI. Не являясь самостоятельным компонентом, объект типа

TCanvas используется как свойство других компонент (например, TForm или

TPrinter), заменяя собой контекст отображения. Таким образом, рисуя на канве,

программист формирует изображение на том компоненте, которому данная канва

принадлежит. Компонент TGraphic и производные от него классы позволяют

Page 69: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

68

работать с растровыми изображениями некоторого ресурса (битового изображения,

метафайла, файла в формате jpeg). Компонент TPicture представляет собой

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

типа TGraphic. Таким образом, TPicture выступает как объект, в котором могут

храниться битовый образ, пиктограмма или метафайл. Сам же объект типа TPicture

может быть свойством другого компонента (например, TImage), представляя, таким

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

7.3. Компонент TCanvas

Компонент TCanvas представляет удобный объектно-ориентированный

интерфейс с функциями GDI. При этом он не требует от программиста знания

нюансов реализации графического интерфейса Windows, его методы и свойства

позволяют непосредственно выводить информацию или задавать параметры вывода.

Для опытных пользователей канва предоставляет дескриптор контекста

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

функции GDI.

Основные свойства и методы компонента TCanvas приведены в таблицах 7.1 и

7.2.

TObject

TPersistent

TInerfacedPersistent

TGraphic

TBitmap TIcon TMetaFile

TPicture

TCanvas

Рис.7.2. Фрагмент схемы иерархии VCL с графическими компонентами

TJPEGImage

Page 70: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

69

Таблица 7.1.

Свойства компонента TCanvas

Свойство Назначение

Pen Перо. Предназначено для установки параметров отображениялиний (цвет, стиль, толщина). Экземпляр класса TPen

Brush Кисть. Предназначено для установки параметров заливкиобъектов (цвет, текстура). Экземпляр класса TBrush

Font Шрифт. Определяет параметры выводимого текста (цвет,размер, стиль). Экземпляр класса TFont

PenPos Текущая позиция пера. Используется как опорная точка внекоторых функциях вывода (MoveTo, LineTo)

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

Pixels Массив цветов точек канвы. Представляет собой двумерныймассив элементов типа TColor, каждый из которых Pixels[x,y]хранит цвет точки с координатами (x,y) холста (канвы)

Handle Дескриптор контекста отображения устройства вывода, скоторым связана канва

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

Таблица 7.2.

Методы компонента TCanvas

Методы Назначение

MoveTo Изменяет позицию пера

LineTo Рисует линию от позиции пера к указанной точке

Arc, Ellipse,Rectangle, Pie,Chord

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

Polygon, Polyline Рисуют ломаные по координатам точек, Polygon замыкаетломаную и закрашивает полученную фигуру, Polyline - нет

TextOut,TextRect

Выводят текст. TextOut- в указанную точку холста,TextRect- в рамках заданного прямоугольника

TextHeight,TextWidth,TextExtent

Позволяют определить какой размер (высоту, ширину ипрямоугольную область соответственно) займет текстоваястрока при выводе для текущего шрифта

FloodFill Закрашивает некоторую область канвы текущей кистью.Область либо ограничена определенным цветом, либо самаимеет заданный цвет

Page 71: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

70

Продолжение таблицы 7.2

CopyRect Копирует прямоугольный фрагмент с одной канвы надругую

Draw, StrethDraw Рисует графический ресурс (битовый образ, пиктограмму,метафайл) на канве. Draw – в реальных размерах,StretchDraw – с масштабированием

После обзора методов и свойств можно переписать листинг 7.1 средствами

C++Builder. Это возможно благодаря тому, что компонент TForm имеет свойство

Canvas, представляющее собой объект класса TCanvas. Получившийся код

представлен в листинге 7.2.

Листинг 7.2. Пример работы с методами и свойствами канвыCanvas->Pen->Color=RGB(255,0,0);

Canvas->Pen->Width=4;

Canvas->Ellipse(100,100,200,200);

Canvas->Font->Height=20;

Canvas->Font->Name="Courier";

Canvas->Font->Style=Canvas->Font->Style<<fsItalic;

Canvas->TextOut(150,150,"Hello");

Отличия вывода с использованием канвы очевидны – в листинге не создаются

объекты GDI, такие как перо, шрифт, не надо получать контекст отображения, все

команды направлены только на вывод информации в том виде, как это требуется

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

использовать и функции GDI в тех случаях, когда нужный метод в компоненте

отсутствует. Так, например, вызов метода канвы TextOut можно заменить вызовом

GDI-функции TextOut:TextOut(Canvas->Handle,150,150,"Hello",5);

При формировании изображения на канве формы необходимо учитывать

особенности работы Windows. В связи с тем, что операционная система работает в

многооконном режиме, на экране происходят перекрытия окон, разворачивание,

сворачивание окон, что, очевидно, влияет на изображение в окне. Поэтому,

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

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

Page 72: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

71

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

таких операциях, как разворачивание окна, изменение его размеров, перекрытие

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

перерисовки часть окна по умолчанию закрашивается текущей кистью фона.

Проблему иллюстрирует рис. 7.3. Если сформировать на форме некоторое

изображение (рис.7.3а), а потом перекрыть часть окна формы другим окном

(рис.7.3б), то при закрытии второго окна Windows определит, что нашей форме

нужно восстановить испорченную часть, но по умолчанию эта часть просто

закрашивается фоновой кистью, в результате изображение теряет целостность

(рис.7.3в). Исправить ситуацию возможно, создав обработчик события OnPaint для

формы. Событие OnPaint возникает всякий раз, когда операционная система решает,

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

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

OnPaint формировать полное изображение на форме в том виде, как он хотел бы его

видеть в данный момент. К обработчику события OnPaint можно обратиться и

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

события OnPaint и перерисовке изображения на форме. Частый вызов метода Repaint

может существенно замедлить работу приложения. Метод Invalidate объявляет всю

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

операционную систему сгенерировать сообщение WM_PAINT в тот момент, когда

нет других событий для обработки. Сообщение WM_PAINT приведет к появлению

события OnPaint.

Канвой обладают не только формы. Свойство Canvas присутствует у таких

компонентов, как TPrinter, TBitmap, TImage, TToolbar. Это означает, что

а) б) в)

Рис. 7.3. Потери изображения на форме при перерисовке

Page 73: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

72

графическое изображение, хранящееся в этих компонентах или составляющее их

внешний вид, можно изменять, используя описанные в таблицах 7.1 и 7.2 свойства и

методы.

7.4. Компоненты для работы с изображениями

Операционная система Windows содержит встроенные средства для

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

(JPEG, GIF, PNG) требуют предварительного преобразования в обычный растр

перед обработкой или отображением. Это требует детального знания данных

форматов и достаточно больших усилий программиста. Однако используя

специальные компоненты VCL можно значительно упростить процедуры обработки

изображений в различных форматах. Для работы с DDB и DIB-растрами можно

использовать компонент TBitmap, с JPEG-форматом – TJPEGImage, с

изображениями в формате метафайла – TMetaFile, с GIF-форматом – TGIFImage (не

входит в стандартную поставку C++Builder 6.0).

Компонент TBitmap инкапсулирует растровое изображение Windows [4] как в

формате DDB (аппаратно-зависимый растр), так и в формате DIB (аппаратно-

независимый растр). Благодаря наличию свойства Canvas программист имеет

полный доступ к любой точке растра (массив Pixels или свойство ScanLine), а также

возможность отображать растр или его фрагмент на другой канве (методы Draw,

StretchDraw, CopyRect). Для управления палитрой растра используется свойство

Palette. Компонент TBitmap поддерживает также методы загрузки/сохранения растра

в стандартном буфере обмена, файле, внешнем потоке, ресурсах приложения.

Компонент TBitmap используется в визуальных компонентах С++Builder как

свойство Bitmap компонента TPicture. TPicture выступает в этом случае как

контейнер, хранящий графику одного из поддерживаемых форматов (bitmap, icon,

metafile). Свойство Picture имеют такие компоненты, как TImage, TDBImage,

TControlBar. Листинг 7.3 представляет пример работы со свойствами и методами

компонента TBitmap.

Листинг 7.3. Работа с изображением с помощью TBitmap

Page 74: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

73

Graphics::TBitmap *bm=new Graphics::TBitmap;//Создаем объект TBitmap

if(OpenDialog1->Execute())//Открываем файл в стандартном диалоге

{bm->LoadFromFile(OpenDialog1->FileName); //загружаем картинку из

//файла в Bitmap

bm->Canvas->TextOutA(0,bm->Height-20,"Copy");//Изменяем растр в

//памяти (выводим текст в левом нижнем углу)

Canvas->Draw(20,20,bm); //копируем битовый образ на форму

}

delete bm;

Метод Draw позволяет отобразить некоторую графику (объект класса-потомка

TGraphic) на канве. В данном примере содержание растра bm отображается на канве

формы в позиции (20,20). Если вызов метода Draw заменить наCanvas->StretchDraw(ClientRect,bm);

то содержимое растра будет премасштабировано до размеров указанного в первом

параметре прямоугольника (в данном случае – до размеров клиентской области

окна).

Используя массив Pixels, можно получить цвет любой точки растра, а также

изменить его. Например, первую строку растра можно закрасить белым цветом

следующим образом: for(int i=0;i<bm->Width;i++)

bm->Canvas->Pixels[i][0]=clWhite;

Для работы с изображениями в формате JPEG предназначен компонент

TJPEGImage. Его свойства и методы позволяют загружать и сохранять jpeg-

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

Методы Assign и DIBNeeded позволяют преобразовать изображение из JPEG в BMP

формат. Для работы с файлами, потоками, буфером обмена используются методы

LoadFromFile, LoadFromStream, LoadFromClipboardFormat, SaveToFile,

SaveToStream, SaveToClipboardFormat. На качество и производительность данных

JPEG влияют свойства: CompresionQuality (степень потери качества при сжатии),

Performance (скорость распаковки), Scale (относительный размер изображения при

распаковке). В листинге 7.4 приведен пример работы с JPEG-изображениями в

С++Builder.

Листинг 7.4. Пример работы с изображением в формате JPEG

Page 75: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

74

#include <jpeg.hpp>

if (OpenDialog1->Execute())

{TJPEGImage *ji=new TJPEGImage();

ji->LoadFromFile(OpenDialog1->FileName);

ji->DIBNeeded();

Image1->Height=ji->Height;Image1->Width=ji->Width;

Image1->Picture->Bitmap->Assign(ji);

delete ji;}

Вывод

Графический интерфейс в ОС Windows реализуется подсистемой GDI, работа

с функциями которой требует высокой квалификации программиста. C++Builder

предлагает программисту набор графических компонент, которые существенно

упрощают графический вывод информации, предоставляя свойства и методы для

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

различных форматов. При этом графические компоненты C++Builder оставляют

возможность работы c API-функциями GDI. Все это обеспечивает эффективность и

гибкость работы с устройствами графического вывода информации.

8. Разработка компонент в C++Builder

Как уже было отмечено, среда С++Builder содержит большое количество

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

Программисты могут расширять функциональность системы благодаря

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

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

созданы редактор компонента, редакторы свойств, а также файл помощи. Таким

образом, дальнейшая работа с созданным компонентом ничем не отличается от

работы со стандартными компонентами. Созданные компоненты могут быть

объединены в пакеты для упрощения их установки. Существует большое количество

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

Кроме того, программисты могут сами создавать компоненты для упрощения

Page 76: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

75

дальнейшей разработки приложений. Рассмотрим процесс создания компонент

более подробно.

8.1. Процедура разработки компонента C++Builder

При разработке нового компонента необходимо наследовать его от какого-

либо стандартного класса в соответствии с принципами наследования ООП. Как уже

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

TComponent. Процедура создания и установки компонентов в среде С++Builder

автоматизирована. Для автоматической генерации заготовки нового компонента

можно выбрать пункт главного меню Component | New Component. Далее в

появившемся окне список выбора “Ancestor Type” позволяет выбрать имя класса, от

которого будет наследован компонент. В поле “Class Name” указывается имя

будущего класса. В соответствии с нотацией, принятой в среде С++Builder, имена

классов должны начинаться с заглавной буквы “T”. В поле “Palette Page”

указывается закладка, на которой будет располагаться компонент. В поле “Unit file

name” указывается полный путь и имя файла, который будет содержать новый

класс. После нажатия на кнопку “ОК” по указанному пути будет сгенерировано два

файла c расширениями *.cpp и *.h и именами, совпадающими с именем класса без

начальной буквы “T”. Кроме того, будет отображено окно редактирования этих

файлов. В самих файлах уже будет содержаться код для определения класса и

инсталляции компонента. Программист должен добавить в этот код все

необходимые функциональные возможности нового компонента. Допустим, мы

выбрали в поле “Ancestor Type” класс TComponent, в поле “Class Name” –

TOurComponent, в поле “Palette Page” – OurSample, тогда будет сгенерирован файл

OurComponent.h#ifndef OurComponentH

#define OurComponentH

#include <SysUtils.hpp>

#include <Classes.hpp>

class PACKAGE TOurComponent : public TComponent

{private:

Page 77: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

76

protected:

public:

__fastcall TOurComponent(TComponent* Owner);

__published:};

#endif

Вместе с заголовочным файлом будет создан файл OurComponent.cpp#include <basepch.h>

#pragma hdrstop

#include "OurComponent.h"

#pragma package(smart_init)

static inline void ValidCtrCheck(TOurComponent *)

{ new TOurComponent(NULL); }

__fastcall TOurComponent::TOurComponent(TComponent* Owner)

: TComponent(Owner){ }

namespace Ourcomponent

{ void __fastcall PACKAGE Register()

{TComponentClass classes[1] = {__classid(TOurComponent)};

RegisterComponents("OurSamples", classes, 0);}}

Как видно из приведенного примера создается заготовка для конструктора, а

также определяются две функции ValidCtrCheck и Register. Функция ValidCtrCheck

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

функций. Данная функция будет вызвана при установке компонента. В ней просто

производится попытка создания экземпляра компонента, что в случае наличия

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

Функция Register регистрирует компонент в палитре компонентов. В первом

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

массив указателей на метаклассы регистрируемых компонент, третий содержит

количество регистрируемых компонентов минус 1.

Для компонента может быть создана пиктограмма, которая будет

отображаться в палитре компонентов. Для этого необходимо использовать Image

Editor из пункта главного меню Tools. В этом редакторе необходимо выбрать пункт

File | New | Component Resource File (.dcr), а затем пункт Resource | New | Bitmap и

задать размер 24х24 пиксела. Необходимо переименовать созданный Bitmap, назвав

его так же, как и будущий класс компонента, но заглавными буквами. Для нашего

Page 78: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

77

случая это будет имя TOURCOMPONENT. Далее можно нарисовать необходимый

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

Сам файл ресурса необходимо сохранить в том же каталоге, что и файлы .cpp и .h, с

тем же именем, но с расширением .dcr. Для нашего случая это будет имя

ourcomponent.dcr. После внесения изменений в файлы .cpp и .h можно приступать к

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

Component | Install Component и в появившемся окне в поле “Unit file name” указать

имя .cpp файла, содержащего исходный код компонента. В поле “Packege File Name”

выбрать пакет, в который будет помещен компонент. По умолчанию

пользовательские компоненты помещаются в пакет “Borland User Components”.

После нажатия кнопки “Ok” необходимо согласиться с перекомпиляцией пакета и

сохранить изменения в пакете. После этого новый компонент появится в палитре

компонентов той закладки, которая была указана при регистрации компонента. Для

удаления/добавления или перекомпиляции модулей в пакетах можно также

использовать пункт Component | Install Package. В появившемся окне необходимо

выбрать нужный пакет и нажать кнопку «Edit».

8.2. Определение свойств и событий компонента

В рассмотренном выше примере была создана всего лишь заготовка

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

обеспечивающий функциональность нового компонента. Принцип работы с новым

компонентом ничем не отличается от обычной процедуры наследования ООП.

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

функции, а также использовать наследуемые. Новым в среде С++Builder является

возможность использования свойств и событий. Как уже отмечалось, свойства

предоставляют дополнительный интерфейс для доступа к защищенным данным

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

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

областей видимости класса (private, protected, public), в этом случае их доступность

определяется также как и для данных класса. Однако в среде С++Builder введена

Page 79: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

78

еще одна директива для области видимости __published. Если свойство или событие

будет размещено в этой секции, то оно будет доступно в инспекторе объектов на

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

слово __property. Описание свойств и событий в общем случае выглядит

следующим образом__property <type> <id> { read = <data/function id>, write =

<data/function id>}

Кроме атрибутов read и write для свойств можно устанавливать

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

однако их рассмотрение выходит за рамки данного учебного пособия. <id>

определяет имя свойства и задается по стандартным правилам для идентификаторов

С++. Согласно нотации среды С++Builder имена событий начинаются с букв “On”.

Описание свойств и событий отличаются только типом <type>. События должны

иметь специальный тип «событие», указатель на функцию, описанный с ключевым

словом __closure. Видя такой тип, инспектор объектов размещает события на

закладке Events. Свойства могут иметь любой стандартный или производный тип,

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

использовать тип указатель на класс, поскольку статические экземпляры классов

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

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

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

Assign. Свойства на самом деле не хранят никаких данных и являются как бы

интерфейсом для доступа к внутренним данным компонента. Где на самом деле

будут храниться данные, и как будет происходить доступ к ним, определяется с

помощью спецификаторов read и write. И read, и write могут указывать и на метод, и

на переменную (обычно объявленную в private секции класса). Чаще всего write

указывает на функцию, а read просто на переменную. В самой функции также

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

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

допустимых значений при записи в свойство или изменение значения других

свойств и переменных в зависимости от данного. Имя свойства может не иметь

Page 80: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

79

ничего общего с именем переменной, которую оно модифицирует. Однако согласно

нотации среды С++Builder имя связанной со свойством должно быть таким же, как и

имя свойства, но с префиксом F. Если write отсутствует, то свойство будет только

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

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

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

собственный обработчик событий. Обработчик события представляет собой

обычную функцию класса (обычно принадлежащую классу формы), в которую

передается указатель на объект, который сгенерировал события и некоторые

дополнительные данные, специфичные для каждого типа события. Если произошло

какое-либо событие, то компонент просто вызывает назначенный этому событию

обработчик, таким образом позволяя пользователю компонента выполнить

необходимые действия при возникновении этого события. Рассмотрим пример

определения свойств и событий.

Заголовочный .h файлclass PACKAGE TOurComponent : public TComponent

{private:

int FMyInteger; char FMyChar;

Graphics::TFont *FMyFont;

TNotifyEvent FOnMyError;

void __fastcall SetMyInteger(const int Value);

__published:

__property int MyInteger = {read=FMyInteger,

write=SetMyInteger};

__property char MyChar = {read=FMyChar, write=FMyChar};

__property Graphics::TFont* MyFont = {read=FMyFont,

write=SetMyFont};

__property TNotifyEvent OnMyError = {read=FOnMyError,

write=FOnMyError};}

Исходный .cpp файл__fastcall TOurComponent::TOurComponent(TComponent* Owner)

: TComponent(Owner)

{FMyInteger=10;FMyChar='s';

FMyFont= new Graphics::TFont();}

Page 81: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

80

__fastcall TOurComponent::~TOurComponent()

{delete FMyFont;}

void __fastcall TOurComponent::SetMyFont(const Graphics::TFont *Value)

{ FMyFont->Assign((TPersistent*)Value); }

void __fastcall TOurComponent::SetMyInteger(const int Value)

{if (Value%2) FMyInteger = Value;

else if (!ComponentState.Contains(csDesigning))

if (FOnMyError) FOnMyError (this);}

В данном примере определяется три свойства: MyChar, MyFont и MyInteger.

Свойство MyChar обеспечивает доступ к защищенной переменной FMyChar без

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

защищенной переменной FMyFont, являющейся указателем на класс типа TFont.

Еще раз отметим, что в этом случае объект должен быть создан в конструкторе и

уничтожен в деструкторе. Кроме того, как видно из функции SetMyFont, значение

переменной FMyFont присваивается с помощью метода Assign. Данный метод

обеспечит корректное копирование всех внутренних данных и свойств класса TFont.

При выполнении же присваивания вида FMyFont=Value произойдет присваивание

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

под FMyFont, и при удалении объекта Value, указатель FMyFont станет

некорректным. Свойство MyInteger обеспечивает доступ к защищенной переменной

FMyInteger. При чтении значения свойства происходит просто чтение этой

переменной, при записи же происходит проверка: для записи в переменную

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

сгенерировано событие FOnMyError, причем генерация события происходит, только

если компонент находится на этапе выполнения, а не на этапе проектирования. Для

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

ComponentState: если это свойство содержит флаг csDesigning, то компонент

находится на этапе проектирования. Далее происходит проверка, назначил ли

программист, использующий наш компонент, обработчик события OnMyError.

Поскольку переменная FOnMyError содержит адрес функции обработчика, то, если

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

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

Page 82: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

81

качестве параметра передается указатель this, т.е. указатель на текущий экземпляр

класса, для которого была вызвана функция SetMyInteger. В обработчике этот

параметр будет доступен как указатель Sender, что позволит программисту

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

Вывод

Среда С++Builder предоставляет удобные средства для создания

пользовательских компонент. Работа с созданными компонентами ничем не

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

функциональность среды С++Builder.

Page 83: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

82

Список литературы

1. Архангельский А. Я. Разработка прикладных программ для Windows в С++

Builder 5- М.: ЗАО «Издательство БИНОМ», 2000. – 256 с.:ил.

2. Елманова Н. З., Кошель С. П. Введение в BorlandC++Builder – М.:Диалог-

МИФИ, 1998. – 272 с.

3. Рихтер Дж. Windows для профессионалов (программирование в Win32 API для

Windows NT 4.0 и Windows 95) / Пер. с англ. – М.: Издательский отдел

“Русская редакция” ТОО “Chanel Trading Ltd.”, 1997. – 720 c.:ил.

4. Теллес М. Borland C++Builder: библиотека программиста – СПб: Питер Ком,

1998. – 512с.: ил.

5. Холингворт Дж., Сворт Б., Кэшмэн М., Густавсон П. Borland C++Builder 6.

Руководство разработчика.: Пер. с англ. – М.: Издательский дом «Вильямс»,

2004. – 976 с.:ил.

6. Шамис В. А. Borland C++ Builder. Программирование на С++ без проблем. М.:

«Нолидж», 1997. – 266 с., ил.

Page 84: 0480196 746 b8_lyasin_d_n_sankov_s_g_osnovy_programmirovaniya_v_srede_c_bui

83

Дмитрий Николаевич Лясин

Сергей Геннадьевич Саньков

Основы программирования в среде C++Builder

Учебное пособие

Редактор О.П. Чеботарева

План заказных изданий 2007г. поз. N 1

Лицензия ИД N04790 от 18.05.2001

Подписано в печать _________ . Формат 60 х 84

Бумага газетная. Печать офсетная. Усл. печ. л. ____ .

Уч. -изд.л. ___ . Тираж _____ . Заказ _____ .

Волгоградский государственный технический университет.

400131 Волгоград , пр. Ленина , 28.

РПК "Политехник" Волгоградского государственного технического

университета.

400131 Волгоград , ул. Советская , 35.