Лабораторная работа 1 - Кузнецкий институт информационных

advertisement
Министерство образования и науки РФ
Кузнецкий институт информационных и управленческих технологий
Объектно-ориентированное
программирование
Методические указания
к лабораторным работам
Кузнецк 2011
Лабораторная работа 1
Тема: Знакомство с интегрированной средой разработки IDE Visual
Studio (C++). Классы.
Цель работы: изучение особенностей практической реализации аспектов концепции
объектно −ориентированного программирования
Знакомство с интегрированной средой разработки IDE Visual Studio (C++)
Интегрированная среда разработки (IDE) Visual Studio предоставляет набор инструментов,
которые помогают в создании и изменении кода, а также в обнаружении и исправлении
ошибок.
При написании программы на Visual C++ с помощью Visual Studio первым этапом является
выбор типа проекта. Для каждого типа проекта Visual Studio устанавливает параметры
компилятора и генерирует стартовый код. Создание нового проектаВ меню Файл выберите
команду Создать и затем пункт
Проект....
1.
Рис.1 Диалоговое окно Создать проект.
В области Типы проектов выберите пункт CLR Console Application, зададим в его
нижней части имя будущего проекта в поле Имя, которое перекочует в поле Имя решения,
затем с помощью кнопки Обзор установим папку, в которую будет помещен наш проект.
Нижняя часть окна рис.1 станет выглядеть так, как показано на рис.2.
Рис.2 Формирование консольного приложения.
2. Затем нажмем кнопку ОК. В результате получится то, что показано на рис.3.
Заготовка состоит из заголовка главной функции:
int main(array<System::String ^> ^args)
и тела, ограниченного фигурного скобками.
Рис.3. Вид заготовки консольного приложения.
3. Преобразуем заголовок функции main(множество аргументов функции)к
виду main(),т.е. к виду без аргументов, а из тела удалим оператор return 0.
Когда мы формировали заготовку консольного приложения, то видели, что при задании
имени приложения формировалось и некое поле Имя решения. Дело в том, что среда
VC++ оформляет создаваемое приложение в виде двух контейнеров, вложенных один в
другой. Один (главный контейнер) называется Имя решения, а другой – Проект. Проект
определен как конфигурация (каркас, контейнер), объединяющая группу файлов.
В рамках проекта создается программа, в т.ч. и подлежащая исполнению, т.е.
откомпилированная и построенная. Каждый проект содержит по крайней мере две
подконфигурации: отладочную и обычную (исполнительскую). Это задается в
выпадающем меню, которое по умолчанию установлено на опцию Отладка. Выпадающее
меню находится в строке окна среды, расположенной ниже строки главного меню.
Проекты являются частью другого каркаса, другого контейнера, который называется
Решение и который отражает взаимосвязь между проектами: одно Решение может
содержать множество проектов, а проект содержит множество элементов,
обеспечивающих существование приложения как такого. Можно сказать, что Решение –
это не что иное, как группа объединенных проектов. Назовем его просто: «Группа
проектов», чтобы термин «Решение» не вводил нас в заблуждение.
Существует специальный инструмент работы с группой проектов, называемый
Обозреватель решений. К нему можно добраться через опцию Вид меню среды
разработки. Сама среда автоматически формирует создаваемое приложение как группу
проектов, содержащую собственно проект (рис.4).
Рис. 4. Формирование проекта приложения.
Такой подход к оформлению приложения позволяет работать с группой проектов как с
одним целым, что ускоряет процесс разработки приложений.
В качестве примера создадим проект с именем 2_2008 таким же способом, как мы
создавали проект 1_2008, и добавим его к имеющейся группе 1_2008. При создании
нового проекта в нижней части окна Создать проект наряду с полем Имя решения ниже
кнопки Обзор (рис. 1) имеется переключатель Создать каталог для решения. Если
включить этот переключатель. То будет создана новая группа проектов с именем, по
умолчанию совпадающем с именем создаваемого проекта. Мы включим этот
переключатель.
Теперь попробуем объединить два проекта в одно Решение (в одну группу проектов). Для
этого, во-первых, закроем Решение 2_2008 и откроем Решение 1_2008, а затем щелкнем
правой кнопкой мыши на строке Решение “1_2008” и в появившемся контекстном меню
выберем команду Добавить | Существующий проект … (рис. 5)
Рис.5 Процесс добавления созданного ранее проекта к группе проектов.
При этом откроется диалоговое окно для поиска проекта, затем обычным способом
откроем проект 2_2008, в результате чего он добавится к Решение “1_2008” (рис.6)
Рис.6 Решение “1_2008” с добавленным к нему проектом 2_2008.
Рассмотрим некоторые файлы, попавшие в проект, показанные на рис.3:
 1_2008.cpp – это главный исходный файл и точка входа в создаваемое
приложение (1_2008 – это в данном случае имя проекта);
 stdafx.cpp – подключает для компиляции файл stdafx.h;
 stdafx.h – если для проекта требуются какие-то дополнительные заголовочные
файлы, то они задаются пользователем в этом файле;
 ReadMe.txt – файл, описывающий некоторые из созданных шаблоном
консольного приложения файлы проекта. Посмотреть содержимое указанных
файлов можно через их контекстные меню, если выполнить в них команду
Открыть.
Запуск программы в режиме отладки
1.Щелкните вкладку 1_2008.cpp в области редактирования, если этот файл не
отображается.
2.Щелкните следующую строку в редакторе, чтобы установить ее в качестве текущей:
while (f<=u)
3.Чтобы установить в этой строке точку останова, в меню Отладка выберите команду
Точка останова или нажмите клавишу F9. Кроме того, для установки или удаления точки
останова можно щелкнуть в области слева от строки кода.
Слева от строки с установленной точкой останова появляется красный кружок.
4.В меню Отладка выберите команду Начать отладку или нажмите клавишу F5.
При достижении программой строки с установленной точкой останова выполнение
временно приостанавливается (так как программа находится в режиме приостановки
выполнения). Строка, которая должна выполняться следующей, отмечается желтой
стрелкой слева от строки.
5.Чтобы узнать текущее значение переменной f, наведите на нее курсор. Имя переменной и
ее значение, равное 0.00000000, отобразится в окне всплывающей подсказки (рис.7).
Чтобы наблюдать за переменной f в окне Контрольные значения, щелкните ее правой
кнопкой мыши и выберите команду Добавить контрольное значение. Кроме того, можно
выделить переменную и перетащить ее в окно Контрольные значения.
Рис.7
6.В меню Отладка нажмите кнопку Шаг с обходом или нажмите клавишу F10, чтобы
перейти к следующей строке кода.
Значение переменной f изменится на 20.000000.
Рис.8
7.Щелкните правой кнопкой мыши последнюю строку в методе main (getch();) и
выберите команду Выполнить до текущей позиции. Желтая стрелка слева от строки кода
указывает на следующий оператор, который должен выполняться.
8.Чтобы остановить программу, в меню Отладка выберите команду Остановить отладку
или нажмите сочетание клавиш SHIFT+F5.
Отладка проекта (C++)
В этом разделе рассматривается изменение программы для устранения проблемы,
выявленной при тестировании проекта.
Развертывание программы (C++)
Заключительным этапом создания приложения является создание установщика, с помощью
которого другие пользователи смогут устанавливать программу на своих компьютерах. Для
этого мы добавим новый проект в имеющееся решение. Выходным файлом проекта будет
являться файл setup.exe, служащий для установки ранее созданного приложения на других
компьютерах.
В этом руководстве для развертывания приложений используется установщик Windows.
Кроме того, для развертывания приложения может использоваться ClickOnce.
Создание проекта установки и установка программы
1.Правой кнопкой мыши щелкните на 1_2008 выбрать пункт Добавить и выберите команду
Создать проект. Откроется диалоговое окно Добавление нового проекта.
2.В области Типы проектов разверните узел Другие типы проектов и выберите пункт
Установка и развертывание.
3.В области Шаблоны выберите Мастер установки. Введите имя проекта установки,
например faleInstaller, и нажмите кнопку ОК.
4.Откроется
диалоговое
окно
Мастер
установки.
Нажмите
кнопку Далее
для
продолжения.
5.В области Выбор типа проекта мастера выберите пункт Создать программу установки
для приложения Windows и нажмите кнопку Далее для продолжения.
6.В области Выбор включаемых выходных данных проекта мастера выберите пункт
Основные выходные файлы из game и нажмите кнопку Далее для продолжения.
7.В установщик не должны включаться дополнительные файлы, поэтому в области Выбор
файлов для включения установщика нажмите кнопку Далее.
8.Просмотрите изменения с помощью мастера и убедитесь, что все правильно. Чтобы
создать проект, нажмите кнопку Готово (рис.).
В Обозревателе решений отобразится новый проект faleInstaller. Этот проект будет
содержать список зависимостей приложения, таких как библиотека времени выполнения C
или .NET Framework, а также файлов проекта, которые должны быть включены в
установщик.
После создания проекта установки могут быть изменены различные параметры.
Произведите построение установщика, выбрав его в Обозревателе решений и щелкнув
команду Построить faleInstaller в меню Построение.
9.Перейдите к месту размещения файлов setup.exe и faleInstaller.msi, созданных на
предыдущем этапе. Чтобы установить приложение на компьютере, дважды щелкните
любой из этих файлов.
Рис.9
Теоретические основы:
Концепция объектно-ориентированного программирования (ООП) включает в себя понятия
объектов, классов, инкапсуляции и наследования.
Объект – это некая математически - программно описанная сущность, элемент
окружающего нас мира, с которым мы встречаемся в повседневной жизни. Например, ваша
собака, ваш автомобиль, ваш телевизор – это все объекты. Реальные объекты имеют две
характеристики: состояние, которое определяется набором свойств объекта и поведение.
Например, собака имеет состояние, определяемое следующим набором ее свойств: имя,
цвет шерсти, порода, характер и т.д. А ее поведение определяется тем, что она в данный
момент может лаять, вилять хвостом и т.д. поведение объекта определяется набором
функций, заданных в объекте, которые здесь называются методами.
Класс – это некий чертеж, некий проект, из которого создается объект. В классе заложены
свойства и поведение будущего объекта, который получается из класса как из проекта.
Например, «Автомобили» - это класс. «Тойота» - это объект класса «Автомобили»,
конкретное воплощение класса в конкретную модель. Или, например, проект дома серии
135 – это класс, а сам конкретный дом, построенный по конкретному адресу – это объект
класса домов серии 135. таким образом, когда мы смотрим на окружающие нас объекты
реального мира в плане их состояния и поведения, то готовы к пониманию объектноориентированного программирования.
Объектно-ориентированное программирование – это способ программирования с
ориентацией на объекты. При таком способе создаются крупные программные образования
– классы., куда закладываются общие свойства будущих объектов, которые станут
получаться по определенным правилам из этих классов, куда закладываются варианты
поведения будущих объектов через создаваемые в классах параметрические программы
(методы классов). Такой способ значительно ускоряет разработку программного
обеспечения и облегчает труд программистов. Вспомним, что одним из первых средств
автоматизации труда программиста были так называемые стандартные программы, которые
выполняли часто встречающиеся действия (например, перевод десятичных чисел в
двоичные, вычисление тригонометрических функций и т.п. ). Такие программы
объединялись в библиотеки стандартных программ. Сегодня на более высоком уровне мы
имеем библиотеки классов, которые поставляют нашим программам необходимые им
объекты (рисунки, фотографии, средства мультимедиа и т.п.), тем самым повышая качество
и эффективность современного программирования.
Программно в классах задаются элементы, называемые свойствами. Они описывают
состояние объекта и хранятся в специальных элементах, называемых полями. Поведение
же объекта описывается специальными функциями, которые в классах носят название
методов. Когда свойствам класса присваиваются какие-то конкретные значения, то тем
самым из класса создается конкретный объект. Объекты создаются специальным методом
класса, называемым конструктором.
Методы обрабатывают внутренние состояния объекта и обеспечивают механизм
взаимодействия между объектами. Например, возьмем класс велосипедов. Свойствами,
характеризующими состояния объектов этого класса, будут: текущая скорость, текущее
состояние переключателя педали (изменение скорости), количество шестеренок и текущая
шестеренка, за счет которой скорость изменяется. Методами, которые изменяют состояние
велосипеда будут: смена шестеренки, переключение педали и изменение скорости. Весь
этот механизм изменения свойств методами класса спрятан внутри самого класса. Такой
принцип взаимодействия элементов класса носит название инкапсуляции данных. Это
фундаментальный принцип объектно-ориентированного программирования.
В чем же фактическая польза от механизма классов-объектов?
Во-первых, обеспечивается модульность программирования: исходный код объекта
написан и поддерживается независимо от исходных кодов других объектов (т.е.
повышается надежность всей задачи, программа которой состоит из цепочки таких
независимых модулей).
Во-вторых, механизм работы такого модуля скрыт внутри самого модуля и не отвлекает
программиста на выяснение различных мелких деталей алгоритма.
В-третьих, имеется возможность многократного использования элемента (как и когда-то
многократное использование библиотеки стандартных программ).
В-четвертых, обеспечивается легкая сменяемость элементов в общей программе (в
приложении): если такой элемент выходит из строя, его можно легко заменить
аналогичным элементом, не разрушая всю задачу.
Существуют разработчики классов и пользователи классов (разработчики приложений):
если разработчик создает классы, то пользователь манипулирует классами и экземплярами
классов.
Класс – это обыкновенный тип. Если вы программист, то всегда имеете дело с типами и
экземплярами, даже если и не используете эту терминологию. Например, вы создаете
различные переменные типа int. Можно сказать, что вы фактически создаете различные
экземпляры переменных этого типа. Классы обычно более сложны, чем простые типы
данных, но они работают тем же способом. Создавая переменные типа заданного класса, вы
создаете экземпляры этого класса., а назначая различные значения экземплярам того же
типа (как и переменные типа int), вы можете выполнять разные задачи.
Класс – это собрание связанной информации, которая включает в себя и данные, и функции
(программы для работы с данными). Эти функции в классах называются методами.
Класс – это дальнейшее развитие структур: в них тоже объединяются данные разных типов.
Это такой шаблон, под который (как и под структуру) память выделяется только тогда,
когда мы создаем «переменную типа этого шаблона». Вспомним, что если у нас была некая
структура А, то чтобы работать с ней, мы создавали экземпляр этой структуры а путем
объявления А а; а затем уже работали с экземпляром а. Можно сказать, что мы объявляли
переменную а типа А.
Точно так же поступают и для класса: если есть класс А (шаблон, под него память не
выделяется), то объявляют переменную типа А путем объявления А а;, после чего можно
работать уже как бы с самим классом, а на самом деле – с его экземпляром а. Как и при
использовании структур, к членам класса (данным и методам) можно обращаться по тем же
правилам: если объявлено А а;, то обращение к члену класса с именем аа будет
записываться как а.аа, а если был объявлен указатель на класс (например, как А *а;), то
обращение к члену класса с именем аа будет записываться как а->аа.
Класс – это конструкция, параметрически определяющая некоторую категорию объектов.
Например, может быть класс компьютеров, который объединяет в себе компьютеры разных
марок, разных возможностей. Может быть класс столов: столы письменные, обеденные и
т.п. Класс столов может делиться на подклассы: столы письменные, которые, в свою
очередь
могут
делиться
на
столы
письменные
дубовые
и
столы
письменные
древесноволокнистые и т.д. Мы видим, что классы могут принадлежать некой иерархии
классов. В каждом классе определены характеристики тех объектов, которые образуют этот
класс.
В классе также задаются программы, называемые методами, которые обрабатывают
характеристики объектов, принадлежащих данному классу. Поведение объекта в реальном
мире определяется его характеристиками. Изменяя значение характеристик, мы получаем
разное поведение объектов. Когда мы создаем экземпляр класса и определяем значения его
конкретных характеристик, то получаем конкретный объект.
В составе класса существует специальный метод (т.е. программа-функция), который
формирует
экземпляр
противоположность
класса.
Этот
конструктору,
метод
существует
носит
название
программа
–
конструктора.
деструктор,
В
которая
уничтожает экземпляр класса в памяти, освобождает память, которая может использоваться
для других программных целей. А если вспомнить, что память – величина не
беспредельная, то становится понятной и роль деструктора.
Принципы построения классов.
Основные
принципы
построения
классов
это
–
инкапсуляция,
наследование
и
полиморфизм.
Инкапсуляция – это принцип объединения в единой конструкции и данных, и программ,
обрабатывающих эти данные. В терминологии ООП данные называются членами-данными,
а программы, их обрабатывающие (эти программы построены в виде функций), - членамифункциями (или методами).
Такой подход позволяет максимально изолировать объект, получаемый из класса, от
внешнего воздействия, что приводит к высокой надежности программ, использующих
объекты. С другой стороны, классы используются так, как ранее использовались
стандартные программы, только с еще большей эффективностью в самых разных
приложениях, что значительно повышает производительность труда программиста. При
добавлении новых характеристик классам программы, ранее использовавшие объекты,
построенные из них, остаются без изменений.
В Visual C++ введено понятие компонентов – специальных классов, в которых объекты
определяются такими характеристиками, как свойства, события и методы. Причем, в
отличие от работы с обычными классами, при работе в Visual C++ возможно
манипулировать видом и функциональным поведением компонентов и на стадии
проектирования приложения, и в момент его выполнения.
Например, в Visual C++
существует компонент «форма» (класс Form)
и компонент
«кнопка» (класс Button), у которых есть свои свойства, методы и события. Если при
проектировании приложения в форму поместить две кнопки, то с помощью определения
двух разных значений свойствам кнопок Text (название кнопки) и Visible (значения false и
true определяют видимость кнопки при исполнении приложения) вы получаете два
экземпляра, которые ведут себя по-разному: первая кнопка при выполнении программы
будет невидима в форме, а вторая останется видимой. При помощи события компонент
сообщает пользователю, что на него произведено определенное воздействие (например, для
компонента «кнопка» событием может быть нажатие кнопки – щелчок кнопкой мыши), а
методы служат для обработки реакции компонента на события.
Наследование.
Наследование – второй принцип построения классов. Мы видели, что классы в общем
случае могут составлять иерархию: один класс получается из другого, на основании
другого получается третий и т.д. То есть речь идет о том, что и в классах существуют
родители и дети, бабушки с дедушками, их внуки и т.д. наследование предполагает, что все
характеристики класса-родителя присваиваются классу-потомку. После этого потомку при
необходимости добавляют новые характеристики. Иногда некоторые методы в классепотомке, полученном от предков, переопределяются, т.е. наполняются новым содержанием.
Рассмотрим структуру базового класса, из которого могут создаваться классы-потомки.
Объявление класса представлено в листинге 1:
class <имя>
{
private: /* Имя секции. Данные и методы, помещенные в эту секцию будут доступны
только методам этого класса. Доступ к ним методом производных классов запрещен*/
<Приватные данные>
<Приватные конструкторы>
<Приватные методы>
protected: /* Имя секции. Данные и методы, помещенные в эту секцию будут доступны
только методам этого класса и производным от него, т.е. его потомкам */
<Защищенные данные >
< Защищенные конструкторы >
< Защищенные методы >
public: /* Имя секции. Данные и методы, помещенные в эту секцию будут доступны
методам всех классов */
<Общедоступные данные >
< Общедоступные конструкторы >
< Общедоступные деструкторы >
< Общедоступные методы >
}; /*обратите внимание, что так же заканчивается и объявление структуры */
В секциях private, protected, public можно определять функции (в классах – это методы), а
вызывать методы на выполнение можно только в соответствии с тем, в какой секции
находится функция. Атрибуты private, protected, public называются атрибутами доступа к
членам класса. В классах методы вызываются так же, как если бы они находились в
структуре:
имя (экземпляра).f (фактические параметры функции);
Полиморфизм
Полиморфизм – это третий принцип, лежащий в основе создания класса. При
полиморфизме (дословно: многоформие) родственные объекты (т.е. происходящие от
общего родителя) могут вести себя по-разному в зависимости от ситуации, возникающей в
момент выполнения программы. Чтобы добиться полиморфизма, надо иметь возможность
один и тот же метод в классе-родителе переопределить в классе-потомке.
Например, все классы имеют общего прародителя – класс Object. В этом классе определен
метод draw (рисовать фигуру). Классы, рисующие различные фигуры и произошедшие от
Object, - родственные классы.
Каждый из них определяет рисование своей фигуры методом draw, унаследованным от
Object: точку, линию, прямоугольник, окружность и т.д. Но все фигуры разные, хотя метод
общий. Но этот метод draw в каждом из классов-потомков переопределен, т.е. в каждом
классе-потомке ему назначена другая функциональность.
Полиморфизм достигается за счет того, что методам из класса-родителя позволено
выполняться в классе-потомке, а там оставляют только имя, но при этом дают ему
необходимую для данного класса функциональность. Такие методы должны объявляться в
обоих классах с атрибутом virtual, записываемым перед атрибутом «возвращаемый тип
данных». Если функция имеет атрибут virtual, то она может быть переопределена в классепотомке, даже если количество и тип ее аргументов такие, что и функции базового класса.
Переопределенная функция отменяет функцию базового класса.
Кроме атрибута virtual, у методов существует атрибут friend. Методы с таким атрибутом,
расположенным (как и атрибут virtual) в объявлении метода перед указанием типа
возвращаемых данных, называются дружественными. Метод, объявленный с атрибутом
friend, имеет полный доступ к членам класса, расположенным в секциях private и
protected, даже если этот метод – не член этого класса. Это справедливо и для классов:
внешний класс (т.е.его методы) имеет полный доступ к классу, который объявляет этот
внешний класс дружественным.
Во всех остальных аспектах дружественный метод – это обычный метод. Подобные методы
из внешних классов, имея доступ к секциям private и protected, могут решать задачи,
реализация которых с помощью методов-членов данного класса затруднительна или даже
невозможна.
Указатель this
Каждый объект содержит свой экземпляр полей класса. Методы класса находятся в памяти
в единственном экземпляре и используются всеми объектами совместно, поэтому
необходимо обеспечить работу методов с полями именно того объекта, для которого они
были вызваны. Это обеспечивается передачей в функцию скрытого параметра this, в
котором хранится константный указатель на вызвавший функцию объект. Указатель this
неявно используется внутри метода для ссылок на элементы объекта. В явном виде этот
указатель применяется в основном для возвращения из метода указателя (return this;) или
ссылки (return *this;) на вызвавший объект.
Указатель this можно также применять для идентификации поля класса в том случае, когда
его имя совпадает с именем формального параметра метода. Другой способ идентификации
поля использует операцию доступа к области видимости.
Примеры создания классов
Приведем примеры трех программ, в которых объявлены и использованы простейшие
классы.
Пример_1:
// 1_2010.cpp: главный файл проекта.
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
using namespace System;
class A
{
protected:
int x;/* к этим данным имеют доступ только методы данного класса и
производных*/
int y;
public:
int a;
int b;
int f1(int x,int y)/* метод класса*/
{
return (x-y);
}
};
int main()
{
Console::WriteLine(L"Здравствуй, мир!");
A min; //создание экземпляров классов А,В
min.a=10; // Работа с элементами класса А из секции public
min.b=20;
int x1=min.f1(min.a,min.b);
printf("x1= %d\n ",x1);
_getch();
//return 0;
}
Рис.10 Результат работы программы Пример_1
Пример_2: Создадим класс, членами которого будут изделия, состоящие из деталей и их
стоимостей,а также методы, первый из которых присваивает значения изделию,детали, а
также их стоимости через свои параметры,а второй выводит на экран значения,
присвоенные первым методом.
#include "stdafx.h"
#include<stdio.h> //for printf()
#include <conio.h> // for _getch()
using namespace System;
class produce //начало определения класса
{
private:
// поля класса
int modelnumber; // номер изделия
int partnumber; // номер детали
float cost;
// стоимость детали
public:
// установка данных с помощью метода
// присваивает данным класса значения своих параметров
void setpart(int mn, int pn, float c)
{
modelnumber=mn;
partnumber=pn;
cost=c;
}
void show() // вывод данных
{
printf("The Number of the Model is %d\n",modelnumber);
printf("The Number of the Part is %d\n ",partnumber);
printf("The Number of the Cost is %.2f\n ",cost);
}
};//конец описания класса
// обработка класса в головной программе
int main()
{
produce izd;// определение объекта мз класса (экземпляр класса)
izd.setpart(100,200,250.5);// вызов метода класса
izd.show();// вывод данных
_getch();
}
Рис.11 Результат работы программы Пример_2
Обратите внимание, что когда вы создаете переменную типа класса, т.е. экземпляр класса
(например, A min;, где min – это экземпляр класса), то для этого экземпляра никакой
памяти не выделяется. А компилятор все-таки размещает этот экземпляр где-то в памяти.
Почему?
Среди исполнения приложений в Си++ выделяют два вида памяти: статическую и
динамическую. Последняя носит название «куча» (heap). Куча может быть управляемой и
неуправляемой. Если компилятор способен определить размер памяти под объявленную
переменную, то он выделяет для нее место в статической памяти (например, под
переменную типа int из 10 элементов он выделит 40 байтов).
Если же компилятор не в состоянии определить размер памяти под объявленную
переменную, то он потребует от программиста поместить такую переменную в куче – в
динамической памяти. Кстати, если программист сам хочет работать с динамической
памятью (даже когда компилятор может поместить переменную в статистической памяти),
то язык это ему не позволяет. Для простых переменных при этом используются:
 Функция malloc(), которая выделяет область памяти в динамической области и
