Типы и классы. Переменные и объекты
Программный проект SimpleVariables
Продолжу приводить примеры и сейчас подробнее остановлюсь на том, как строилось Решение (Solution) с именем Ch2, в котором размещены проекты этой лекции. Наряду с консольным проектом ConsoleNullable, примеры из которого приводились в предыдущем разделе, создадим Windows-проект с именем SimpleVariables. В этом проекте почти не будет никаких вычислений. Его главная задача - продемонстрировать различные способы объявления простых переменных встроенных базисных типов, простейшие присваивания и вывод значений переменных.
Побочная цель состоит в том, чтобы показать работу проекта, включающего несколько форм - интерфейсных классов. Проект продемонстрирует часто встречающуюся на практике ситуацию, когда в нем есть главная кнопочная форма с множеством командных кнопок, обработчики событий которых открывают формы, решающие специальные задачи.
Поскольку в первой лекции подробно рассказывалось о том, как создаются Windows-проекты и первые шаги работы с ними, останавливаться на этом уже не буду. На рис. 2.3 показана главная форма на начальном этапе проектирования.
Что же было сделано при проектировании главной формы? Прежде всего, она была переименована и получила содержательное имя. Переименован был и файл, содержащий описание интерфейсного класса, задающего форму. На форме размещена поясняющая надпись "Главная форма" и три командные кнопки.
Для задания надписей, поясняющих назначение формы, можно использовать элемент управления Label или текстовое окно - TextBox. В нашем примере использовалась метка.
Главная кнопочная форма
Проектируемая главная форма является примером главной кнопочной формы. В каких ситуациях имеет смысл проектировать главную форму как главную кнопочную форму? Так поступают достаточно часто. Представьте себе, что создаваемый проект предоставляет конечному пользователю несколько различных сервисов, и пользователь, начиная работу с проектом, выбирает нужный ему сервис. Главная форма может иметь меню, команды которого и позволяют пользователю выбирать нужный ему сервис. Если каждый сервис достаточно сложен и требует собственного интерфейса, то в таких ситуациях вместо стандартного меню удобнее использовать главную кнопочную форму. Роль команд меню в ней играют расположенные в форме командные кнопки. Выбор командной кнопки на форме соответствует выбору команды меню.
Подведем итоги. Если в проекте предполагается n различных сервисов, каждый из которых требует собственного интерфейса, то в проект наряду с главной формой, создаваемой по умолчанию в момент создания проекта, добавляются n интерфейсных классов - наследников класса Form, каждый из которых имеет собственную форму. Каждая такая форма заселяется элементами управления, задавая интерфейс соответствующего сервиса. На главной форме располагаются n командных кнопок, а в код интерфейсного класса, задающего главную форму, добавляются n полей, каждое из которых содержит объявление объекта соответствующего интерфейсного класса. Когда пользователь выбирает в главной форме командную кнопку, то обработчик события Click этой кнопки вызывает конструктор интерфейсного класса и создает реальный объект этого интерфейсного класса и реальную форму, связанную с объектом. Затем в обработчике вызывается метод Show этого объекта, соответствующая форма открывается, показывается на экране дисплея, и пользователь начинает работать с интерфейсом формы. Такая схема работы встречается на практике достаточно часто, так что проекты с главной кнопочной формой будут появляться неоднократно.
Продемонстрирую различные аспекты применения скалярных типов и объявления переменных. В проекте роль сервисов, предоставляемых пользователю, будут играть три различных примера - три теста. Каждый тест имеет свою цель и свой интерфейс, позволяющий конечному пользователю проводить исследования возможностей и особенностей объявления скалярных переменных. Для каждого теста будет создан свой интерфейсный класс и спроектирована форма, связанная с этим классом. Каждая командная кнопка главной формы будет запускать свой тест. Обработчик события Click каждой из командных кнопок будет открывать форму, спроектированную для работы с выбранным тестом нашего проекта.
Тест "Types" - ввод и вывод переменных различных типов
Какова идея этого теста? Давайте дадим конечному пользователю возможность в текстовых окнах формы задать имя скалярного типа и значение, соответствующее этому типу. После этого пользователь может нажать командную кнопку "Ввод", спроектированную в интерфейсе формы. Обработчик события Click командной кнопки "Ввод" должен построить переменную заданного типа и присвоить ей значение, заданное пользователем. Если корректно указано имя типа и значение, то операция пройдет успешно, о чем пользователю и будет выдано соответствующее сообщение. В качестве допустимых типов разрешается указывать любой допустимый в C# скалярный тип, заданный таблицей 2.1. В качестве допустимого значения разрешается указывать любое значение из диапазона, соответствующего выбранному типу, и представленному в таблице 2.1. В случае некорректной работы пользователя появляется сообщение "Неправильно указано имя типа" или, если значение не соответствует заданному типу, должно выдаваться сообщение об ошибке.
Спроектируем в интерфейсе пользователя и командную кнопку "Вывод", по нажатию которой будет выдаваться значение, хранимое в созданной переменной.
Тест должен позволить пользователю изучить все скалярные типы языка C#, понять, какие значения допустимы для каждого типа, увидеть, как можно вводить и выводить значения переменных скалярного типа.
Еще одна важная роль этого теста состоит в демонстрации правильной организации ввода данных с использованием программной конструкции try - catch блоков. Ввод данных, задаваемых пользователем, всегда должен контролироваться, поскольку человеку свойственно ошибаться. Тест показывает, как можно обнаруживать ошибки ввода.
В соответствии с задачами теста спроектируем интерфейс пользователя. Прежде всего в проект нужно добавить новый интерфейсный класс, сопровождаемый формой. Такие классы являются наследниками класса Form из библиотеки FCL. Воспользуемся пунктом меню Project|AddWindowsForm для добавления в проект интерфейсного класса и ,соответственно, новой формы. Отслеживая наши действия, инструментальное средство Designer Form добавит в наш проект необходимые классы. Следуя правилам стиля, произведем переименование, заменив стандартные имена содержательными.
Теперь можно заняться непосредственным проектированием пользовательского интерфейса, размещая в форме нужные элементы управления. Не буду в деталях описывать весь процесс проектирования, поскольку интерфейс достаточно прост. Он отвечает заданной функциональности и включает известные элементы управления - метки, текстовые окна, командные кнопки и контейнеры GroupBox. Контейнеры в формах позволяют придать пользовательскому интерфейсу нужную структуру, объединяя в группу элементы управления, решающие общую задачу - например, ввода исходных данных или вывода результатов.
На рис. 2.4 показана спроектированная форма в процессе работы с ней.
Визуальное, событийно-управляемое программирование
Прежде чем продолжить рассмотрение теста, давайте поговорим об основных принципах, лежащих в основе современного визуального стиля программирования. На начальных этапах программирования работой программы полностью управлял ее текст. Так, в программах на языке Алгол выполнение программы начиналось с оператора begin (начало) и заканчивалось оператором end (конец). Развитие программирования потребовало диалога с пользователем в ходе выполнения программы. Вначале это был простой диалог, характерный для уже рассмотренных нами консольных приложений, когда выполнение программы приостанавливается, и она ждет ответа пользователя, вводимого с консоли. Дальнейшее развитие программирования привело к визуальному стилю, когда программные объекты стали иметь визуальные образы, когда появились графические объекты. Графические образы более информативны, чем текстовые. Визуальный стиль изменил и стиль диалога с пользователем, позволив строить интерфейс пользователя, основанный на объектах, имеющих визуальный образ. Простейшим и классическим примером является объект класса TextBox, графическим образом которого является текстовое окно - оно может служить как для вывода текстов в окно, так и для ввода текста пользователем. Этот объект обладает мощной функциональностью текстового редактора, позволяет пользователю редактировать вводимый им текст, удаляя, заменяя и вставляя символы в произвольное место текста.
В библиотеке FCL имеется большое число классов, предназначенных для организации пользовательского интерфейса. Со многими из них будем знакомиться по ходу изучения нашего курса. Эти интерфейсные классы и соответствующие объекты получили название элементов управления (control). Класс Control из этой библиотеки обеспечивает базовую функциональность всех элементов управления и является родительским классом для всех интерфейсных классов. Класс Form, который неоднократно упоминался, также является непрямым наследником класса Control и прямым наследником класса ContainerControl. Последний класс определяет базовую функциональность тех элементов управления, которые, как и формы, есть контейнеры, допускающие внутри графического образа размещение образов других элементов управления. Кроме формы, уже известным нам примером контейнера служит класс GroupBox.
Выше говорилось, что проектирование пользовательского интерфейса, как правило, ведется не программным путем, хотя и такое возможно, а "руками". В Visual Studio 2008 имеется специальная инструментальная панель с элементами управления, которые можно перетаскивать на форму в процессе проектирования, располагать эти элементы в нужном месте формы, менять их размеры, устанавливать их свойства, открываемые в окне свойств. Дизайнер формы транслирует все эти действия в соответствующий программный код.
Процедура Main, задающая точку входа в Windows-проект, открывает главную форму, и пользователь попадает в спроектированный для этой формы мир графических объектов. Теперь пользователь становится у руля управления ходом выполнения проекта и является "возмутителем спокойствия" в этом мире объектов. Он начинает вводить тексты в текстовые окна, выбирать нужные ему элементы из открывающихся списков, нажимать командные кнопки и выполнять другие действия над элементами управления. Каждое такое действие пользователя приводит к возникновению соответствующего события у программного объекта. Так, когда пользователь изменяет текст в текстовом окне, у соответствующего объекта класса TextBox возникает событие TextChanged, при нажатии командной кнопки у объекта возникает событие Click, двойной щелчок по командной кнопке приводит к событию DblClick. В ответ на возникновение события объект посылает сообщение операционной системе. Обрабатывая очередь сообщений, операционная система отыскивает обработчик события, если объект предусмотрел таковой, и передает ему управление.
Подключить к объекту обработчик события можно визуально в процессе проектирования элемента управления. В окне свойств элемента управления можно перейти к списку событий этого элемента и в этом списке выбрать (включить) нужное событие. На рис. 2.5 показан момент проектирования формы, когда для выбранного элемента управления buttonInput в окне его свойств отображается список возможных событий этого элемента.
Можно видеть, что для этого элемента включено событие Click. Заметьте, имя обработчика события строится из имен элемента управления и события, разделенных знаком подчеркивания. У каждого элемента управления есть одно основное событие, которое можно включить простым щелчком по элементу управления, например, для командных кнопок таким событием является событие Click.
При включении события интерфейсный класс автоматически дополняется специальным методом, содержащим заготовку обработчика события - заголовок метода с пустым его телом. Дополнить обработчик события содержательным кодом - задача программиста. В обработчике события программист волен предусмотреть самые разные действия: может изменять свойства других объектов, вызывать методы других объектов, создавать объекты, добавлять или удалять интерфейсные объекты, изменяя мир объектов пользовательского интерфейса. Большинство компьютерных игр - всяческие "стрелялки" - яркий пример такого стиля программирования.
С точки зрения объектного программирования обработчики событий - это специальные методы интерфейсных классов (события), особенность которых состоит в том, что они вызываются в нужный момент операционной системой в ответ на возникновение события у соответствующего объекта, инициированного работой пользователя. Механизм делегатов, на котором основана работа с событиями в языке C#, будет подробно рассматриваться в соответствующем разделе нашего курса.
Стиль программирования, основанный на проектировании визуального пользовательского интерфейса, называется визуальным программированием. Стиль программирования, основанный на событиях и системных вызовах обработчиков событий, называется событийно-управляемым программированием (event - driven programming). Современный стиль является визуальным, событийно-управляемым стилем программирования.