возвращает указатель на эту область.
 Функция free(), которая освобождает занятую переменной область и передает
освобожденную память в общее пользование.
Если же работа происходит с объектами, то здесь используются операторы new – аналог
malloc(), и delete – аналог free().
Указанные функции и аналогичные им операторы работают с неуправляемой кучей. С
управляемой кучей работает утилита gcnew и нет необходимости освобождать самому
память от объекта, поскольку в этом случае работает так называемая автоматическая сборка
мусора: когда объект становится ненужным, память от него освобождается.
Но приведем пример этой же программы (пример_1), в которой используется (по нашему
желанию) динамическая память:
В данном случае оператор new размещает объект в куче, выдает адрес этого объекта, а
конструктор инициализирует объект.
Пример_3: // 1_2010.cpp: главный файл проекта.
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
using namespace System;
class A
{
protected:
int x;
int y;
public:
int a;
int b;
int f1(int x,int y)
{
return (x-y);
}
};
int main()
{
Console::WriteLine(L"Здравствуй, мир!");
A *min=(A *) new A();
min->a=10;
min->b=20;
int x1=min->f1(min->a,min->b);
printf("x1= %d\n x2= %d\n",x1);
_getch();
delete min;
}
Рис.12 Результат работы программы Пример_3
Конструкторы и деструкторы класса.
Конструктор класса.
Конструктор класса тоже член класса, но специфический – это метод с таким же именем,
что и класс. Такие методы не имеют право возвращать какие-либо значения: если вы
написали в конструкторе оператор return, компилятор выдаст ошибку. Конструктор
выполняет различные задачи и не виден вам, как программисту. Даже если вы сами не
писали его текст, конструктор по умолчанию всегда присутствует в классе, ибо основная
его задача – создавать в памяти экземпляр класса (т.е. как бы по проекту (классу) построить
дом (экземпляр класса)). В этом случае конструктор берется из общего прародителя классов
– класса Object, в котором он имеется.
Вторая задача конструктора – придавать всем членам-данным класса начальные значения.
Если вы сами не построили конструктор, который станет инициализировать члены-данные
вашего класса вашими же значениями, то этим данным невидимый для вас конструктор
(конструктор по умолчанию) придаст свои, принятые в системе для данного типа величин
значения(например, данные типа int получат нулевые значения и т.д.). В примере 4
приведен пример класса с конструктором, созданным для инициализации членов-данных
класса теми значениями, которые задаст пользователь класса при работе с ним.
Пример_4:
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
using namespace System;
class Date
{
public:
/*Это члены-данные класса.
С ними будут работать функции-члены класса:get...и set... */
int month;
int day;
int year;
Date (int dy,int mn, int yr) //конструктор класса
{
/*члены-данные month, day, year будут принимать значения, которые поступят
в конструктор как в функцию при его использовании где-нибудь в приложении*/
day=dy;
month=mn;
year=yr;
}
int getMonth() const;
/*Функция getMonth() объявлена с атрибутом const - может данные
только поставлять, не изменяя их (read-only),
а функция SetMonth() не имеет квалификатора const и поэтому данные внутри
себя может изменять: виды функций определены вне класса */
void setMonth(int mn);
int getDay();
void setDay(int dy);
int getYear();
void setYear(int yr);
~Date()//деструктор класса
{ }
}; // конец описания класса
/*создание функций (вне класса, поэтому надо указывать имя класса,
для которого эти функции создаются)*/
int Date::getMonth() const
{
return month;
//Функция ничего не изменяет
}
void Date::setMonth(int mn)
{
month=mn;
}
//Функция изменяет член-данное класса
int Date::getDay()
{
return Date::day;
}
void Date::setDay(int dy)
{
day=dy;
}
int Date::getYear()
{
return Date::year; }
void Date::setYear(int yr)
{
Date::year=yr;
}
int main() // Работа с созданным классом
{
/*Здесь с помощью конструктора в экземпляре класса (экземпляр
MyDate)
устанавливаются заданные пользователем значения:*/
Date Mydate(21,1,2010);
int d,m,y;d=Mydate.getDay(); //d=21
m=Mydate.getMonth();
//m=3
y=Mydate.getYear();
//y=2007
printf("d=%d, m=%d, y=%d\n",d,m,y);
Date BirthDate(1,12,1938);
/*Изменить значение месяца на значение 4 в экземпляре Mydate*/
Mydate.setMonth(4);
m=Mydate.getMonth(); // m=4
printf("d=%d, m=%d, y=%d\n",d,m,y);
/*Изменить значение месяца на значение 5 в экземпляре BirthDate*/
BirthDate.setMonth(5);
m=BirthDate.getMonth(); // m=5
printf("d=%d, m=%d, y=%d\n",d,m,y);
_getch();
}
Рис.13 Работа конструктора класса
с
именем
Заметим, что у класса может быть много конструкторов. Когда создается класс, то для
инициализации его различных полей и создаются различные конструкторы. Хотя все они
имеют одинаковое имя, совпадающее с именем класса, тем не менее компилятор их
различает по наборам параметров и типов.
Деструктор класса.
Суть этой функции – обратная сути функции конструктора. Она призвана разрушить
созданный конструтором экземпляр класса и освободить от него память. Имя деструктора
совпадает с именем класса, но перед ним указывается знак «тильда» (~). Деструктор у
класса должен быть один.
Методические указания
При выполнении задания к данной лабораторной работе необходимо:
Написать программу, демонстрирующую работу с классом согласно варианту задания.
 Создать проект CLR – консольное приложение.
 Протестировать проект.
 Построить проект.
 Создать установщик для своего приложения.
Варианты лабораторных заданий.
Вариант 1
Создайте класс Int. имитирующий стандартный тип int. Единственное поле этого
класса должно иметь тип int. Создайте методы, которые будут устанавливать значение
поля, равным нулю, инициализировать его целым значением, выводить значение поля на
экран и складывать два значения типа Int.
Вариант 2
Создайте класс с именем Time, содержащий три поля типа char предназначенные
для хранения часов, минут и секунд. Один из конструкторов класса должен
инициализировать поля нулевыми значениями, а другой конструктор — заданным
набором значений. Создайте метод класса, который будет выводить значения полей на
экран в формате 11:59:59. и метод, складывающий значения двух объектов типа Time,
передаваемых в качестве аргументов.
Вариант 3
1). Создайте класс с именем Date. Его данные должны размешаться в трех полях
тина int; Month, Day и Year. Метод класса Getdate() должен принимать значение для
объекта в формате 12/05/09, а метод Showdate() — выводить данные на экран в формате 12
мая 2009г.
Вариант 4
1). Создайте класс, имитирующий работу пункта для взимания платежей за проезд
по автостраде. Каждая проезжающая машина должна заплатить за проезд n руб, однако
часть машин платит за проезд, а часть проезжает бесплатно. В кассе ведется учет числа
проехавших машин и суммарная выручка от платы за проезд.
Класс должен содержать три поля. Одно из них типа unsigned int предназначено
для учета количества проехавших автомобилей, второе, имеющее тип double, будет
содержать суммарную выручку от оплаты проезда, а третье константное поле – плату за
проезд. Конструктор должен инициализировать два поля нулевыми значениями, а третье
значением заданным пользователем. Метод payingCar() инкрементирует число машин и
увеличивает на значение константного поля суммарную выручку. Другой метод.
nopayCar(). увеличивает на единицу число автомобилей, но оставляет без изменения
выручку. Метод display() выводит оба значения на экран.
Вариант 5
Создайте класс Fraction. Данные класса должны быть представлены двумя полями:
числителем и знаменателем. Методы класса должны получать от пользователя значения
числителя и знаменателя дроби в формате 3/5 и выводить значение дроби в этом же
формате. Кроме того, должен быть разработан метод, складывающий значения двух
дробей. Напишите программу, которая циклически запрашивает у пользователя ввод пары
дробей, затем складывает их и выводит результат на экран. После каждой такой операции
программа должна спрашивать пользователя, следует ли продолжать цикл.
Вариант 6
Создайте класс Employee. Класс должен включать поле типа int для хранения
номера сотрудника, поле типа std::string для хранения ФИО сотрудника и поле типа float
для хранения величины его оклада. Методы класса должны позволять пользователю
вводить и отображать данные класса. Создайте программу, демонстрирующую работу
класса. Напишите программу, создающую массив типа Employee, а затем предложить
пользователю внести данные для 10 служащих. После этого необходимо вывести данные
всех служащих на экран компьютера.
Вариант 7
Создайте класс Money имитирующий денежный тип с фиксированной десятичной
точкой. Данные класса должны быть представлены двумя полями: количеством рублей
(тип long) и количеством копеек (тип char). Методы класса должны получать от
пользователя строку в формате 4 000 678 889,88 руб и выводить значение в этом же
формате. Кроме того, должен быть разработан метод, складывающий значения двух
денежных величин. Напишите программу, выводящую на экран сумму всех денежных
величин введенных пользователем.
Вариант 8
Напишите класс SafeArray который использует массив типа int фиксированного
размера. В классе необходимо описать два метода. Первый, Set(). принимает индекс и
значение типа int как аргументы и вставляет это значение в массив по заданному индексу.
Второй, Get(), принимает индекс как аргумент и возвращает значение типа int,
содержащееся в элементе с этим индексом. Оба метода должны проверять индекс
аргумента, чтобы быть уверенными, что он не выходит за размеры массива.
Вариант 9
Создать класс Date для работы с датами в формате «год, месяц день». Дата
представляется структурой с тремя полями типа unsigned int: для года, месяца и дня. Класс
должен включать не менее трех функций инициализации: числами, строкой вида «год,
месяц, день» (например. «2004.08.31») и датой. Обязательными операциями являются:
вычисление даты через заданное количество дней, вычитание заданного количества дней
из даты, определение високосности года, присвоение и получение отдельных частей (год,
месяц, день), сравнение дат (равно, до, после), вычисление количества дней между
датами.
Вариант 10
Рациональная (несократимая) дробь представляется парой целых чисел (а, b), где а
— числитель. b — знаменатель. Создать класс Rational для работы с рациональными
дробями. Обязательно должны быть реализованы операции:

сложения add, (a, b) + (c,d) = (ad + be, bd);

вычитания sub, (а, b) − (с, d) = (ad − be, bd);

умножения mul, (a, b) * (с, d) = (ас, bd);

деления div, (a, b) / (c,d) = (ad, be);
Вариант 11
Создать класс Money для работы с денежными суммами. Число должно быть
представлено двумя полями: типа long для рублей и типа unsigned char — для копеек.
Дробная часть (копейки) при выводе на экран должна быть отделена от целой части
запятой. Реализовать сложение, вычитание, деление сумм, деление суммы на дробное
число, умножение на дробное число и операции сравнения.
Вариант 12
Создать класс Angle для работы с углами на плоскости, задаваемыми величиной в
градусах и минутах. Обязательно должны быть реализованы: перевод в радианы,
приведение к диапазону 0−360º, увеличение и уменьшение угла на заданную величину,
получение синуса, сравнение углов.
Вариант 13
Создать класс Time для работы со временем в формате «час:минута:секунда».
Класс должен включать в себя не менее четырех функций инициализации: числами,
строкой (например, «23:59:59»), секундами и временем. Обязательными операциями
являются: вычисление разницы между двумя моментами времени в секундах, сложение
времени и заданного количества секунд, вычитание из времени заданного количества
секунд, сравнение моментов времени, перевод в секунды, перевод в минуты (с
округлением до целой минуты).
Вариант 14
Реализовать класс: Account, представляющий собой банковский счет. В классе
должны быть четыре поля: фамилия владельца, номер счета, процент начисления и сумма
в рублях. Открытие нового счета выполняется операцией инициализации. Необходимо
выполнять следующие операции: сменить владельца счета, снять некоторую сумму денег
со счета, положить деньги на счет, начислить проценты, перевести сумму в доллары,
перевести сумму в евро, получить сумму прописью (преобразовать в числительное).
Вариант 15
Номиналы российских рублей могут принимать значения 1, 2, 5, 10, 50. 100. 500,
1000, 5000. Копейки представить как 0.01 (1 копейка). 0.05 (5 копеек). 0.1 (10 копеек). 0.5
(50 копеек). Создать класс Money для работы с денежными суммами. Сумма должна быть
представлена полями−номиналами, значениями которых должно быть количество купюр
данного достоинства. Реализовать сложение сумм, вычитание сумм, деление сумм,
деление суммы на дробное число, умножение на дробное число и операции сравнения.
Дробная часть (копейки) при выводе на экран должна быть отделена от целой части
запятой.
Вариант 16
Написать класс для аффективной работы со строками, позволяющий
форматировать и сравнивать строки, хранить в строках числовые значения и извлекать их.
Для этого необходимо реализовать:

перегруженные операции присваивания и конкатенации;

операции сравнения и приведения типов;

преобразование в число любого типа;

форматный вывод строки.
Вариант 17
Описать класс «записная книжка». Предусмотреть возможность работы с
произвольным числом записей, поиска записи по какому−либо признаку (например, по
фамилии, дате рождения или номеру телефона), добавления и удаления записей,
сортировки по разным полям.
Вариант 18
Создать класс Fraction для работы с дробными числами. Число должно быть
представлено двумя нолями, целая часть длинное целое со знаком, дробная часть —
беззнаковое короткое целое. Реализовать арифметические операции сложения, вычитания,
умножения и операции сравнения.
Вариант 19
Создать класс Goods (товар). В классе должны быть представлены данные−члены:
наименование товара, дата оформления, цена товара, количество единиц товара, номер
накладной, по которой товар поступил на склад. Реализовать методы изменения цены
товара, изменения количества товара (увеличения и уменьшения), вычисления стоимости
товара. Метод toString() должен выдавать в виде строки стоимость товара.
Вариант 20
Описать класс «множество», позволяющий выполнять основные операции —
добавление и удаление элемента, пересечение, объединение и разность множеств.
Контрольные вопросы:
1. Как создать проект CLR – консольное приложение?
2. Что такое файл исходного кода? Как добавить такой файл в проект?
3. Как запускается проект в режиме отладки?
4. Что такое развертывание программы?
5. Определение класса? Структура класса?
6. Конструкторы и деструкторы класса?
7. Основные принципы построения классов
8. Спецификаторы доступа ?
9. Экземпляры класса ?
10. Инициализация данных объекта?
11. Переопределение операций?
12. Что такое объект и каким образом объекты соединяются в систему для решения
задачи?
13. Чем характеризуется объект?
14. Каким образом в программных объектах реализуются состояние, поведение и
идентификация объектов предметной области?
15. Что такое переопределение операций? Какие операции можно переопределять?
Лабораторная работа 2
Тема: Наследование.
Цель работы : изучение особенностей техники открытого и закрытого наследования в
свете концепции объектно−ориентированного программирования.
Теоретические основы:
Наследование.
Наследование – второй принцип построения классов. Мы видели, что классы в общем
случае могут составлять иерархию: один класс получается из другого, на основании
другого получается третий и т.д. То есть речь идет о том, что и в классах существуют
родители и дети, бабушки с дедушками, их внуки и т.д. наследование предполагает, что все
характеристики класса-родителя присваиваются классу-потомку. После этого потомку при
необходимости добавляют новые характеристики. Иногда некоторые методы в классепотомке, полученном от предков, переопределяются, т.е. наполняются новым содержанием.
Наследование используется не только при разработке классов, но и при проектировании
приложения. Например, в Visual C++ есть класс Label (метка). Если поместить экземпляр
этой метки в форму (экземпляр Form), то свойство «шрифт» метки примет значение
свойства «шрифт» из экземпляра Form. Меняя параметры шрифта у родителя (Form), мы
добиваемся изменения этих параметров у потомков (наследников). То есть метка
автоматически будет наследовать это свойство от экземпляра Form, на который она
помещена. Это же относится, например, и к классу Button (кнопка). Пример только что
сказанного показан на рисунке 1, из которого видно, как изменяется шрифт компонентов
Кнопка и Метка в зависимости от изменения шрифта в форме.
Размер шрифта формы равен
12
Размер шрифта формы
равен 20
Рис.1 Наследование свойства «шрифт» потомками от родителя.
Простым (или одиночным) называется наследование, при котором производный
класс имеет только одного родителя. Формально наследование одного класса от другого
задается следующей конструкций:
class имя_класса_потомка: [модификатор_доступа] имя_базового_класса
{ тело_класса }
Модификатор доступа определяет доступность элементов базового класса в
классе−наследнике. Квадратные скобки не являются элементом синтаксиса, а показывают,
что модификатор может отсутствовать. Этот модификатор называется модификатором
наследования.
При разработке отдельных классов используются два модификатора доступа к
элементам класса: public (общий) и private (личный). При наследовании применяется еще
один: protected (защищенный). Защищенные элементы класса доступны только прямым
наследникам и никому другому.
Возможны четыре варианта наследования.
1. Класс от класса.
2. Класс от структуры.
3. Структура от структуры.
4. Структура от класса.
Доступность элементов базового класса из классов−наследников изменяется в
зависимости от модификаторов доступа в базовом классе и модификатора наследования.
Каким бы ни был модификатор наследования, приватные элементы базового класса
недоступны в его потомках. В табл. 1.1 приведены все варианты доступности элементов
базового класса в производном классе при любых вариантах модификатора наследования.
Таблица 1.1 Доступ к элементам базового класса в классе−наследнике
Модификатор доступа Модификатор
в базовом классе
наследования
Доступ в производном классе
struct
class
public
отсутствует
public
private
protected
отсутствует
public
private
private
отсутствует
недоступны
недоступны
public
public
public
public
protected
public
protected
protected
private
public
недоступны
недоступны
public
protected
protected
protected
protected
protected
protected
protected
private
protected
недоступны
недоступны
public
private
private
private
protected
private
private
private
private
private
недоступны
недоступны
Если модификатор наследования — public, наследование называется открытым.
Модификатор protected определяет защищенное наследование, а слово private означает
закрытое наследование.
Конструкторы и деструкторы при наследовании
Конструкторы не наследуются — они создаются в производном классе (если не
определены программистом явно). Система поступает с конструкторами следующим
образом:
 если в базовом классе нет конструкторов или есть конструктор без аргументов
(или аргументы присваиваются по умолчанию), то в производном классе создание
конструктора можно опустить — компилятор автоматически создаст конструктор
копирования и конструктор без аргументов;
 если в базовом классе все конструкторы с аргументами, производный класс
обязан иметь конструктор, в котором явно должен быть вызван конструктор базового
класса;
 при создании объекта производного класса сначала вызывается конструктор
базового класса, затем — производного.
Деструктор класса, как и конструкторы, не наследуется, а создается. С
деструкторами система поступает следующим образом:
 при отсутствии деструктора в производном классе компилятор создает
деструктор но умолчанию;
 деструктор базового класса вызывается в деструкторе производного класса
автоматически независимо от того, определен он явно или создан компилятором;
 деструкторы вызываются (для уничтожения объектов) в порядке, обратном
вызову конструкторов.
 создание и уничтожение объектов выполняется по принципу LIFO: последним
создан — первым уничтожен.
Данные−член и функции−член при наследовании
Класс−потомок наследует структуру (все элементы данных) и поведение (все
функции−член) базового класса. Класс−наследник получает в наследство все
данные−член базового класса (хотя, если они были приватные, доступа к ним ему
запрещён). Если новые данные−член не добавляются, размер класса−наследника
совпадает с размером базового класса. Порожденный класс может добавить собственные
данные−член:
Дополнительные данные−член производного класса могут совпадать и по имени, и
по типу с данными−член базового класса — в этом случае новые данные−член скрывают
данные−член базового класса, поэтому для доступа к данным−член базового класса в
классе−наследнике необходимо использовать префикс−квалификатор базового класса.
Класс−потомок наследует все функции−член базового класса, кроме операции
присваивания — она создается для нового класса автоматически, если не определена явно.
В классе−наследнике можно определять новые функции−член. В новых функциях−член
разрешается вызывать любые доступные функции−член базового класса.
Если в классе−наследнике имя функции−член и его прототип совпадают с именем
функции−член базового класса, то говорят, что функция−член производного класса
скрывает функцию−член базового класса. Чтобы вызвать метод родительского класса,
необходимо указывать его с квалификатором класса.
Операция присваивания и принцип подстановки
Открытое наследование устанавливает между классами отношение «является»:
класс−наследник является разновидностью класса−родителя. Это означает, что везде, где
может быть использован объект базового класса (при присваивании, при передаче
параметров и возврате результата), вместо него разрешается подставлять объект
производного класса. Данное положение называется принципом подстановки и
поддерживается компилятором. Этот принцип работает и для ссылок, и для указателей:
вместо ссылки (указателя) на базовый класс может быть подставлена ссылка (указатель)
на класс−наследник. Обратное − неверно! Например, спортсмен является человеком, но не
всякий человек — спортсмен. Здесь человек — базовый класс, а спортсмен —
производный.
Помимо конструкторов, не наследуются два вида функций: операция присваивания
и дружественные функции. Операция присваивания, как и конструкторы с деструктором,
для любого класса создается автоматически.
В теле дочерней операции присваивания выполняется вызов родительской
операции в функциональной форме. Эта операция похожа на операцию преобразования
объектов базового класса в производный.
В любом классе операцию присваивания можно перегрузить неоднократно. При
этом разрешается, чтобы ни аргумент, ни результат не являлись определяемым классом.
Единственным ограничением является видимость определения нужных классов в точке
определения операции присваивания.
Дружественные функции не наследуются, поскольку не являются методами
базового класса, хотя и имеют доступ к внутренней структуре класса. При открытом
наследовании можно не дублировать дружественные функции для производного класса,
так как принцип подстановки обеспечивает помещение аргументов производного класса
на место параметров базового класса.
Если в производном классе определены дополнительные поля, то при подстановке
объектов происходит срезка (расщепление): объекту базового класса присваиваются
только унаследованные производным классом поля. При передаче параметра по значению
может произойти срезка при копировании. При передаче параметра по ссылке (или по
указателю) срезки не происходит.
Закрытое наследование
Закрытое наследование — это наследование реализации (в отличие от наследования
интерфейса): класс реализован посредством класса. Оно принципиально отличается от
открытого: принцип подстановки не соблюдается. Это означает, что нельзя присвоить (во
всяком случае, без явного преобразования типа) объект производного класса базовому.
Поэтому закрытое наследование хорошо применять в тех случаях, когда требуется иметь
функциональность базового класса, но не нужны ни копирование, ни присваивание.
При закрытом наследовании все элементы класса−наследника становятся
приватными и недоступными программе−клиенту.
Можно открыть функции−член базового класса с помощью using−объявления,
которое имеет следующий синтаксис:
using <имя базового класса>::<имя в базовой классе>;
Таким образом, закрытое наследование позволяет ограничить предоставляемую
производным классам функциональность.
Виртуальные функции
Связывание это сопоставление вызова функции с телом функции. Для обычных
функций−член связывание выполняется на этапе трансляции до запуска программы. Такое
связывание называют «ранним», или статическим. При наследовании обычной
функции−член его поведение не меняется в наследнике. Однако бывает необходимо,
чтобы поведение некоторых функций−член базового класса и классов−наследников
отличались. Чтобы добиться разного поведения в зависимости от типа, необходимо
объявить функцию−метод виртуальной; в C++ это делается с помощью ключевого слова
virtual. Виртуальные функции в совокупности с принципом подстановки обеспечивают
механизм «позднего» (отложенного) или динамического связывания, которое работает во
время выполнения программы.
Класс, в котором определены виртуальные функции (хотя бы одна), называется
полиморфным классом.
Ключевое слово virtual можно писать только в базовом классе — это достаточно
сделать в объявлении функции. Даже если определение писать без слова virtual, функция
все равно будет считаться виртуальной. Правила описания и использования виртуальных
функций−методов следующие.
1. Виртуальная функция может быть только методом класса.
2. Любую перегружаемую операцию−метод класса можно сделать виртуальной,
например операцию присваивания или операцию преобразования типа.
3. Виртуальная функция наследуется.
4. Виртуальная функция может быть константной.
5. Если в базовом классе определена виртуальная функция, то функция−член
производного класса с таким же именем и прототипом (включая и тип
возвращаемого значения, и константность функции−член) автоматически
является виртуальным (слово virtual указывать необязательно) и замещает
функцию−член базового класса.
6. Статические методы не могут быть виртуальными.
7. Конструкторы не могут быть виртуальными.
Деструкторы могут (чаще — должны) быть виртуальными — это гарантирует
корректное освобождение памяти через указатель базового класса.
Внутри конструкторов и деструкторов динамическое связывание не работает, хотя
вызов виртуальных функций не запрещен. В конструкторах и деструкторах всегда
вызывается «родная» функция класса.
Виртуальные функции−член можно перегружать и переопределять (в наследниках)
с другим списком аргументов. Если виртуальная функция переопределена с другим
списком аргументов, она замещает (скрывает) родительские методы. Константный метод
считается отличным от неконстантного метода с таким же прототипом.
Родительские методы можно сделать доступными в классе−наследнике при
помощи using−объявления.
Разрешается при переопределении виртуальной функции изменить только тип
возвращаемого значения, если это указатель или ссылка.
Чистые виртуальные функции и абстрактные классы
Виртуальная функция, не имеющая определения тела, называется чистой (риге) и
объявляется следующим образом:
virtual тип имя(параметры) = 0;
Предполагается, что данная функция будет реализована в классах−наследниках.
Класс, в котором есть хоть одна чистая виртуальная функция, называется
абстрактным классом. Объекты абстрактного класса создавать запрещено. И при передаче
параметра в функцию невозможно передать объект абстрактного класса по значению.
Однако указатели (и ссылки) определять можно.
При наследовании абстрактность сохраняется: если класс−наследник не реализует
унаследованную чистую виртуальную функцию, то он тоже является абстрактным. В C++
абстрактный класс определяет понятие интерфейса. Наследование от абстрактного класса
— это наследование интерфейса.
Пример_1:
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
using namespace System;
class A
{
protected:
int x;/* к этим данным имеют доступ только методы данного класса и
производных*/
int y;
public:
int a;
int b;
int f1(int x,int y)/* метод класса*/
{
return (x-y);
}
};
class B:A //это объявляется класс, производный от А, при этом наследуются
члены классы А
{
public:
int f2(int x)/* метод класса*/
{
/*Здесь
могут
использоваться
члены-данные
базового
класса
из
секции
protected.
Так как имя аргумента метода f2() совпадает с именем поля х из класса А,
унаследованного классом В,
то чтобы различить, какая переменная к какому классу относится, потребовалось
уточнить с помощью спецификатора ::.
Показано, что в теле метода х берется тот, что унаследован от А, и
собственный аргумент х самого метода f2():*/
A::x=20;
return (x+A::x);
}
};
int main()
{
Console::WriteLine(L"Здравствуй, мир!");
A min; //создание экземпляров классов А,В
B max;
min.a=10; // Работа с элементами класса А из секции public
min.b=20;
int x1=min.f1(min.a,min.b);
int x2=max.f2(10); // Работа с элементами класса В
printf("x1= %d\n x2= %d\n",x1,x2);
_getch();
//return 0;
}
Пример_2:
#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
using namespace System;
class A
{
protected:
int x;
int y;
public:
int a;
int b;
int f1(int x,int y)
{
return (x-y);
}
};
class B:A
{
public:
int f2(int x)
{
A::x=20;
return (x+A::x);
}
};
int main()
{
Console::WriteLine(L"Здравствуй, мир!");
A *min=(A *) new A();
B *max=(B *) new B();
min->a=10;
min->b=20;
int x1=min->f1(min->a,min->b);
int x2=max->f2(10);
printf("x1= %d\n x2= %d\n",x1,x2);
_getch();
delete min;
delete max;
}
Пример_3: Новый
класс
должен
характеристику изделия - его форму*/
#include "stdafx.h"
#include<stdio.h> //for printf()
#include <conio.h> // for _getch()
using namespace System;
будет
задавать
using namespace System;
//детали изделия в качестве объектов (экземпляров класса)
class produce //начало определения класса
{
private:
int modelnumber; // номер изделия
int partnumber; // номер детали
float cost;
// стоимость детали
public:
// установка данных
// функция-член класса
// присваивает данным класса значения своих параметров
void setpart(int mn, int pn, float c)
{
modelnumber=mn;
partnumber=pn;
cost=c;
}
void show() // вывод данных
{
printf("The Number of the Model is %d\n",modelnumber);
printf("The Number of the Part is %d\n ",partnumber);
printf("The Number of the Cost is %.2f\n ",cost);
}
};//конец описания класса
//Объявление класса-наследника с новыми членами:
class MoreProduce:public produce
{
public:
char *ProduceForm; //описание формы изделия
void FormDecl(char *s)
{
ProduceForm=s;
}
дополнительную
void show1()
{
printf("The ProduceForm is %s\n",ProduceForm);
}
};
// обработка класса в головной программе
int main()
{
MoreProduce newizd;
newizd.setpart(100,200,250.5);
newizd.FormDecl("Square");
newizd.show();
newizd.show1();
_getch();
}
Методические указания
При выполнении задания к данной лабораторной работе необходимо написать программу,
демонстрирующую работу наследования согласно варианту задания.
Варианты лабораторных заданий.
Вариант 1
Создать базовый класс Car (машина), характеризуемый торговой маркой (строка),
числом цилиндров, мощностью. Определить методы переназначения и изменения
мощности. Создать производный класс Lorry (грузовик), характеризуемый также
грузоподъемностью кузова. Определить функции переназначения марки и изменения
грузоподъемности.
Вариант 2
Создать класс Pair (пара чисел); определить методы изменения полей и сравнения пар:
пара p1 больше пары р2, если (first.pl > first.р2) или (first.pl > first.р2) и (second.pl >
second.р2). Определить класс−наследник Fraction с полями: целая часть числа и дробная
часть числа. Определить полный набор методов сравнения.
Вариант 3
Создать класс Liquid (жидкость), имеющий поля названия и плотности. Определить
методы переназначения и изменения плотности. Создать производный класс Alcohol
(спирт), имеющий крепость. Определить методы переназначения и изменения крепости.
Вариант 4
Создать класс Pair (пара чисел); определить методы изменения полей и вычисления
произведения чисел. Определить производный класс Rectangle (прямоугольник) с
полями−сторонами. Определить методы вычисления периметра и площади
прямоугольника.
Вариант 5
Создать класс Man (человек), с полями: имя, возраст, пол и вес. Определить методы
переназначения имени, изменения возраста и изменения веса. Создать производный класс
Student, имеющий поле года обучения. Определить методы переназначения и увеличения
года обучения.
Вариант 6
Создать класс Triad (тройка чисел); определить методы изменения полей и вычисления
суммы чисел. Определить производный класс Triangle с полями−сторонами. Определить
методы вычисления углов и площади треугольника.
Вариант 7
Создать класс Triangle с полями−сторонами. Определить методы изменения сторон,
вычисления углов, вычисления периметра. Создать производный класс Equilateral
(равносторонний), имеющий поле площади. Определить метод вычисления площади.
Вариант 8
Создать класс Triangle с полями−сторонами. Определить методы изменения сторон,
вычисления углов, вычисления периметра. Создать производный класс RightAngled
(прямоугольный), имеющий поле площади. Определить метод вычисления площади.
Вариант 9
Создать класс Pair (пара чисел); определить методы изменения полей и вычисления
произведения чисел. Определить производный класс RightAngled с полями−катетами.
Определить методы вычисления гипотенузы и площади треугольника.
Вариант 10
Создать класс Triad (тройка чисел); определить метод сравнения триад. Определить
производный класс Date с полями: год, месяц и день. Определить полный набор методов
сравнения дат.
Вариант 11
Создать класс Triad (тройка чисел); определить метод сравнения триад. Определить
производный класс Time с полями: час, минута и секунда. Определить полный набор
методов сравнения моментов времени.
Вариант 12
Реализовать класс−оболочку Number для числового типа float. Реализовать методы
сложения и деления. Создать производный класс Real, в котором реализовать метод
возведения в произвольную степень, и метод для вычисления логарифма числа.
Вариант 13
Создать класс Triad (тройка чисел); определить методы увеличения полей на 1.
Определить производный класс Date с полями: год, месяц и день. Переопределить методы
увеличения полей на 1 и определить метод увеличения даты на п дней.
Вариант 14
Реализовать класс−оболочку Number для числового типа double. Реализовать методы
умножения и вычитания. Создать производный класс Real, в котором реализовать метод,
вычисляющий корень произвольной степени, и метод для вычисления числа π в данной
степени.
Вариант 15
Создать класс Triad (тройка чисел); определить методы увеличения полей на 1.
Определить класс−наследник Time с данными−член: час, минута, секунда.
Переопределить методы увеличения полей на 1 и определить методы увеличения на п
секунд и минут.
Вариант 16
Создать базовый класс Pair (пара целых чисел) с операциями проверки на равенство и
перемножения полей. Реализовать операцию вычитания пар по формуле (а, b) − (с, d) = (а
− b, с − d). Создать производный класс Rational; определить новые операции сложения (a,
b) + (c,d) = (ad + bd, bd) и деления (a,b) / (с,d) = (a/d, b/d); переопределить операцию
вычитания (а,b) − (c,d) = (a − b,c − d).
Вариант 17
Создать класс Pair (пара чисел); определить метод перемножения полей и операцию
сложения пар (а, b) + (с, d) = (а + b, с + d). Определить производный класс Complex с
полями: действительная и мнимая части числа. Определить методы умножения (a, b)
×(c,d) = (ас × bd, ad × be) и вычитания (а,b) − (c,d) = (a − b,c − d).
Вариант 18
Создать класс Pair (пара целых чисел); определить методы изменения полей и операцию
сложения пар (а, b) + (с, d) = (а + b, с + d). Определить класс−наследник Long с полями:
старшая часть числа и младшая часть числа. Переопределить операцию сложения и
определить методы умножения и вычитания.
Вариант 19
Создать базовый класс Triad (тройка чисел) с операциями сложения с числом, умножения
на число, проверки на равенство. Создать производный класс vector3D, задаваемый
тройкой координат. Должны быть реализованы: операция сложения векторов, скалярное
произведение векторов.
Вариант 20
Создать класс Pair (пара целых чисел); определить метод умножения на число и операцию
сложения пар (а, b) + (с, d) = (а + b, с + d). Определить класс−наследник Money с полями:
рубли и копейки. Переопределить операцию сложения и определить методы вычитания и
деления денежных сумм.
Контрольные вопросы:
1. Дайте определение понятию виртуальная функция?
2. Что такое чистая виртуальная функция? Если в объявлении класса имеется
чистая виртуальная функция, как называется такой класс и какие ограничения налагаются
на его использование?
3. Как создать виртуальный конструктор−копировщик?
4. Как вызвать функцию базового класса из объекта производного класса, если в
производном классе эта функция была замешена?
5. Как вызвать функцию базового класса из объекта производного класса, если в
производном классе эта функция не была замешена?
6. Если в базовом классе функция объявлена как виртуальная, а в производном
классе виртуальность функции указана не была, сохранится ли функция как виртуальная в
следующем произведенном классе?
7. С какой целью используется ключевое слово protected?
8. Динамический полиморфизм достигается посредством использования _ функций
и указателей _ класса. (Вставьте пропущенные слова.)
9. Если при наличии иерархии классов в производном классе опушена перегрузка
(не чистой) виртуальной функции, что происходит, когда объект этого производного
класса вызывает такую функцию?
10. Что производный класс наследует из базового класса?
11. Что производный класс не наследует из базового класса?
12. В каком порядке вызываются конструкторы и деструкторы класса при
создании и удалении объекта производного класса?
13. Требуются ли конструкторы производному классу, если он не добавляет к
базовому классу элементы данных?
14. Почему лучше передавать объект по ссылке, а не по значению?
Лабораторная работа 3
Тема: Низкоуровневое проектирование Windows – приложений.
Цель работы :
Создание приложений Windows (C++)
Ознакомившись с интегрированной средой разработки Visual Studio и приложениями
командной строки, перейдем к рассмотрению способов создания приложений Windows.
Благодаря Visual C++ можно создавать приложения Windows с использованием различных
технологий, таких как Windows API (также известный как Win32 API) и .NET Framework.
В этой лабораторной работе будет рассмотрено создание приложения Windows с
использованием Win32 API.
Основные понятия и термины, используемые при разработке Windows
приложений
Ядро Windows:
 USER (16, 32) .dll – функции ввода с клавиатуры мыши, ввод через интерфейс и
т.д. (взаимодействие приложений с пользователями и средой Windows).
 KERNEL (16, 32) .dll – функции операционной системы (память, распределение
системных ресурсов, загрузка).
 GDI (16, 32) .dll – графический интерфейс (функции создания и отображения
графических объектов).
GUI (Graphics User Interface) – стандартный графический интерфейс пользователя. Это
та часть Windows, которая обеспечивает поддержку аппаратно-независимой графики.
API (Application Program Interface) — интерфейс прикладных программ (набор
функций, сосредоточенных в ядре Windows и дополнительных библиотеках).
DLL (Dynamic Link Libraries) — библиотека динамической компоновки. Функции API
содержатся в библиотеках динамической загрузки.
DDE – динамический обмен данными.
Окно – это специальная прямоугольная область экрана. Все элементы окна, его
размер и внешний вид контролируются открывающей его программой. Каждый щелчок
мышью, выполняемый пользователем на каком-либо элементе окна, вызывает ответные
действия приложения. Многозадачность Windows заключается, в частности, в
возможности одновременного открытия окон нескольких приложений или же нескольких
окон одного приложения. Активизируя с помощью мыши или клавиатуры то или иное
окно, пользователь дает системе понять, что последующие команды и данные следует
направлять именно этому окну. Стандартный внешний вид окон Windows приложений и
предсказуемость работы их компонентов позволяют пользователям чувствовать себя
уверенно с новыми приложениями и легко разбираться в принципах их работы.
Пиктограмма
приложения
– системное
меню
Строка заголовка
Кнопка свертывания
Строка панели инструментов
Кнопка закрытия
Кнопка
восстановлени
Рамка окна
Рис. 1. Основные компоненты окна.
Классы окон.
Чтобы два окна выглядели и работали совершенно одинаково, они оба должны
базироваться на общем классе окна. В приложениях класс окна регистрируется
программой в процессе инициализации. Зарегистрированный класс становится доступным
для всех программ, запущенных в данный момент в системе. Благодаря тому, что окна
приложения создаются на основе общего базового класса, значительно сокращается объем
информации, которую при этом следует указывать. Поскольку класс окна содержит в себе
описания элементов, общих для всех окон данного класса, нет необходимости повторять
эти описания при создании каждого нового окна. К тому же в приложениях,
использующих функции API, все окна одного класса используют одну общую оконную
процедуру (функцию), обеспечивающую работу с различными однотипными окнами. Это
позволяет избежать дублирования кода.
Графические объекты, используемые в окнах.
Значками называются графические изображения, выполняющие опознавательную
функцию. Так, значки приложений на панели задач позволяют легко определить, какие
программы в настоящий момент запущены. В состав ОС Windows входит набор
стандартных значков. С Помощью встроенного в IDE редактора ресурсов вы можете
создавать собственные значки.
Указатели мыши также являются графическими объектами, используемыми для
отслеживания перемещения мыши. Вид указателя может меняться в зависимости от
выполняемого задания и состояния системы.
Курсоры предназначены для указания места, куда следует осуществлять ввод текстовых
данных. Отличительной чертой курсоров является их мерцание.
Окна сообщений представляют собой разновидность диалоговых окон, содержащих
строку заголовка, значок, текст сообщения и кнопку. Окно сообщений создается путем
вызова функции MessageBox, аргументы которой задают текст заголовка окна, текст
сообщения, какой из стандартных значков Windows использовать (если это необходимо) и
какой набор кнопок выводить. В частности, можно вызывать окна со следующими
комбинациями кнопок:
Abort/Retry/Ignore
(Прервать/Повторять/Игнорировать), OK,
Yes/No (Да/Нет), Yes/No/Cancel (Да/Нет/Отмена) , OK/Cancel
(ОК/Отмена) и
Retry/Cancel
(Повторять/Отмена).
Рис. 2. Окно сообщения текстового редактора.
Шрифт в Windows – это графический ресурс, содержащий набор символов определенного
типа. Шрифты бывают растровые, контурные и масштабируемые.
Растровый
шрифт
(raster font) представляет символы с помощью растровых
изображений. Такие изображения плохо поддаются масштабированию, из-за чего страдает
качество образов.
Контурный шрифт (stroke font) представляет символы с помощью линий. Такие шрифты
предназначены, прежде всего, для графопостроителей (плоттеров).
Масштабируемый шрифт (true type font) представляет символы с помощью линий и
сплайновых кривых. Такие шрифты масштабируются практически до любого размера без
ухудшения качества образов.
Существует набор функций, с помощью которых можно манипулировать начертанием
символов для получения форматированного текста. В приложениях можно использовать
как стандартные шрифты, так и пользовательские шрифты. Встроенные функции
позволяют получать, на базе основного шрифта, полужирное начертание, курсив,
подчеркнуты текст и изменять размер шрифта. Внешний вид шрифта можно сделать
независимым от типа устройства, на которое выводится текст.
Точечные рисунки представляют собой точную копию части экрана, устраняет
необходимость в каких либо дополнительных преобразованиях, что существенно
сокращает время вывода изображения на экран. В Windows точечные рисунки наиболее
широко применяются для двух целей. Во-первых, они служат изображениями
всевозможных кнопок и значков, например, стрелок полос прокрутки и кнопок панелей
инструментов. Другой областью применения точечных рисунков являются кисти, с
помощью которых рисуются и заполняются цветом различные геометрические фигуры на
экране. Точечные рисунки можно создавать и модифицировать с помощью встроенного
редактора ресурсов.
Перья предназначены для рисования геометрических фигур и различных контуров. Перья
характеризуются тремя основными параметрами:
 Шириной линии;
 Стилем (точечный, штрихпунктирный, непрерывный);
 Цветом.
Существует два готовых пера: одно для рисования черных линий, другое – для рисования
белых. С помощью специальных функции вы можете создавать собственные перья.
Кисти предназначены для заливки объектов цветом, выбранным из заданной палитры.
Минимальный размер кисти - 8×8 пикселов. Кисть также характеризуется тремя
параметрами:
 Размером;
 Шаблоном заливки;
 Цветом.
Заливка может быть сплошной, штриховой, диагональной или представлять собой узор,
заданный пользователем.
Принципы обработки сообщений.
Ни одно приложение в Windows не отображает свои данные непосредственно на экране,
не обрабатывает напрямую прерывания устройств и не выводит данные непосредственно
на печать. Вместо всего этого приложение вызывает встроенные функции Windows и
ожидает от системы соответствующих сообщений. ОС Windows является событийноуправляемой ОС. Этот термин означает, что отдельные части ОС взаимодействуют между
собой, а также с прикладными программами посредством сообщений.
Сообщение – это форма регистрации событий в ОС. Система использует сообщения для
того. Чтобы сигнализировать о совершении событий. Подсистема сообщений в Windows,
используемая в ОС и пользовательских приложениях, - это средство распределения
информации в многозадачной среде. С точки зрения приложения, сообщение – это
уведомление о некотором произошедшем событии, на которое приложение должно
отреагировать определенном образом. Такое событие может быть инициировано
пользователем, например, нажатием клавиши или перемещением мыши, изменением
размера окна или выбором команды из меню. Но события могут порождаться и самим
приложением. Особенность этого процесса состоит в том, что приложение должно быть
полностью ориентировано на прием и обработку сообщений. Программа должна быть
готова в любой момент принять сообщение, определить его тип, выполнить
соответствующую обработку и вновь перейти в режим ожидания до наступления
следующего сообщения.
Сообщения используются для информирования приложения о том, что в системе
произошло то или иное событие. На практике, сообщения направляются не столько
самому приложению, сколько определенному окну, открытому этим приложением.
Реально в Windows существует только один механизм обработки сообщений. Но каждое
выполняющееся приложение организовывает и свою очередь. Функции модуля USER, в
частности, ответственны за передачу сообщений из системной очереди в очередь
конкретного
приложения.
Таким
образом,
в
очереди
конкретного
приложения
накапливаются сообщения, адресованные любому окну, открытому данным приложением.
Независимо от типа, все сообщения для 32-разрядных версий Windows характеризуется
четырьмя параметрами (рис.3):
 Дескриптором окна, которому адресуется данное сообщение;
 Типом сообщения;
 Еще двумя 32-разрядными параметрами.
Дескриптор окна
Тип сообщения
32-разрядный
параметр
32-разрядный
параметр
Рис.3 Структура сообщения
Дескрипторы (handle, описатель) широко используются в приложениях ОС Windows.
Дескриптором называется уникальный номер (беззнаковое 32-разрядное целой значение),
который присваивается всем системным объектам, таким как: окна, элементы управления,
меню, значки, перья и кисти, а также областям памяти, устройствам вывода и т.д.
Поскольку Windows позволяет одновременно открывать несколько копий одного
приложения, ОС должна иметь возможность отслеживать каждую копию в отдельности.
Это достигается путем присвоения каждому экземпляру программы своего дескриптора.
Тип сообщения (второй параметр) задается идентификатором, который определен в
одном из файлов заголовков Windows. Для работы с идентификаторами сообщений в
программу включается файл windows.h. Как правило, идентификаторы начинаются с
двухсимвольного префикса, за которым следует символ подчеркивания. Так, оконные
сообщения начинаются с префикса WM_: WM_CREATЕ, WM_DESTROY, WM_SIZE,
WM_PAINT, WM_QUIT, WM_COMMAND и др. сообщения кнопок имеют префикс BM_,
полей – EM_ и т.д. в приложении, можно создать и зарегистрировать собственный тип
сообщения, предназначенного для частных целей.
Последние два параметра сообщения несут дополнительную информацию. Их содержание
может изменяться в зависимости от типа сообщения. Например, посредством этих
параметров может передаваться информация о том, какая клавиша была нажата, какая
команда меню активизирована и т.д. Форматы некоторых оконных сообщений приведены
на рис.4-8. Разберем их. Система посылает окну Windows сообщение WM_CREATЕ после
его создания, но до появления образа окна на экране. Свой первый параметр сообщение
WM_CREATЕ не использует. Второй параметр содержит указатель на структуру типа
CREATESTRUCT, которая содержит информацию о создаваемом окне. Если приложение
обрабатывает WM_CREATЕ, то при успешной работе оно должно возвращать 0. При этом
создание окна продолжается. Если же приложение возвращает -1, то функция создания
окна (CreateWindow или CreateWindowEx ) возвращает пустой манипулятор (со значением
0).
Указатель на структуру
CREATESTRUCT
Дескриптор окна
32-разрядный
параметр
Тип сообщения
WM_CREATЕ
32-разрядный
параметр
________
Рис.4 Структура сообщения WM_CREATЕ
Дескриптор окна
Тип сообщения
32-разрядный
параметр
32-разрядный
параметр
Рис. 5 Структура сообщения WM_DESTROY
Новая высота клиентской
области
Дескриптор окна
Тип сообщения
32-разрядный
параметр
32-разрядный
параметр
Рис. 6 Структура сообщения WM_SIZE
Система посылает сообщение WM_DESTROY окну перед его уничтожением после того,
как образ окна удален с экрана. Сообщение WM_DESTROY не использует оба параметра.
Если приложение обрабатывает WM_DESTROY, то оно должно возвращать значение 0.
Система посылает сообщение WM_SIZE окну Windows после того, как размер окна
изменен. Значения новых размеров клиентской области окна можно получить с помощью
макросов: LOWORD(lParam) дает ширину, а HIWORD(lParam) – высоту. Если
приложение обрабатывает WM_SIZE, то оно должно возвращать значение 0.
Дескриптор окна
Тип сообщения
32-разрядный
параметр
WM_QUIT
32-разрядный
параметр
______
Код возврата
Рис. 7 Структура сообщения WM_QUIT
Сообщение WM_QUIT означает запрос на завершение работы приложения. Оно приводит
к тому, что специальная функция GetMessage возвращает значение 0. Первый параметр
задает значение кода возврата, который приложение передает ОС при своем завершении.
Дескриптор окна
Тип сообщения
WM_PAINT
32-разрядный
параметр
________
32-разрядный
параметр
__________
Рис. 8 Структура сообщения WM_PAINT
Сообщение WM_PAINT посылается окну, если система, или другое приложение, выдает
запрос на перерисовку окна (или его части). В частности, WM_PAINT посылается в
результате вызова функций UpdateWindow и RedrawWindow. Сообщение WM_PAINT не
использует оба параметра. Если приложение обрабатывает WM_PAINT, то оно должно
возвращать значение 0.
Именно
реализация
концепции
обмена
сообщениями
позволяет
Windows
быть
многозадачной средой. Работа Windows основана на передаче, приеме и обработке
сообщений.
Существует четыре основных источника, от которых приложение может получить
сообщение:
 пользователь;
 ОС Windows;
 само приложение;
 другие приложения.
Сообщения пользователей включают информацию о вводе текста, перемещении мыши,
нажатия кнопок мыши, выборе команд меню, перемещении бегунка полос прокрутки и
т.д. большую часть времени приложение занято обработкой именно таких сообщений.
Получение сообщения от пользователя означает, что человек, запустивший программу,
хочет изменить ход ее выполнения.
Системные сообщения посылаются программе при изменении ее состояния. Например,
щелчок на значке приложения означает, что пользователь хочет сделать данное
приложение активным. В этом случае Windows сообщает приложению, что на экране
открывается его окно, размер и положение окна изменяются и т.д. В зависимости от
текущего состояния приложения сообщение от Windows может быть принято и
обработано либо проигнорировано.
Нотация Windows ("венгерская нотация Чарльза Симони")
При программировании под Windows принято использовать префиксы перед именами
переменных, указывающие на принадлежность к типу данных. Рекомендуется давать
имена собственным переменным и идентификаторам, придерживаясь следующих
принципов:
1. мнемоническое значение – идентификатор должен легко запоминаться;
2. смысловое значение – роль идентификатора должна быть ясна из его названия;
3. преемственность – похожие объекты должны иметь похожие идентификаторы;
4. быстрота принятия решения
–
придумывание, ввод
и
редактирование
идентификатора не должны занимать много времени.
Некоторые префиксы венгерской нотации:
Префикс
Значение
A
массив
B
логический тип (int)
By
беззнаковый символьный тип (byte)
C
символьный тип (1 байт)
Cb
счетчик байтов
Cr
цвет
cx,cy
короткий тип (short)
Dbl
double (с плавающей точкой)
Dw
беззнаковое длинное целое число (dword)
Flt
float (вещественная с плавающей точкой)
Fn
функция
g_
префикс для глобальной переменной (глобальная переменная)
H
handle (беззнаковое целое число)
hDC
handle (указатель на контекст устройства)
I
целое (integer)
Id
интегральное значение идентификатора
L
длинный тип (long)
Lp
длинный указатель
Lpsz
дальний указатель на строку, закачивающуюся нулевым байтом
m_
переменная класса
N
short или int
Np
ближний указатель
P
указатель
Pfn
указатель на функцию
Pst
указатель на структуру
Psz
указатель на строку, заканчивающуюся нулевым байтом
Pv
указатель на тип void
S
строка
Sz
строка, заканчивающая нуль-символом
U
беззнаковый символ
Tm
текстовая метрика
V
тип void
W
беззнаковое целое (word, 16-бит)
x, y
короткое целое число (координата x или y)
Таблица 1. Наиболее часто используемые типы данных в Windows.
Тип
Описание
CALLBACK
Замещает спецификацию FAR PASCAL в функциях обратного вызова
HINSTANGE
32-разрядное беззнаковое целое число, используемое в качестве
дескриптора
HDC
Дескриптор контекста устройства
HWND
Дескриптор окна
LPARAM
Используется для описания младшего аргумента сообщения
LPCSTR
32-разрядный указатель на константную строку
LPSTR
32-разрядный указатель на строку
LRRESULT
Используется для возвращения значений из оконных процедур
UINT
32-разрядное беззнаковое целое число
WINAPI
Замещает спецификацию FAR PASCAL в описаниях функций API
WPARAM
Используется для описания старшего аргумента сообщения
Таблица 2. Наиболее часто используемые структуры Windows.
Структура
Что определяет
MSG
Параметры сообщений
PAINTSTRUCT Область окна, требующая перерисовки
WNDCLASS
Класс окна
Windows – приложения содержат два общих элемента:
1. Функцию WinMain;
2. Оконную процедуру.
Функция WinMain составляет основу любого приложения. Она служит точкой входа в
приложение и выполняет ту же роль, что и функция main в обычных программах на
языках С и Си++.
Оконная процедура исполняет роль диспетчера сообщений. Приложения никогда не
получают к ней прямого доступа. Для этого им сначала нужно сделать запрос к Windows
на выполнение соответствующего действия. Поэтому все оконные процедуры должны
быть функциями обратного вызова (callback). Подобная функция регистрируется в ОС и
вызывается всякий раз, когда выполняется некоторое действие над окном.
Функция WinMain, как было сказано, является обязательным компонентом любого
Windows – приложения. С нее начинается выполнение программы и ею же обычно
заканчивается. Эта функция состоит из трех функциональных частей, в которых,
соответственно, выполняются:
1. Начальная инициализация приложения (подготовка данных класса окна и его
регистрация);
2. Создание главного окна приложения;
3. Запуск цикла обработки сообщений, извлекаемых из очереди сообщений
приложения (цикл обработки сообщений и приложение завершаются после
получения сообщения WM_QUIT).
В рамках данной процедуры создается простейшее приложений Win32,
отображающее приветствие "Hello, World!" в отдельном окне. При создании любых
приложений Win32 порядок действий одинаков. По завершении выполнения
процедуры получившийся код можно использовать в качестве основы для создания
любых других приложений Win32.
Создание простейшего Windows-приложения с использованием Win API
Windows API представляет собой набор функций, совместно вызываемых из одной
программы (или из связанного набора программ), который программист использует для
создания Windows – приложений и взаимодействия с операционной системой.
Разбираться во внутреннем содержании функций совсем не обязательно – достаточно
иметь лишь их документированные спецификации. Сегодня функции Windows API
являются наиболее известными интерфейсами прикладных программ.
Прежде чем рассмотреть простейшее Windows – приложение, созданное на основе
Windows API, в качестве справки, перечислим наиболее часто используемые
данные(таблица 1) и структуры(таблица 2) Windows.
Элементы Windows-приложения
Построение приложения Windows включает выполнение следующих этапов:
1. Создание WinMain(...) и связанных с ней функций на языке C или C++.
2. Создание описаний меню и всех дополнительных ресурсов, помещение описаний в
файл описания ресурсов.
3. Создание уникальных курсоров, пиктограмм и битовых образов.
4. Создание диалоговых окон.
5. Создание файла проекта.
6. Компиляция и компоновка всего кода.
Простейшая программа. Создание и вывод Windows-окна на экран
Создадим пустой проект Windows- приложения с помощью мастера:
1. В меню Файл последовательно выберите команды Создать и Проект....
2. В узле Visual C++ области Типы проектов выберите Win32, а затем в области
Шаблоны выберите Проект Win32.
3. Введите имя проекта, например win32app. Можно принять место размещения по
умолчанию, ввести необходимое место размещения или перейти к каталогу, в
который требуется сохранить проект.
4. В окне Мастер приложений Win32 нажмите кнопку Далее.
5. В окне Мастер приложений Win32 в поле Тип приложения выберите пункт
Приложение Windows. В поле Дополнительные параметры выберите Пустой
проект. Остальные параметры оставьте без изменений. Чтобы создать проект,
нажмите кнопку Готово.
6. Добавьте в проект файл C++, в меню Проект выбрав команду Добавить новый
элемент.... В диалоговом окне Добавление нового элемента выберите Файл C++
(.cpp). Введите имя файла, например GT_HelloWorldWin32.cpp, и нажмите кнопку
Добавить.
Добавим следующий код:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
static TCHAR szWindowClass[]=_T("win32app");
static TCHAR szTitle[]=_T("Win32 Guided Tour Application");
HINSTANCE hInst;
//module:
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE
lpCmdLine, int nCmdShow)
{
hPrevInstance, LPSTR
WNDCLASSEX wcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=NULL;
wcex.lpszClassName=szWindowClass;
wcex.hIconSm=LoadIcon(wcex.hInstance,MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,_T("Call
to
RegisterClassEx
failed"),_T("Win32
Guided
Tour"),NULL);
return 1;
}
hInst=hInstance;
HWND
hWnd=CreateWindow(szWindowClass,szTitle,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_
USEDEFAULT,500,100,NULL,NULL,hInstance,NULL);
if (!hWnd)
{
MessageBox(NULL,_T("Call
to
CreateWindow
failed!"),_T("Win32
Guided
Tour"),NULL);
return 1;
}
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT message, WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[]=_T("Hello, World!");
switch (message)
{
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
TextOut(hdc,5,5,greeting,_tcslen(greeting));
EndPaint(hWnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd,message,wParam,lParam);
break;
}
return 0;
}
Скомпилируем и запустим программу. На экране появится Windows-окно.
Рис.1. Результат выполнения приложения.
Запуск приложения Win32
1. Как известно, любое приложение на языках C и C++ должно иметь функцию main.
Эта функция является начальной точкой для приложения. Подобным же образом
любое приложение Win32 должно иметь функцию WinMain. Синтаксис функции
WinMain выглядит следующим образом:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow);
Описание параметров и значений, возвращаемых этой функцией, см. в разделе
Функция WinMain.
2. Наряду с функцией WinMain, в каждом приложении Win32 также должна быть
определена еще одна функция, обычно называемая WndProc и представляющая
собой оконную процедуру. Синтаксис функции WndProc выглядит следующим
образом:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
Назначением этой функции является обработка сообщений, получаемых приложением
от операционной системы. В каком случае приложение получает сообщения от
операционной системы? Оно получает их постоянно! Например, представим, что было
создано диалоговое окно с кнопкой ОК. Когда пользователь нажимает кнопку,
операционная система посылает приложению сообщение, оповещающее о нажатии
кнопки. Функция WndProc отвечает за реагирование на это событие. В этом примере
соответствующей реакцией на это событие может быть закрытие диалогового окна.
Дополнительные сведения см. в разделе Процедуры окна.
Расширение функциональности WinMain
3. Для начала создайте внутри функции WinMain структуру класса окна типа
WNDCLASSEX. Эта структура содержит информацию об окне, такую как
используемые в приложении значки, цвет фона окна, отображаемое в заголовке
окна название, имя функции процедуры окна и т.д. Типичная структура
WNDCLASSEX выглядит следующим образом:
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style
= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance
= hInstance;
wcex.hIcon
= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor
= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm
=
LoadIcon(wcex.hInstance,
MAKEINTRESOURCE(IDI_APPLICATION));
Описание полей этой структуры см. в разделе WNDCLASSEX.
4. После того как класс окна будет создан, необходимо зарегистрировать его.
Воспользуйтесь функцией RegisterClassEx, которой следует передать структуру
класса окна в качестве аргумента:
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
5. После того как класс будет зарегистрирован, можно приступать к созданию окна.
Используйте функцию CreateWindow, как показано ниже:
static TCHAR szWindowClass[] = _T("win32app");
static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application dows not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
Эта функция
возвращает
объект
HWND,
являющийся
дескриптором
окна.
Дополнительные сведения см. в разделе Типы данных Windows.
6. После того как окно будет создано, его можно вывести на экран с помощью
следующего кода:
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
Это окно будет практически пустым, поскольку функция WndProc еще не реализована.
7. На последнем этапе в функции WinMain реализуется цикл обработки сообщений.
Назначением этого цикла является прослушивание сообщений, посылаемых
операционной системой. При получении приложением сообщения оно передается
функции WndProc на обработку. Цикл обработки сообщений выглядит следующим
образом:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
Дополнительные сведения о структурах и функциях, используемых в цикле обработки
сообщений, см. в разделах, посвященных MSG, GetMessage, TranslateMessage и
DispatchMessage.
8. Выполненные этапы типичны для создания большинства приложений Win32. На
данном этапе функция WinMain должна выглядеть примерно следующим образом:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style
= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance
= hInstance;
wcex.hIcon
= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor
= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm
=
LoadIcon(wcex.hInstance,
MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
hInst = hInstance; // Store instance handle in our global variable
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application dows not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
Расширение функциональности WndProc
9. Назначением функции WndProc является обработка сообщений, получаемых
приложением.
Обработка
таких
сообщений
обычно
реализуется
путем
использования функции Switch.
Для начала реализуем обработку сообщения WM_PAINT. Приложение получает это
сообщение, когда возникает необходимость в обновлении какой-либо области окна
приложения. При создании окна данное сообщение передается для указания на
необходимость обновления всего окна.
При обработке сообщения WM_PAINT сперва необходимо вызвать функцию
BeginPaint, а в завершение следует вызвать функцию EndPaint. Между вызовами этих
двух функций обрабатывается логика по отображению текста, кнопок и других
элементов управления в окне. Данное приложение отображает в окне строку "Hello,
World!". Для отображения текста следует использовать функцию TextOut, как показано
ниже:
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, World!");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, World!"
// in the top left corner.
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
// End application-specific layout section.
EndPaint(hWnd, &ps);
break;
}
10. Обычно приложение обрабатывает множество других сообщений, таких как
WM_CREATE и WM_DESTROY. Ниже приведен код простой, но полноценной
функции WndProc:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, World!");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, World!"
// in the top left corner.
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
// End application specific layout section.
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
Чтобы построить приложение, в меню Построение выберите команду Построить
решение. Если компиляция приложения была выполнена без ошибок, можно запустить
приложение с помощью клавиши F5. В верхнем левом углу экрана появится простое окно
с текстом "Hello, World!"(рис.1).
Пример_2: Вывод окна с графическими объектами.
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
static TCHAR szWindowClass[]=_T("win32app");
static TCHAR szTitle[]=_T("Win32 Guided Tour Application");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND hwnd,UINT message, WPARAM
lParam);
int
WINAPI
WinMain(HINSTANCE
lpCmdLine, int nCmdShow)
{
hInstance,HINSTANCE
wParam,
LPARAM
hPrevInstance,LPSTR
WNDCLASS wc;
wc.style=CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc=WndProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hInstance;
wc.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_APPLICATION));
wc.hCursor=LoadCursor(NULL,IDC_CROSS);
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName=NULL;
wc.lpszClassName=szWindowClass;
//Регистрируем класс окна
if (!RegisterClass(&wc))
{
MessageBox(NULL,_T("Call to RegisterClassEx faled!"),_T("Win32
Guided Tour"),NULL);
return 1;
}
hInst=hInstance;
HWND
hWnd=CreateWindow(szWindowClass,szTitle,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_
USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
if (!hWnd)
{MessageBox(NULL,_T("Call to RegisterClassEx faled!"),_T("Win32 Guided
Tour"),NULL);
return 1;}
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return(int)msg.wParam;
}
//Второй вариант
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[]=_T("Пример вывода текста в окно");
TCHAR greeting1[]=_T("Пример вывода линии в окно");
TCHAR greeting2[]=_T("Пример вывода эллипса в окно");
TCHAR greeting3[]=_T("Пример вывода прямоугольника в окно");
switch(message)
{
case WM_PAINT:
COLORREF oldColor,oldBkColor;
HBRUSH hNewbrush,hOldBrush;
HPEN hNewPen,hOldPen;
hdc=BeginPaint(hWnd,&ps);
if (!hdc)
{
MessageBox(NULL,_T("Контекст
устройства
не
получен"),_T("Ошибка
1"),MB_OK);
exit(1);
}
oldColor=SetTextColor(hdc,RGB(0,255,0));
if (oldColor==CLR_INVALID)
{
MessageBox(NULL,_T("Ошибка SetTextColor"),_T("Ошибка 2"),MB_OK);
exit(2);
}
oldBkColor=SetBkColor(hdc,RGB(0,0,0));
if (oldBkColor==CLR_INVALID)
{
MessageBox(NULL,_T("Ошибка SetBkColor"),_T("Ошибка 3"),MB_OK);
exit(3);
}
TextOut(hdc,150,0,greeting,27);
SetTextColor(hdc,oldColor);
SetBkColor(hdc,oldBkColor);
TextOut(hdc,50,30,greeting1,26);
MoveToEx(hdc,125,50,NULL);
LineTo(hdc,175,100);
TextOut(hdc,50,120,greeting2,28);
hNewbrush=CreateSolidBrush(RGB(255,0,0));
hOldBrush=(HBRUSH)(SelectObject(hdc,hNewbrush));
Ellipse(hdc,100,140,200,240);
if (!DeleteObject(hNewbrush))
{
MessageBox(NULL,_T("Неверное
использовние
DeleteObject"),_T("Ошибка
10"),MB_OK);
exit(10);
}
SelectObject(hdc,hOldBrush);
TextOut(hdc,50,250,greeting3,35);
hNewPen=CreatePen(PS_DOT,1,RGB(255,0,0));
hOldPen=(HPEN)(SelectObject(hdc,hNewPen));
Rectangle(hdc,100,270,200,370);
DeleteObject(hNewPen);
SelectObject(hdc,hOldPen);
EndPaint(hWnd,&ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd,message,wParam,lParam);
break;
}}
Методические указания
При выполнении задания к данной лабораторной работе необходимо
Написать программу, демонстрирующую работу создания окна согласно варианту
задания.
Варианты лабораторных заданий.
Вариант 1
Создайте простое оконное приложение, использующее Windows API. Запретите команду
Закрыть системного меню. Придумайте способ (способы) завершения работы
приложения.
Вариант 2
Создайте простое оконное приложение, использующее Windows API, с пиктограммой в
виде вопросительного знака.
Вариант 3
Создайте простое оконное приложение, использующее Windows API, с курсором в виде
«песочных часов».
Вариант 4
Создайте простое оконное приложение, использующее Windows API, с серым цветом
фона окна.
Вариант 5
Создайте простое оконное приложение, использующее Windows API, с заголовком,
содержащим ваши атрибуты (например – фамилия, должность).
Вариант 6
Создайте простое оконное приложение, использующее Windows API. Запретите
изменение размеров окна с помощью его рамки.
Вариант 7
Создайте простое оконное приложение, использующее Windows API. Окно должно иметь
горизонтальную полосу прокрутки.
Вариант 8
Создайте простое оконное приложение, использующее Windows API. Окно должно
первоначально отображаться в виде в максимально возможном размере.
Вариант 9
Создайте простое оконное приложение, использующее Windows API. Окно должно
первоначально отображаться в виде пиктограммы.
Вариант 10
Создайте простое оконное приложение, использующее Windows API. Кнопка Закрыть
(расположена в правой части строки заголовка окна) должна быть неактивной.
Придумайте способ (способы) завершения работы приложения.
Вариант 11
Создайте простое оконное приложение, использующее Windows API. Кнопка Свернуть
(расположена в правой части строки заголовка окна) должна быть неактивной.
Вариант 12
Создайте простое оконное приложение, использующее Windows API, без системного
меню. Придумайте способ(способы) завершения работы приложения.
Вариант 13
Создайте простое оконное приложение, использующее Windows API. В главном окне
предусмотрите вывод цветной «картинки» с поясняющей надписью. Картинка должна
содержать несколько замкнутых контуров (не эллипсы и не прямоугольники),
закрашенных различными цветами.
Вариант 14
Создайте простое оконное приложение, использующее Windows API, с заданными
размерами и местоположением на экране.
Вариант 15
Создайте простое оконное приложение, использующее Windows API. В главном окне
предусмотрите вывод закрашенного прямоугольника.
Вариант 16
Создайте простое оконное приложение, использующее Windows API.
В окне
предусмотрите вывод цветной картинки с поясняющей надписью. Картинка должна
содержать несколько замкнутых контуров (не эллипсы и не прямоугольники),
закрашенных различными цветами.
Контрольные вопросы:
1. Что представляет собой окно?
2. Перечислите и охарактеризуйте основные компоненты окна.
3. Что такое класс окна, зачем он нужен?
4. Перечислите и охарактеризуйте графические объекты, используемые в окнах.
5. Что такое событийно-управляемая ОС?
6. Общая характеристика формата сообщения, используемого в Windows?
7. Компоненты ядра Windows?
8. Элементы Windows-приложения?
9. Что собой представляет Windows API?
Лабораторная работа 4
Тема: Создание приложения Windows Forms.
Цель работы : изучение среды Visual C++ для работы с графическими интерфейсами.
Теоретические сведения.
Изучим создание приложений с так называемыми формами. В изучаемой среде такие
приложения называются Windows Forms Application. Окно такого приложения показано на
рисунке 1.
Рис.1 Вид главного окна для приложений типа Windows Forms Application
Создание проектов.
Чтобы приступить к разработке новой программы (т.е. приложения), надо выполнить
команду Файл | Создать | Проект. Откроется диалоговое окно для выбора типа
приложения, где нужно произвести пронумерованные действия (рис.2.)
После нажатия на кнопку ОК на рабочем столе появится объект, который называется
формой (рис.1).
Выберите CLR
Выбираем шаблон
Рис.2 Диалоговое окно для выбора типа приложения.
В результате действий по созданию приложения мы увидим на экране объект, называемый
формой, - это экземпляр класса Form. Одновременно с этими действиями сред IDE
автоматически создает файлы проекта и среди них – программный модуль-заготовку для
помещения в него программ-обработчиков событий компонентов, которые будут
размещены в форме. Чтобы увидеть этот модуль, надо открыть контекстное меню формы
и выполнить в нем команду Перейти к коду.
Форма – это главный объект при создании проекта в среде VC++. Это главный контейнер,
в котором размещаются компоненты самой среды. С помощью этих компонентов и
реализуется конкретный алгоритм определенной задачи.
Язык VC++ в момент создания проекта (приложения) формирует массу различных
файлов. Но не все файлы, которые образуются в среде разработки включаются в тот или
иной проект. Это зависит от типа проекта и от тех опций, которые вы выбираете, когда
пользуетесь Мастером создания проекта.
В таблице 1 приведены собственно проектные файлы. Следует отметить, что не все
проектные файлы отражены в Обозревателе решений (там отражен только самый
минимум). В опции Сервис | Параметры | Проекты и решения | Параметры проекта
VC++ можно посмотреть расширения файлов, предусмотренных для проектов и решений.
Если перевести проект в режим показать все файлы - меню Проект | Показать все
файлы, то файлы покажутся все равно не все, мы увидим список расширений файлов,
которые будут скрыты даже тогда, когда проект находится в режиме показать все файлы .
Таблица 1. Собственно проектные файлы.
Имя файла
Form.h
app.rc
app.ico
Описание
h-файл, содержащий описание формы и всех ее компонентов
Файл ресурсов проекта. Записанный в виде сценария, который в
зависимости от типа проекта содержит описание диалоговых окон,
панелей инструментов, пиктограмм, версии проекта и др.
Здесь хранится пиктограмма программы
resource.h
stdafx.h
AssemblyInfo.cpp
stdafx.cpp
Projname.cpp
Solname.sln
Projname.suo
Projname.vcproj
Projname.idl
Projname.ncb
Readme.txt
Это заголовочный файл содержит в себе определения ресурсов,
используемых в проекте, сгенерированных из файла app.rc.
Этот файл используется для построения предкомпиляционного
заголовочного файла и предкомпиляционных объектных файлов
Этот файл содержит информацию по сборке проекта (файлы, ресурсы,
типы и т.п.)
Здесь содержится информация для содержания предкомпиляционных
файлов
Содержит обычную команду int main(), с которой мы встречались при
изучении С++, оператор include, подключающий h-файл, содержащий
описание формы и всех ее компонентов (т.е. это программа проекта на
языке С++)
Этот файл относится к категории группы проектов, объединенных в
одно Решение. Он организует все элементы проекта в одно общее
Решение.
Этот файл опций Решения. Хранит все пользовательские режимы,
задаваемые при создании Решения.
Это главный файл проекта для VC++проектов, генерируемых с
использованием Мастера Приложений – программы, формирующей
приложения на основании диалога с пользователем, создающим
приложение. Она содержит информацию о версии среды разработки, о
платформе, на которой создается приложение, и о свойствах созданного
проекта
Содержит код описания интерфейса для управления библиотекой типов
(он используется для генерации такой библиотеки). Эта библиотека
выставляет интерфейс компонента другим клиентам.
Это некомпилируемый файл. Содержит информацию, генерируемую
специальной программой – синтаксическим анализатором, которая
используется классом View (просмотр информации). Если этот файл
случайно удален, то он автоматически генерируется.
В этом файле описываются некоторые файлы созданного проекта.
Помимо собственно проектных файлов среда разработки формирует и файлы
предварительной компиляции проекта stdax.h, stdafx.cpp.
Необходимо дать некоторые сведения и о ресурсных файлах.
Ресурсы – это интерфейсные элементы, которые обеспечивают пользователя
информацией (к ним относятся) графические битовые изображения, пиктограммы,
линейки инструментов, курсоры и др.). В таблице 2 перечислены такие файлы.
Таблица 2. Ресурсные файлы.
Имя файла
Описание
Projname.rc
Этот файл содержит
информацию, зависящую от типа проекта.
Например, это могут быть линейки инструментов, меню по умолчанию,
таблицы строк, диалоговые окна по умолчанию, файл пиктограмм,
информация о версиях проекта. Битовые изображения, HTML-файлы
В этом файле содержаться определения ресурсов, используемых в
Resource.h
проекте
Projname.rc2
Здесь содержаться дополнительные ресурсы, используемые в проекте
Projname.def
Здесь хранятся имя и описание компонента, размер занимаемой им
памяти во время исполнения проекта
Projname.ico
Файл пиктограмм для проекта или компонента
Графический файл, представляющий приложение или компонент на
Toolbar.bmp
линейке инструментов или в палитре компонентов
Окно сведений об объекте.
Любой объект, находящийся на рабочем столе, обладает какими-то свойствами.
Например, файл из Обозревателя Решений имеет такое свойство, как путь к папке, в
которой он расположен, компонент из палитры компонентов (например, кнопка)
характеризуется своим именем, видимостью в момент исполнения, координатами в форме
и т.д.
Все свойства активного объекта мгновенно отражаются в специальном окне (рис.3).
В окне имеется 5 вкладок:
1.
- упорядочивает содержимое окна по категориям информации;
2.
- упорядочивает содержимое окна по алфавиту;
3.
- показывает перечень свойств;
4.
- показывает перечень событий, связанных с объектом;
5.
- выводит на экран так называемые «страницы свойства».
Вкладка
- События.
Содержит список возможных событий, которые могут происходить с компонентом. Она
позволяет связывать каждое событие программой-обработчиком этого события: если
дважды щелкнуть мышью на окне с кнопкой рядом с именем события или дважды
щелкнуть на самом компоненте в форме.
Рис.3 Окно сведений об объекте
Вкладка
- Свойства страницы.
Это интерфейсный элемент (т.е. элемент, обеспечивающий общение между средой
разработки и пользователем), который позволяет задавать установки элементов проекта.
Когда мы дважды щелкаем на этой вкладке (если она доступна для данного объекта: для
некоторых объектов эта страница заблокирована), то открывается диалоговое окно, в
котором можно задавать определенные настройки.
Настройка опций редактора подопции Параметры.
Настройка опций редактора выполняется через диалоговое окно, которое открывается,
если выполнить команду Сервис | Параметры главного меню среды. В открывшемся
окне в левой части надо щелкнуть мышью на опции Текстовый редактор (рис.4).
В раскрывшемся списке выбираем язык С++, щелкаем мышью на опции Общие и справа
получаем три группы установок с переключателями. Рассмотрим некоторые из них:


Переносить по словам. Включенная опция позволяет «заворачивать» длинную
строку, не умещающуюся в поле редактора, на вторую строку. При этом можно
задать появление пиктограммы в конце заворачиваемой строки;
Номера строк. При включенной опции строки кода будут пронумерованы.
Рис.4 Редактирование опций редактора кода.
Изменение шрифта и цвета
Для изменения шрифта редактора следует выполнить команду главного меню Сервис |
Параметры и в открывшемся диалоговом окне выбрать папку Среда, а в не Шрифты и
цвета(рис.5).
Рис.5 Изменение шрифта редактора.
В открывшемся содержимом папки следует выбрать
соответствующий элемент редактирования, для которого
требуется изменить шрифт, и подобрать ему шрифт с
использованием
выпадающих
списков
Шрифт
(моноширинные шрифты имеют полужирное начертание)
и Размер. А цвет шрифта выбирается с использованием
выпадающих списков Основной цвет элемента и
Фоновый цвет элемента.
Компоненты среды программирования VC++
Рассмотрим основной компонент среды программирования – класс Form.
Этот класс определяет элемент будущего приложения, называемый формой. Это –
контейнер, в который помещаются остальные элементы приложения, определяющие
впоследствии всю функциональность данного приложения. В это среде существует
инструмент для работы с формой, называемый дизайнером форм.
Пустая форма, которая появляется на экране после загрузки среды VC++ или когда мы
создаем новое приложение. Фактически представляет собой окно дизайнера форм.
Компоненты выбираются из палитры компонентов. Расположенной на вкладке Вид |
Панель элементов(рис.6).
Рис.6 Панель элементов.
Добавление новых форм к проекту.
Алгоритмы решения некоторых задач требуют, чтобы компоненты, обеспечивающие
решение таких задач, размещались в разных формах и чтобы эти формы вызывались в
процессе выполнения проекта в определенном порядке. Например. Возьмем задачу
управления кадрами. Желательно, чтобы все справочные данные по кадрам были
размещены отдельно от аналитических форм – так удобнее поддержать справочную
информацию (этим вопросом должен заниматься отдельный работник, которому нечего
делать в разделе аналитических форм). Да и работнику, связанному с анализом кадров,
легче решать свои проблемы, не заботясь о поддержке в активном состоянии нормативносправочной информации.
Как добавить к проекту новую форму?
Для этого надо открыть контекстное меню проекта (в окне Обозреватель решений надо
щелкнуть на имени проекта) и выполнить в нем опцию Добавить | Создать элемент. В
открывшемся диалоговом окне (рис.7) выбрать позицию Windows Form (мы
рассматриваем сейчас именно этот тип приложений), задать имя новой формы и нажать
кнопку Добавить.
Рис.7 Добавление новой формы к проекту.
В результате мы увидим информацию о добавлении новой формы в окне Обозреватель
решений (рис.8)
Рис.8 Сведения о добавлении новой формы к проекту
Теперь надо выбрать, какую форму запускать первой.
Когда добавляете форму к проекту, она не станет по умолчанию сама выводиться в
момент исполнения приложения – ее надо вызвать.
Форма, которая появляется в проекте, когда мы выбираем режим Файл | Создать |
Проект, станет запускаться первой по умолчанию, т.е. всегда считается главной,
стартовой.
Если мы имеем несколько форм и нужно сделать одну из них (не обязательно первую
сделать стартовой), то такой возможности нет в версиях 2008 Express Edition и 2010 RC .
Поэтому приходится считать, что главной все-таки будет первая форма проекта, из
которой следует организовать вызов остальных форм.
Организация работы с множеством форм.
Итак, форма, с которой был связан проект при его создании, имеет статус главной. Это
означает, что она первой загружается и выполняется после того, как
проект
откомпилирован и запущен на выполнение. Если в проекте много форм, то из главной
формы можно организовать вызов на выполнение остальных форм (а можно из каждой
формы вызвать любую другую). Эта задача решается с помощью обработчиков кнопок
вызова конкретных форм.
При разработке проекта на экране всегда находится какая-то одна форма. Если нам
требуется поместить другую форму на экран из уже добавленных ранее в проект, то
следует просто переключится на другую вкладку, отражающую данную форму в режиме
дизайна. Например, если у нас две формы и вкладки, соответственно, помечены как
Form1.h [Конструктор] и Form2.h [Конструктор], то для вызова на экран 2-й формы
надо щелкнуть на вкладке Form2.h [Конструктор].
Вызов формы на выполнение.
Форма вызывается на выполнение в двух режимах: модальном и немодальном (обычном).
Вызов на выполнение осуществляется двумя разными командами. В модальном режиме –
методом формы ShowDialg() , в обычном – методом формы Show().
Свойства формы
Эти свойства могут встречаться у многих компонентов, поэтому впоследствии будем
говорить о них кратко. Все свойства объекта можно посмотреть в разделе Справка по
данному объекту(надо при выделенном объекте нажать клавишу <F1>). Перечень свойств
формы, отображенных в окне Свойства, приведен на рис.9.
Рассмотрим некоторые свойства формы.
 ApplicationSettings – установка приложения.
Эта возможность типа Windows Form позволяет легче создавать, хранить и
поддерживать приложение и различные преференции пользователя. С установками,
о которых речь пойдет чуть позже. Вы сможете не только хранить данные
приложения (такие как строки соединения с БД), но и специфические данные
пользователя, в частности его преференции (специфические установки
параметров). Вы сможете создавать новые установки, читать и писать их,
привязывать к свойствам ваших форм и определять их до загрузки и сохранения
приложения. Фактически аппарат установок приложения – это аппарат
параметризации этого приложения, что всегда возможность перестройки его без
перекомпиляции.
Рис.9 Перечень свойств формы, отображенных в окне Свойства.
Так что же такое эти установки? Ваши Windows Form – приложения почти всегда
содержит такие данные, которые не желательно хранить в самом приложения, т.к. их
изменение влечет за собой перекомпиляцию. Если ваше приложение эксплуатируется не
вами, а другим пользователем, то перекомпиляция из-за какой-то мелочи может повлечь
за собой его неработоспособность. Ведь пользователь не знает вашей программы и не
сможет ее правильно изменить (подстроить), даже если у него имеется код программы,
что весьма сомнительно (обычно разработчики поставляют пользователю только
исполняемые модули без кода).
Следовательно, такую настроечную информацию желательно хранить в отдельном файле,
который подключается к приложению. Если смотреть на этот процесс с точки зрения
работы приложения в рамках системы «клиент-сервер», то аппарат установок дает
возможность хранить на компьютере клиента как установки клиента, так и установки
приложения. В частности вы можете определить установки (т.е. значения заданных
величин, влияющих на ход выполнения программы-приложения) для данного свойства,
указывая его имя тип данного и контекст (это создается для приложения или для
пользователя). Такие установки не изменяются программой и читаются ею в память
автоматически в момент исполнения программы-приложения.
В большинстве случаев программные установки имеют статус «только для чтения» - «read
only» - это программная информация и нет необходимости ее изменять в самой
программе. И наоборот, пользовательские установки могут и читаться и быть безопасно
измененными в момент исполнения программы.
Установки приложения сохраняются в двух XML-файлах: в файле app.config (app – это
имя модуля exe-модуля приложения), который создается во время работы дизайнера
форм, т.е. во время проектирования приложения. Формирование этого файла происходит в
момент создания первой установки приложения. Другой файл – user.config (этот файл
формируется в момент исполнения приложения – когда пользователь изменяет значение
любой пользовательской установки).
Установки определяются дизайнером форм заданием свойства ApplicationSettings в окне
Свойства формы. Когда вы определяете установки, среда программирования
автоматически создает специальный управляемый пользователем класс-оболочку, в
котором каждая установка связывается со свойством класса.
Как осуществить установки с помощью дизайнера форм? В следующем порядке действий
вы выполняете конфигурацию установок и связей, используя редактор свойства для
Windows Form. Когда вы используете этот редактор, то среда программирования
генерирует класс- оболочку, происходящий от класса ApplicationSettingsBase, и
определяет все ваши установки в качестве свойств класса-оболочки. Чтобы создать новые
установки приложения, выберите форму или компонент, чьи свойства хотите связать с
новыми установками. Далее требуется:
1.
Добавить в проект файл app.config (Добавить | Создать элемент | Служебная
программа), а затем переименовать его в app.settings. Раскрыть свойство
ApplicationSettings (если слева от него стоит знак «+») и щелкнуть мышью на
кнопке с многоточием на подчиненном свойстве PropertyBindings . Откроется
диалоговое окно, показанное на рис.10
2.
В диалоговом окне надо открыть выпадающее меню для того свойства (кнопка с
галочкой справа), которое требуется связать с объектом (для нашего рисунка – это
форма). В открывшемся списке выполняем команду Создать. В результате
откроется окно Новый параметр приложения, в котором и следует задать
установки, т.е. значения указанных в нем элементов. Во-первых, надо задать имя
установки, ее значение по умолчанию, ее предназначение (для приложения или
пользователя). Если установка предназначена для приложения, то это свойство
станет глобальным для всех пользователей приложения и не сможет изменяться в
режиме исполнения. Если же контекст выбрать User, то свойство будет иметь
статус read/write (его можно не только читать, но и записывать, т.е. изменять).
Рис. 10. Диалоговое окно для задания установок приложения
3. Щелкнуть на кнопке ОК последовательно в обоих диалоговых окнах. Пример
задания установки для свойства FormBorderStyle (стиль окантовки формы) показан
на рис.11.
Рис.11. Пример задания установки для свойства FormBorderStyle
Символ :: - это так называемый оператор контекстного разрешения (мы должны сказать
компилятору, что будет использован глобальный идентификатор вместо локального,
предваряя такой идентификатор символом ::).
Примеры:

::identifier – это просто идентификатор;

class-name :: identifier – это идентификатор, относящийся к
классу;

namespace :: identifier – это идентификатор, относящийся к
пространству имен.
При выводе графика любой функции применяется метод DrawLine() класса
Graphics(). Но напрямую сформировать указатель на этот класс, чтобы
воспользоваться его членами (в частности методом DrawLine()), нельзя. Надо сначала
получить ссылку на этот графический объект через специальный метод формы, который
называется СreateGraphics().
Graphics ^im = this->CreatGraphics();
то получим желаемое (метод, по его определению, формирует ссылку на графический
объект).
Теперь через определенную нами ссылку типа Graphics можем добраться до членов
класса Graphics (в частности до необходимого нам метода DrawLine(), который
рисует прямую линию между двумя точками). Рисование происходит с помощью
специального механизма, находящегося в классе Pen (перо или ручка с пером). Чтобы
добраться до этого механизма, надо объявить ссылку на этот класс, а потом через нее
добраться до нужного нам класса.
Формирование ссылки на класс происходит не само по себе, а с помощью утилиты
gcnew, запускающей специальную программу-конструктор класса, который, в свою
очередь, создает в выделенной утилитой памяти экземпляр класса, чтобы с ним можно
было работать. Конструктор всегда имеет то же имя, что и класс. Для которого он
создается, только это обычная функция, выполняющая определенные действия по
инициализации членов-данных класса (т.е. придает им некоторые начальные значения).
Конструктор для класса Pen имеет один параметр (цвет), потому что перо должно
рисовать линии определенным цветом. Следовательно, прежде чем задавать работу
конструктору класса Pen, нам нужно как-то определиться с цветом, который потом
следует задать в качестве параметра этому конструктору. Цвета находятся в специальном
классе Color (цвет). Чтобы добраться до нужного цвета в этом классе, надо
сформировать ссылку на этот класс, а потом уже через нее достать нужный цвет. Отсюда
имеем:
Сolor ^col = gcnew Color();
Утилита gcnew запускает конструктор класса Color, формирует экземпляр класса в
памяти и выдает ссылку на этот экземпляр в переменную сol. Теперь любой цвет из
Color можно достать через ссылку так:
“col->”;
При этом откроется окно подсказчика, из которого остается только выбрать подходящий
цвет. Когда вы начнете вводить начальные буквы нужного вам объекта, среда сразу
установит подсветку на ближайший объект, имя которого начинается на вводимые вами
символы, что ускоряет процесс выбора нужной строки. После выбора строки нажмите
клавишу <Enter> и она попадет в ваш оператор. Если вы не нашли подходящую строку,
значит в объекте, на который вы сформировали ссылку, такого члена-данного нет.
После определения цвета можно выполнять конструктор пера:
Pen ^pen = gcnew Pen(col->Red);
Чтобы график выводился на поле формы, не занятое предыдущим графиком, следует
графический объект, которым мы пользуемся для рисования (он фактически задает
специальный холст для рисования, состоящий из точек – пиксел ), закрасить нейтральным
цветом, на фоне которого будет выводиться новый график.
Чтобы рисовать график, из непрерывной функции получают в цикле дискретные значения
ее точек и между двумя соседними точками проводят прямую линию. Естественно, чем
больше точек на данной поверхности, тем более точным будет график.
Пример рисования графика функции:
Код программы:
#pragma once
namespace график {
using
using
using
using
using
using
namespace
namespace
namespace
namespace
namespace
namespace
System;
System::ComponentModel;
System::Collections;
System::Windows::Forms;
System::Data;
System::Drawing;
/// <summary>
/// Сводка для Form1
///
/// Внимание! При изменении имени этого класса необходимо также изменить
///
свойство имени файла ресурсов ("Resource File Name") для
средства компиляции управляемого ресурса,
///
связанного со всеми файлами с расширением .resx, от которых
зависит данный класс. В противном случае,
///
конструкторы не смогут правильно работать с локализованными
///
ресурсами, сопоставленными данной форме.
/// </summary>
//Объявление своих функций
//sin(x)
double fs(double x)
{
return(Math::Floor(Math::Sin(x)));
}
//tan(x)
double ft(double x)
{
return(Math::Floor(Math::Tan(x)));
}
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: добавьте код конструктора
//
}
protected:
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Button^ button1;
protected:
private: System::Windows::Forms::Button^
private: System::Windows::Forms::Button^
button2;
button3;
private:
/// <summary>
/// Требуется переменная конструктора.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Обязательный метод для поддержки конструктора - не изменяйте
/// содержимое данного метода при помощи редактора кода.
/// </summary>
void InitializeComponent(void)
{
this->button1 = (gcnew System::Windows::Forms::Button());
this->button2 = (gcnew System::Windows::Forms::Button());
this->button3 = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// button1
//
this->button1->Location = System::Drawing::Point(12, 208);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(86, 36);
this->button1->TabIndex = 0;
this->button1->Text = L"Рисование синусоиды";
this->button1->UseVisualStyleBackColor = true;
this->button1->Click += gcnew System::EventHandler(this,
&Form1::button1_Click);
//
// button2
//
this->button2->Location = System::Drawing::Point(154, 208);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(94, 36);
this->button2->TabIndex = 1;
this->button2->Text = L"Рисование тангенусоиды";
this->button2->UseVisualStyleBackColor = true;
this->button2->Click += gcnew System::EventHandler(this,
&Form1::button2_Click);
//
// button3
//
this->button3->Location = System::Drawing::Point(318, 208);
this->button3->Name = L"button3";
this->button3->Size = System::Drawing::Size(85, 36);
this->button3->TabIndex = 2;
this->button3->Text = L"Выход";
this->button3->UseVisualStyleBackColor = true;
this->button3->Click += gcnew System::EventHandler(this,
&Form1::button3_Click);
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode
=
System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(434, 256);
this->Controls->Add(this->button3);
this->Controls->Add(this->button2);
this->Controls->Add(this->button1);
this->Name = L"Form1";
this->Text = L"Рисование графика в форме";
this->ResumeLayout(false);
}
#pragma endregion
private:
System::Void
button1_Click(System::Object^
sender,
System::EventArgs^ e)
{
Color ^col=gcnew Color();
Pen ^pen=gcnew Pen (col->Red);
//чтобы создать графический объект, надо получить ссылку на него,
//выполнив метод CreateGraphics(); компонента (формы)
Graphics ^im=this->CreateGraphics();
//рисует линию между 2-мя точками
//
im->DrawLine(pen,20,10,300,100);
//вывод графика функции с использованием DrawLine
im->Clear(col->White);
/*
закрасить
предыдущее
изображение
белым
цветом*/
float x1,y1,x2,y2; //текущие координаты в пикселах в форме
x1=0;y1=0; //начальные коорд. графика функции f(x)
// вычисление функции y=f(x) в точках x1,x2...
x2=x1;
while(x2<this->Width && y2<this->Height)
{
x2+=5; //следующая точка в пикселах по оси Х
y2=fs(x2)*100;
if (y2<0) y2*=-1;// чтобы выводить отрицательные значения
im->DrawLine(pen,x1,y1,x2,y2);
//точка 2 должна стать точкой 1,
//а точка 2 должна стать следующая текущая точка
x1=x2; y1=y2;
continue;
}
}
private:
System::Void
System::EventArgs^ e) {
button2_Click(System::Object^
Color ^col=gcnew Color();
Pen ^pen=gcnew Pen (col->Red);
Graphics ^im=this->CreateGraphics();
im->Clear(col->White);
float x1,y1,x2,y2;
x1=0; y1=0;
x2=x1;
while(x2<this->Width && y2<this->Height)
{
x2+=10;
y2=ft(x2)*50;
if (y2<0)y2+=-1;
im->DrawLine(pen,x1,y1,x2,y2);
x1=x2;y1=y2;
continue;
}
}
private:
System::Void
button3_Click(System::Object^
System::EventArgs^ e) {
this->Close();//завершение приложения
}
};
}
sender,
sender,
Результат выполнения:
Синусоида
Тангенусоида
Методические указания
При выполнении задания к данной лабораторной работе необходимо
написать программу, демонстрирующую работу согласно варианту задания.
Форма должна содержать главное меню, область вывода графика функции. Главное меню
обязательно содержит:
 пункт считывания значений переменных из файла;
 пункт сохранения результатов вычислений значений функции в файл;
 пункт вывода графика функции согласно варианту;
 различную информацию по вашему выбору (о программе, справка и т.д.).
Варианты лабораторных заданий.
Варианты заданий:
 B 2 ).
2
1.
Y=(arccos(A/B-B)-B/2*log( A
2.
Y  (( A  B) / (C  D ))
1.
Y  lg( B  tan( A )) .
2.
Y  (sin(C )) 3 * (cos( A )) 2 / (5 * sin(B) D ) .
3.
Y  2 * A * arcsin(314
. / B) .
4.
Y  2 * B * ln( A  B) / D 2 .
5.
Y  2 * ( A D  4 * C 2 / 3) .
6.
Y  0.5 * lg((1  sin(B)) / (1  sin( A ))) * (C  D ) .
7.
Y  1 / A 2 * (B / 10) 3 * (C  D ) 2 .
8.
Y  (( A / B  1) / (C / D  1)) 2 .
9.
Y  ( A  B) / (C  D / ( A  C )) .
10.
Y  sin( A  B  C  D ) 2  tan( A  C) .
11.
Y 
12.
Y  ( A 2  B 2  C 2 ) / ln( A * B * C ) .
13.
Y  A * D 3 / 3  B * C2 / 2.
14.
Y  ( A  B 2 ) /(C  D /( A3  C )) .
15.
Y  2 * ( A 2  B * C 2 / 3) .
16.
Y  2 * C * cos(3.14 / B) .
17.
Y  (arcsin( C )) 3 * (cos( A)) /(5 * sin( B) D ) .
18.
Y  2 * B * sin( A  B) / D 2 .
2
 B2 .
(A  B  C) 2  (A  B  C) 2 .
Контрольные вопросы:
1. Создание приложения Windows Forms Application.
2. Что такое форма?
3. Назначение основных файлов проекта.
4. Что такое ресурсы? Назначение файлов ресурсов.
5. Назначение вкладок: события, свойства страницы.
6. Что определяет основной компонент среды программирования – класс Form?
7. Панели инструментов. Их назначение.
Приложение
Свойства

AccessibleDescription – в этом свойстве отражается (или задается) текст описания
компонента для приложений, имеющих к нему доступ. Служит для доступа
клиентских приложений. Это свойство необходимо для случаев, когда описание
объекта неочевидно (кнопка с надписью ОК не нуждается в дополнительной
информации, но кнопка, на которой изображен, например, рисунок, требует
пояснений). Свойства AccessibleName и AccessibleRole для такой кнопки опишут
ее назначение, а рассматриваемое свойство AccessibleDescription выразит саму
идею этой кнопки. При этом AccessibleName задает имя компонента для
приложений, имеющих к нему доступ, а AccessibleRole
(выбирается из
выпадающего списка) содержит тип элемента пользовательского интерфейса
(ComboBox, DropList и т.д.). Если конкретно это свойство не может быть
определенно, то оно устанавливается назначение Default.

AllowDrop – свойство, определяющее возможность вывода у себя данных, когда
пользователь перемещает их над этим компонентом. Например, если компонент А
имеет такую возможность, то когда вы начнете перемещать мышью некоторое
изображение над ним, это изображение выведется на этом компоненте, когда будет
отпущена кнопка мыши (изображение «капнет» на поверхность компонента,
например, формы).

AutoScaleMode
–
это
свойство
задает
так
называемое
автоматическое
масштабирование. Автоматическое масштабирование дает возможность форме и
расположенным в ней компонентам, сконструированным на одном компьютере с
некоторым разрешением вывода (т.е. с фиксированным значением числа точек
изображения, которое станет выводиться на единицу поверхности вывода) или с
определенным шрифтом, выводиться, соответственно, на другом компьютере с
другим разрешением или шрифтом. Например, если выбрать значение Font(шрифт),
то автоматическое изменение шрифта будет полезным тогда, когда вы хотите,
чтобы форма или компонент растягивались или сокращались в соответствии с
размерами шрифта в ОС и использовались в случаях, когда их абсолютные
размеры не играют роли. Если выбрано значение DPI, то эта величина полезна, если
вы хотите изменять размеры формы или компоненты относительно экрана.
Например, вы выводите на экран диаграмму или другую графику и хотите, чтобы
это изображение всегда занимало определенный процент экрана. Если выбрать
значение свойства, равное Inherit, то другой компьютер станет наследовать шрифт
и разрешение базового компьютера.

AutoScroll – это свойство задает возможность автоскроллинга компонента, т.е.
появление полос прокрутки, если из-за изменения его размера появляются такие
компоненты, которые полностью не видны на данном компоненте.

AutoScrollMargin – свойство задает возможность автоскроллинга компонента, но с
учетом отступов по ширине и высоте от внутреннего компонента, вызывающего
скроллинг.

AutoScrollMinSize – свойство задает минимальный размер (в пикселах) ширины и
высоты полос прокрутки.

AutoSizeMode – свойство задает способ автоматического изменения формой своих
размеров. Значение выбирается из выпадающего списка.

BackColor – свойство дает возможность выбора из выпадающего списка цвета
фона в компонента.

BackgroundImageLayout – задает тип размещения фонового изображения в
компоненте: подгоняется под размер окна компонента, разрешает zoom-действие и
т.д.

BackgroundImage – дает возможность выбора изображения, которое станет
фоновым в компоненте.

CancelButton – это свойство позволяет создавать имитацию нажатия кнопки с
помощью нажатия клавиши <Esc> в момент работы приложения. Свойство удобно
использовать для обеспечения быстроты работы с приложением (просто клавишу
удобнее и быстрее нажимать, чем разыскивать кнопку в окне и щелкать на ней
мышью). При нажатии клавиши <Esc> приложение выполняет такое же действие,
как будто вы щелкнули на кнопке мышью. Свойство не станет работать. Если
другой компонент в форме работает с клавишей <Esc>.

CausesValidation
–
включает/выключает
необходимость
проверки
на
достоверность компонента во время получения им фокуса ввода (т.е. когда
компонент становится активным). На самом деле это свойство подавляет или не
подавляет возникновение события Validating. Если это событие не подавлено, то в
его обработчике можно проверить на достоверность некоторые данные, когда
компонент, содержащий свойство CausesValidation и событие Validating получает
фокус ввода. Например, в компоненте находится адрес электронной почты. Когда
компонент становится активным, можно проверить, содержит ли адрес
электронной почты символ @, обязательный для такого адреса.

ContextMenuStrip – через это свойство к компоненту подключается его
контекстное меню. Меню должно быть определено в форме и тогда оно станет
«видимо» в этом свойстве. Например, можно задать такое меню для компонента,
через который вводится текст, с тем, чтобы иметь возможность в момент ввода
изменять шрифт, искать фрагменты текста или иметь возможность копирования
текста в буфер системы, вставки его оттуда в необходимое место другого текста и
т.д.

ControlBox – свойство предоставляет возможность вывода в различном виде
заголовочной полосы формы.

Cursor – задает путем выбора из выпадающего списка форму курсора мыши, когда
он появляется над формой.

DoubleBuffered – свойство задает возможность снижения мерцания изображения
компонента при его перерисовки за счет использования дополнительного буфера
памяти.

Enabled – свойство задает право доступа к компоненту: значение true означает,
что доступ разрешен, false – запрещен. В случае с формой значение свойства,
равное false, приведет к блокировке формы: после компиляции ничто в ней не
будет реагировать на мышь, даже закрыть форму будет невозможно.


ForeColor – это свойство задает цвет переднего плана компонента.
FormBorderStyle – задает стиль окантовки формы, который выбирается из
выпадающего списка. По умолчанию принято значение Sizable (форма может
изменять свои размеры в режиме исполнения). Другие значения этого свойства не
допускают такой «вольности».

HelpButton – задает возможность вывода кнопки помощи
в заголовочном
компонента. Эта кнопка появляется (рис.2) в заголовке формы слева от кнопки
(закрыть форму) и может служить средством вывода сообщения. Имеющего
характер помощи (если конечно сделать обработку этой кнопки). Обработка
кнопки состоит в создании обработчика HelpRequested формы. Следует помнить,
что кнопка помощи появится в заголовке формы при условии, что кнопки (это
свойства формы) MaximizeBox
и MinimizeBox будут отключены(т.е. в
заголовочной полосе формы не будет кнопок свертывания и развертывания окна
формы). Кроме того, после создания обработчика кнопка реагирует только на
нажатие клавиши <F1>, т.е. обычной клавиши помощи. Код обработчика события
HelpRequested приведен ниже:
Листинг рис.3.:
private:
System::Void
Form1_HelpRequested(System::Object^
sender, System::Windows::Forms::HelpEventArgs^ hlpevent)
{
MessageBox::Show("Проверка действия кнопки Help", "Задание
кнопки
помощи
в
заголовке
формы",
MessageBoxButtons::OK,
MessageBoxIcon::Asterisk); }
рис.2
Рис.3
 Icon – дает возможность подключения к форме пиктограммы: если нажать кнопку с
многоточием в поле этого свойства, то откроется диалоговое окно для выбора
пиктограммы (файла с расширением ico). Выбранная пиктограмма попадает в
заголовок формы.
 ImeMode -
подключает к компоненту (посредством выбора из выпадающего
списка) редактор с различными режимами обработки входных данных Input Method
Editor (IME) (это специальная программа, которая дает возможность пользователям
вводить различные нестандартные символы, например, японские, с помощью
стандартной клавиатуры).
 IsMdiContainer – свойство, показывающее, является ли форма контейнером для
многодокументного интерфейса (т.е. является ли она одной из форм так
называемого MDI-приложения).
 KeyPreview – пояснение этого свойства связано с понятием “событие формы”. С
большинством компонентов связаны ситуации, названные “событиями”, которые
происходят в момент воздействия на компонент чего-либо. Например, когда форма
начинает изменять свои размеры, происходит событие Resize, когда форма
начинает на экране прорисовываться, наступает событие Paint, когда над формой
появляется курсор мыши, возникает событие MouseMove и т.д.
 Language – позволяет выбрать из выпадающего списка язык, на котором
предполагается работать с формой.
 Localizable – это свойство связано с настройкой приложения на различные
«культуры», т.е. на специфику данных отдельных стран.
 Locked – включение блокировки компонента, в результате чего компонент теряет
свойство переместимости или изменения размеров. При этом в левом верхнем углу
компонента появляется пиктограмма замка.
 MainMenuStrip – через это свойство к компоненту подключается главное меню: его
компонент с именем menuStrip надо поместить в форму и он станет “виден в
свойстве”.
 MaximumSize – максимальный размер формы. Если задано 0;0, то форма
безразмерна.
 Opacity – задает уровень затемнения (прозрачности) формы. Значение задается в
процентах. Чем ниже процент, тем более прозрачна форма в режиме исполнения.
 Padding – задает отступы внутри компонента. Чтобы лучше понять смысл этого
свойства, разберем одновременно и свойство Margin (оно определяет пространство
вне компонента, которое “держит” другие компоненты на заданной дистанции от
границ данного компонента). Свойство Padding определяет пространство внутри
компонента, которое “держит” на заданной дистанции от границ компонента
 RightToLeft – это свойство введено с учетом особенностей письменности некоторых
народов, у которых оно идет справа налево (например, у арабов или евреев). Если
значение установлено в Yes, то компоненты, содержащие текст, станут выводить их
справа налево.
 Size – задает размеры компонента. Попробуйте растянуть форму и посмотрите, как
изменяется значения этого свойства.
 SizeGripStyle – это свойство позволяет задать вывод/невывод калибровочной
полоски (захватки) в правом нижнем углу формы. Avto – захватка отсутствует, Hide
– захватки не видно, Show – захватка появилась.
 StartPosition – свойство задает стартовую позицию формы в режиме исполнения
приложения. Значения выбирается из выпадающего меню. Если, например, задать
значение CenterScreen, то форма начнет выводится по центру экрана.
 Tag – в этом свойстве можно задавать некоторые данные, чтобы потом ими
пользоваться при решении тех или иных задач. Это нечто вроде буферной памяти,
связанной с компонентом.
 Text – в этом свойстве задают название компонента. Например, для кнопки можно
написать: “Завершение работы приложения”.
 TopMost – это свойство определяет, будет ли данная форма всегда помещаться над
другой.
 TransparencyKey – свойство задает цвет, которым будут высвечиваться прозрачные
области формы.
 UseWaitCursor – свойство задает, будет ли использоваться курсор в виде песочных
часов (курсор ожидания) для данного компонента и всех его потомков или нет.
 WindowState – свойство задает состояние окна формы. Перед тем как форма
выведется, это свойство всегда сохраняет значение Normal, несмотря на
первоначальное значение этого свойства. Это состояние отражается в свойствах
Height, Left, Top, Width. Если форма “прячется” после того как она была показана,
то эти свойства отражают предыдущее состояние до тех пор, пока форма не
покажется, несмотря на изменения, сделанные в свойстве WindowState (изменения
свойства можно делать и в режиме исполнения).
События формы
 Activated – возникает, когда форма активизирована.
 Click – возникает при щелчке мышью в форме.
 ControlAdded – возникает, когда в форму добавлен новый компонент.
 ControlRemoved – возникает, когда компонент удален из формы.
 CursorChanged – возникает после двойного щелчка в форме.
 FormClosed – возникает после закрытия формы.
 FormClosing – возникает перед закрытием формы.
 HelpButtonClicked – возникает после щелчка на кнопке HelpButton.
 HelpReguested – возникает при нажатии клавиши <F1>.
 Load – возникает перед первым выводом формы.
 Paint – возникает, когда форма перерисована.
 Scroll – возникает, когда в форме начинается прокрутка.
 Shown – возникает, когда форма впервые выведена.
Некоторые методы формы
Форма имеет большое количество методов, которые можно посмотреть, открыв Help и
набрав в поле поиска появившегося окна Form members. Рассмотрим только некоторые из
методов формы.
 Close () – закрывает форму. Если закрывается главная форма, приложение
закрывается. Ресурсы, занятые формой, освобождаются.

Hide () – форма становится невидимой.

Show () – выводит форму на экран.

ShowDialog () – показывает форму в модальном режиме. Если форма показана в
модальном режиме, то приложение не может выполняться, пока форма не будет
закрыта. Чтобы закрыть форму, открытую в модальном режиме, надо назначить
свойству DialogResult кнопку, которая должна закрыть форму (например, ОК), и
проверить это свойство на совпадение его значения с соответствующим значениям
такого же свойства кнопки. Дело в том, что когда метод ShowDialog выполнится, то он
возвратит именно это заданное значение свойства в свойство формы с тем же
наименованием DialogResult. Это и станет сигналом того, что форма была открыта в
модальном режиме и ее можно закрыть. Как вызывать из главной формы другие и как
возвращаться в главную видно из листинга, который показывает работу приложения с
3-мя формами: Form1, Form2, Form3. Из главной (стартовой) Form1 вызываются
остальные, причем Form2 – в модальном режиме, а Form3 – в обычном (немодальном).
Если Form3 можно закрывать, нажимая на кнопку Вызов Form1 или на кнопку
закрытия окна, и при этом все проходит успешно, то для Form2 это не имеет места:
пока вы “правильно” не закроете эту форму, нажав на кнопку Вызов Form1, форма
закроется. Отметим: чтобы формы были видны одна из другой, надо в h-файл для
главной формы перед командой using namespace поместить операторы:
#include " Form2.h"
#include " Form3.h"
 Dispose () – форма разрушается и память, занятая ею, освобождается.

Focus () – делает форму активной: свойства Visible и Enabled принимают
значение true (форма становится видимой и доступной).
Листинг_ показывает работу приложения с 3-мя формами:
Файл Form1.h
private: System::Void button1_Click(System::Object^ sender,
System::EventArgs^ e)
{ //открытие Form2
System::Windows::Forms::DialogResult dr;
Form2 ^newDlg = gcnew Form2();
m:dr= newDlg->ShowDialog();
/*Вызывается Form2 в модальном режиме. В dr запоминается
значение DialogResult. Когда Form2 закроется, то значение ее
свойства DialogResult будет сравниваться с dr(там перед
закрытием формы мы внесем значение ОК в DialogResult) */
if (dr==System::Windows::Forms:: DialogResult::OK)
return;
else
{MessageBox::Show(“Ошибка закрытия Form2 ”);
goto m;
} }
private: System::Void button2_Click(System::Object^ sender,
System::EventArgs^ e)
{ //Вызов Form3
Form3 ^f3 = gcnew Form3();
f3->Show();
}
private: System::Void button3_Click(System::Object^ sender,
System::EventArgs^ e)
{
this->Close();
}
Файл Form2.h
private: System::Void button1_Click(System::Object^ sender,
System::EventArgs^ e)
{
this->
DialogResult=
System::Windows::Forms::
DialogResult::OK;
this->Close();
}
Файл Form3.h
private: System::Void button1_Click(System::Object^ sender,
System::EventArgs^ e)
{
this->Close();
}
Лабораторная работа 5
Тема: Создание интерфейса между пользователем и приложением
Цель работы : рассмотреть некоторые компоненты, с помощью которых разработчик
приложения может создать удобный интерфейс, позволяющий пользователю ПО легко
общаться и управлять последним.
Теоретические сведения.
Каждый компонент характеризуется тремя наборами данных, определяющими его
функциональность: свойства, события и методы. Мы рассмотрим только компоненты
первой необходимости, т.к. с течением времени разработчики среды пополняют ее все
большим количеством компонентов, на описание которых потребуется не одна книга.
Владея принципами работы с основными компонентами, пользователь среды VC++ может
самостоятельно осваивать новые, пользуясь справочной системой (Help).
В работе с компонентами используется механизм классов и пространств имен,
определенный в библиотеке классов .NET Framework, которая включает в себя классы,
интерфейсы, различные типы данных, обеспечивающие доступ к функциональным
возможностями среды разработки. С целью достижения совместимости между
различными языками в библиотеке предусмотрен инструмент CLS (Common Language
Specification). В библиотеке .NET Framework определены такие элементы:

Основные типы данных и аппарат исключений;

Структуры данных;

Элементы, обеспечивающие ввод/вывод данных;

Элементы, предоставляющие информацию о типах данных;

Элементы, обеспечивающие безопасность данных;

Элементы, обеспечивающие доступ к данным;

Богатый графический пользовательский интерфейс.
В библиотеке .NET Framework имеется достаточный набор как абстрактных (на их основе
создаются конкретные классы), так и конкретных классов. Родственные типы в этой
библиотеке объединены в пространстве имен, чтобы легче было с ними работать. Первая
часть полного имени – это имя пространства имен. Последняя часть имени – это тип
имени. Например, System.Collection.ArrayList представляет тип ArrayList, который
принадлежит пространству System.Collection. Типы данных из этого пространства
используются для работы с наборами объектов.
Пространство имен System.
Это пространство является базовым для фундаментальных типов данных в .NET
Framework. Оно включает в себя классы, применяемые в базовых типах данных, которые
используются всеми приложениями: Object (корневой класс в наследственной иерархии
классов), Byte, Char, Array, Int32, String и т.д. Большинство из этих типов соответствуют
первичным типам данных, используемым в языке программирования.
Таблица 1. Типы данных для Си++
Категория
Имя класса
Описание данного
данного
Integer
Byte
8-битовое беззнаковое
SByte
8-битовое целое со знаком
Int16
16-битовое целое со знаком
Int32
32-битовое целое со знаком
Int64
64-битовое целое со знаком
UInt16
16-битовое целое без знака
UInt32
32-битовое целое без знака
UInt64
64-битовое целое без знака
Float
Single
С обычной (32 бита) точностью число с
плавающей точкой
Double
С двойной (64 бита) точностью число с плавающей
точкой
Logical
Boolean
Логическое (булево) число (true или false)
Другие
Char
Unicode (16-битовый) символ
типы
Decimal
Десятичное (128 бит) значение
IntPtr
Целое со знаком, значение которого зависит от
соответствующей платформы: 32-битовое значение
на 32-битовой платформе и 64-битовое на 64битовой платформе
UInPtr
Целое без знака, значение которого зависит от
соответствующей платформы: 32-битовое значение
на 32-битовой платформе и 64-битовое на 64-
битовой платформе
Object
Корневой класс для иерархии классов
String
Строка Unicode символов постоянной длины
Компонент WebBrowser.
Компонент находится в списке Standard палитры компонентов Common Controls.
Этот компонент позволяет выводить Web-страницы прямо в вашем приложении.
Его можно использовать вместо Internet Explorer.
Например, можно использовать опцию Navigated, чтобы пользоваться списком
адресов, можно использовать опции GoBack (дает возможность перейти к предыдущей
Web-странице), GoForward (дает возможность перейти к последующей Web-странице),
Stop (приостанавливает текущую навигацию и связанные с ней звуки и анимацию) и
Refresh (перезагружает текущую Web-страницу) для создания навигационных кнопок на
линейке инструментов. Можно обработать событие Navigated для обновления линейки
адресов значением свойства Url (здесь задается или сюда записывается интернет-адрес
текущей Web-страницы), можно обработать заголовочную линейку значением свойства
DocumentTitle (дает заголовок текущей Web-страницы).
Классы
Рис.1. Пример справочника в режиме проектирования.
Если вы хотите сгенерировать свою собственную страницу внутри приложения, то
должны установить свойство DocumentText (через него можно ввести или прочитать
HTML – текст текущей Web-страницы).
Обработчики событий приложения приведены в листинге:
private:
System::Void
listView1_ItemActivate(System::Object^
sender,
System::EventArgs^ e)
{
ListView::SelectedListViewItemCollection^
breakfast=this->listView1>SelectedItems;
System::Collections::IEnumerator^ myEnum=breakfast->GetEnumerator();
while (myEnum->MoveNext())
/*надо запустить перечисление, т.к. в выборке м.б. много элементов, хотя у
нас всегда один */
{
ListViewItem ^it=safe_cast<ListViewItem^>(myEnum->Current);
/*здесь работает функция приведения одного типа данных к другому*/
String ^s;
s=it->Text;
this->webBrowser1->Navigate(s);
}
}
private:
System::Void
System::EventArgs^ e)
{
this->Close();
}
button5_Click(System::Object^
sender,
private:
System::Void
textBox1_KeyDown(System::Object^
sender,
System::Windows::Forms::KeyEventArgs^ e)
{
//обработка вызова
if(e->KeyCode==Keys::Enter)//завершение ввода по нажатию клавиши <Enter>
{
//засылка URL в свойство
this->webBrowser1->Navigate(this->textBox1->Text);
}
}
private:
System::Void
button4_Click(System::Object^
System::EventArgs^ e)
{
//refresh()
this->webBrowser1->Refresh();
}
sender,
private:
System::Void
button1_Click(System::Object^
System::EventArgs^ e)
{
//GoBack
this->webBrowser1->GoBack();
}
sender,
private:
System::Void
button2_Click(System::Object^
System::EventArgs^ e)
{
//GoForward
this->webBrowser1->GoForward();
}
sender,
private:
System::Void
button3_Click(System::Object^
System::EventArgs^ e)
{
//Stop
this->webBrowser1->Stop();
}
sender,
Рис.2. Запуск приложения.
Методические указания
При выполнении задания к данной лабораторной работе необходимо
Написать программу, демонстрирующую работу своего справочника интернет – адресов.
Related documents
Download