Справочник по C# Герберт Шилдт ббк 32. 973. 26018 75 Ш57 удк 681 07 Издательский дом "Вильямс" Зав редакцией
Скачать 5.05 Mb.
|
Глава 25 Создание Windows- приложений 690 Часть III. Применение языка C# ольшинство программ, приведенных в этой книге, представляют собой консольные приложения, т.е. приложения, запускаемые из командной строки (и не имеющие графического интерфейса). Консольные приложения прекрасно подходят для демонстрации элементов языка C# и вполне годятся для некоторых типов обслуживающих программ, которые, например, фильтруют файлы. Конечно же, современные приложения в большинстве предназначены для работы в Windows GUI-среде (graphics user mterface — графический интерфейс пользователя), и эта книга была бы неполной, если не показать в ней, как использовать C# для создания Windows-приложений. Еще в недалеком прошлом создание Windows-приложений было под силу лишь опытным программистам и внушало ужас новичкам, которым зачастую приходилось в течение нескольких недель осваивать лишь основные элементы построения Windows- приложений. К счастью, C# и среда .NET Framework изменили ситуацию коренным образом. В .NET-библиотеке содержится полная подсистема, которая поддерживает библиотеку Forms, что значительно упрощает создание Windows-программ. С использованием языка C# и библиотеки System.Windows.Forms Windows-приложения создавать теперь намного проще. Windows-программирование — очень большая тема, которой посвящено немало книг. Очевидно, описать все его аспекты в одной главе попросту нереально. Поэтому настоящую главу следует рассматривать как “высокий старт” в направлении Windows- программирования. Здесь вы узнаете, как создать окно, меню и кнопку, а также ответить на сообщение. Прочитав эту главу, вы будете готовы освоить и другие аспекты Windows- программирования, основанного на применении окон. Краткий экскурс в историю Windows-программирования Чтобы оценить достоинства языка C# и среды .NET Framework применительно к Windows-программированию, необходимо слегка погрузиться а его историю. Сразу после создания Windows программы взаимодействовали непосредственно с Windows API- интерфейсом (Application Programming Interface — программный интерфейс приложения), представляющим собой большой набор методов, которые могут вызываться программами для доступа к функциям Windows. API-ориентированные программы отличаются большим размером и сложностью. Длина API-ориентированных программ, которые выполняют отдельные функции, измеряется сотнями строк, а реальных приложений — тысячами. Теперь вы можете представить себе, насколько Windows-программы было трудно писать и поддерживать. Для решения этой проблемы были созданы библиотеки классов, которые инкапсулировали функции API-интерфейса. Возможно, многие читатели уже знакомы с библиотекой MFC (Microsoft Foundation Classes — библиотека базовых классов Microsoft). Она написана на C++; MFC-ориентированные программы также использовали язык C++. Благодаря объектно-ориентированной направленности библиотеки MFC процесс создания Windows-программ заметно упростился. Однако MFC-программы все равно отличались повышенной сложностью, т.е. включали заголовочные файлы, файлы с исходным кодом и файлы ресурсов. Более того, библиотека MFC была по сути лишь “тонкой оболочкой”, в которую помещался API-интерфейс, поэтому для реализации Windows-ориентированного поведения приложений по-прежнему требовалось внушительное количество программных инструкций. Б Глава 25. Создание Windows-приложений 691 Язык C# и .NET Framework-библиотека Forms предлагают полностью объектно- ориентированный подход к Windows-программированию. Вместо обеспечения лишь оболочки для API библиотека Forms определяет простой, интегрированный и логически непротиворечивый способ управления разработкой Windows-приложений. Этот уровень интеграции стал возможным лишь благодаря таким уникальным средствам языка C#, как делегат и события. Более того, благодаря специфическому в C# использованию системы сбора мусора, практически устранена проблема “утечки памяти”. Если вы уже программировали с использованием API-интерфейса или библиотеки MFC, то убедитесь в том, что C#-решения относятся к более высокому уровню. Впервые (с момента создания операционной системы Windows) создание Windows-приложений стало таким же простым, как и создание консольных приложений. Два способа создания Windows-приложений, основанных на применении окон Для начала необходимо остановиться вот на чем. Пакет Visual Studio включает обширный набор средств разработки, которые автоматизируют большую часть процесса создания Windows-приложения. С помощью этих средств можно создавать и помешать в нужное место различные элементы управления и меню, используемые приложением. Visual Studio помогает создавать классы и методы, которые необходимы для каждого управляющего элемента. Средства разработки Visual Studio — очень удобный инструмент для создания большинства Windows-приложений, хотя и не единственно возможный. Windows-программы можно также создавать с помощью текстового редактора с последующей компиляцией исходного кода подобно тому, как вы это делали с консольными приложениями. Поскольку книга посвящена языку C#, а не Visual Studio, да и Windows-программы, представленные в этой главе, довольно невелики по размеру, их создание показано здесь в форме, которая подходит для использования текстового редактора, Но общая структура, разработка и организация программ остаются такими же, как и при использовании автоматизированных средств разработки. Таким образом, материал этой главы применим к любому способу создания программ. Как Windows взаимодействует с пользователем Прежде чем приступать к Windows-программированию, необходимо понять, как пользователь взаимодействует с Windows, поскольку именно этот фактор определяет архитектуру всех Windows-программ. Это взаимодействие в корне отличается от взаимодействия, реализованного в консольных программах, представленных в других частях этой книги. В случае консольной программы именно ваша программа инициирует взаимодействие с операционной системой. Примером может служить программа, запрашивающая входные данные и выводящая результаты путем вызова методов Read() или WriteLine() . Таким образом, программы, написанные “традиционным способом”, сами обращаются к операционной системе, а не операционная система к ним. Но в отношении “своих” программ Windows предполагает совсем иную модель отношений: именно Windows должна обращаться к вашей программе. Процесс взаимодействия организован следующим образом: программа ожидает до тех пор, пока не получит сообщение от Windows. Получив его, программа должна предпринять соответствующее действие. Отвечая на сообщение, она может вызвать метод, определенный в Windows, но главное здесь то, что инициатором взаимодействия все-таки является Windows. 692 Часть III. Применение языка C# Таким образом, общий формат всех Windows-программ продиктован механизмом сообщений, который и лежит в основе взаимодействия с Windows. Существует множество различных сообщений, которые Windows может послать программе. Например, при каждом щелчке кнопкой мыши в окне вашей программы будет послано сообщение, связанное со щелчком кнопкой мыши. При щелчке на электронной кнопке будет послано сообщение другого типа, а при выборе элемента меню — третьего. Здесь необходимо понимать следующее: с точки зрения программы сообщения поступают случайным образом. Вот почему Windows-программы напоминают программы, управляемые прерываниями. Вы сами не знаете, каким будет следующее сообщение. Windows-формы Ядром Windows-программ, написанных на C#, является форма. Форма инкапсулирует основные функции, необходимые для создания окна, его отображения на экране и получения сообщений. Форма может представлять собой окно любого типа, включая основное окно приложения, дочернее или даже диалоговое окно. Первоначально окно создается пустым. Затем в него добавляются меню и элементы управления, например экранные кнопки, списки и флажки. Таким образом, форму можно представить в виде контейнера для других Windows-объектов. Когда окну посылается сообщение, оно преобразуется в событие. Следовательно, чтобы обработать Windows-сообщение, достаточно для него зарегистрировать обработчик событий. При получении этого сообщения обработчик событий будет вызываться автоматически. Класс Form Форма создается посредством реализации объекта класса Form или класса, производного от Form . Класс Form помимо поведения, обусловленного собственными членами, демонстрирует поведение, унаследованное от предков. Среди его базовых классов выделяются своей значимостью классы System.ComponentModel.Component (см. главу 24) и System.Windows.Forms.Control . Класс Control определяет черты, присущие всем Windows-элементам управления. Тот факт, что класс Form выведен из класса Control , позволяет использовать формы для создания элементов управления. Использование некоторых членов классов Form и Control демонстрируется в приведенных ниже примерах. Схематичная Windows-программа, основанная на применении окон Начнем с создания простейшего Windows-приложения, основанного на применении окон. Это приложение создает и отображает окно, которое не содержит других элементов управления. Тем не менее оно позволяет показать действия, необходимые для построения полнофункционального окна. Это окно представляет собой стартовую площадку, на которой можно построить большинство Windows-приложений. Итак, рассмотрим первую Windows-программу: // Простейшее Windows-приложение, основанное // на применении окон. Глава 25. Создание Windows-приложений 693 using System; using System.Windows.Forms; // Класс WinSkel - производный от класса Form. class WinSkel : Form { public WinSkel() { // Присваиваем окну имя. Text = "Рама Windows-окна"; } // Метод Main() используется только для запуска приложения. [STAThread] public static void Main() { WinSkel skel = new WinSkel(); // Создаем форму. // Запускаем механизм функционирования окна. Application.Run(skel); } } Окно, созданное этой программой, показано на рис. 25.1. Рис. 25.1. Окно, созданное программой WinSkel Рассмотрим эту программу построчно. Прежде всего обратите внимание на то, что она включает два пространства имен: System и System.Windows.Forms . Пространство имен System необходимо для использования атрибута STAThread , который предшествует методу Main() , a System.Windows.Forms предназначено для поддержки подсистемы Windows Forms. Затем создается класс WinSkel , который наследует класс Form . Следовательно, класс WinSkel определяет тип формы. В данном случае это самая простая (минимальная) форма. В теле конструктора класса WinSkel содержится только одна строка кода: Text = "Рама Windows-окна"; Здесь устанавливается свойство Text , которое содержит название окна. Таким образом, после выполнения инструкции присвоения строка заголовка окна будет содержать текст Рама Windows-окна . Свойство Text определяется так: public virtual string Text { get; set; } Свойство Text унаследовано от класса Control Теперь рассмотрим метод Main() , который объявлен подобно другим методам Main() , входящим в состав программ этой главы. С этого метода, как вы уже знаете, 694 Часть III. Применение языка C# начинается выполнение программы. Однако заметьте, что заголовку метода Main() предшествует свойство STAThread . Microsoft заявляет, что это свойство должен иметь метод Main() в каждой Windows-программе. Свойство STAThread устанавливает модель организации поточной обработки (threading model), а именно модель с однопоточным управлением, т.е. такую обработку данных, когда все объекты выполняются в едином процессе (single-threaded apartment — STA). Рассмотрение моделей организации поточной обработки выходит за рамки этой главы, но вкратце заметим, что Windows-приложение может использовать одну из двух моделей: с однопоточным или многопоточным управлением. В методе Main() создается объект класса WinSkel с именем skel . Этот объект затем передается методу Run() , определенному в классе Application : Application.Run(skel); Эта инструкция запускает механизм функционирования окна. Класс Application определяется в пространстве имен System.Windows.Forms и инкапсулирует аспекты, присущие всем Windows-приложениям. Вот как определяется используемый здесь метод Run() : public static void Run(Form ob ) В качестве параметра он принимает ссылку на форму. Поскольку класс WinSkel выведен из класса Form , объект типа WinSkel можно передать методу Run() Эта программа при выполнении создает окно, показанное на рис. 25.1. Оно имеет стандартный размер (300 пикселей по ширине и 300 пикселей по высоте). Это окно полностью функционально. Можно изменить его размеры, переместить, свернуть, восстановить и закрыть. Таким образом, основные свойства, присущие практически всем окнам, были достигнуты написанием всего нескольких строк программного кода. Для сравнения: такая же программа, написанная на языке С и напрямую вызывающая интерфейс Windows API, потребовала бы приблизительно в пять раз больше программных строк! Предыдущий пример продемонстрировал основные принципы создания Windows- приложений, основанных на применении окон. Итак, чтобы создать форму, создайте класс, производный от класса Form . Затем инициализируйте эту форму в соответствии с требованиями приложения, создайте объект производного класса и вызовите метод Application.Run() для этого объекта. Компиляция первой Windows-программы Windows-программу можно скомпилировать, используя либо компилятор командной строки, либо среду разработки Visual Studio. Для таких коротких программ, как те, что представлены в этой главе, вполне подойдет компилятор командной строки (как самый простой вариант), но для реальных приложений стоит использовать IDE. (Кроме того, как разъяснялось в начале главы, имеет смысл освоить средства разработки, предоставляемые пакетом Visual Studio.) В любом случае здесь описаны оба варианта компиляции Windows- приложений. Компиляция из командной строки Назовите нашу первую Windows-программу WinSkel.cs и скомпилируйте ее, вызвав компилятор командной строки с помощью следующей команды: csc /t:winexe WinSkel.cs Ключ /t:winexe указывает компилятору на создание Windows-приложения, а не консольной программы. Чтобы выполнить программу, достаточно ввести в командную строку текст WinSkel Глава 25. Создание Windows-приложений 695 Компиляция в интегрированной среде разработки (IDE) Чтобы скомпилировать программу с помощью Visual Studio IDE, сначала создайте новый проект Windows Application. Для этого выберите команду File , New , Project (Файл , Создать , Проект). Затем выберите в диалоговом окне New Project (Создать проект) вариант Windows Application (Windows-приложение). Назовите проект WinSkel С этим проектом будет связан файл Form1.cs . Удалите его. Затем, щелкнув правой кнопкой мыши на имени проекта WinSkel , выберите из контекстного меню команду Add , Add New Item (Добавить , Добавить новый элемент). Вы должны увидеть диалоговое окно, показанное на рис. 25.2. Рас. 25 2. Диалоговое окно Add New Item (Добавить новый элемент) Выберите на панели Templates (Шаблоны) вариант Code File (Файл с текстом программы) и назовите файл WinSkel.cs . Затем введите текст нашей первой Windows- программы и скомпилируйте программу с помощью команды Build , Build Solution (Построить , Построить решение). Для выполнения программы выберите команду Debug , Start Without Debugging (Отладка , Начать выполнение без отладки). Создание кнопки В общем случае функциональность окна обеспечивается элементами двух типов: элементами управления и меню. Именно с помощью этих элементов и взаимодействует пользователь с программой. Меню описаны ниже в этой главе. Здесь вы узнаете, как поместить в окно элемент управления. В Windows определены различные типы управляющих элементов, включая экранные кнопки, флажки, переключатели и окна списков. Несмотря на различия между ними, способы их создания примерно одинаковы. В этом разделе мы поместим в окно экранную кнопку, но процедура добавления других типов управляющих элементов будет такой же. 696 Часть III. Применение языка C# Немного теории. Экранная кнопка инкапсулирована в классе Button , который выведен из абстрактного класса ButtonBase . Поскольку класс ButtonBase предназначен для реализации поведения оконного элемента управления, он наследует класс Control . В классе Button определен только один конструктор: public Button() Этот конструктор создает кнопку стандартного размера, расположенную внутри окна. Эта кнопка не содержит описания, поэтому, прежде чем использовать ее, необходимо описать ее, присвоив свойству Text соответствующую текстовую строку. Для указания местоположения кнопки в окне необходимо присвоить свойству Location координаты ее верхнего левого угла. Свойство Location унаследовано от класса Control и определяется так: public Point Location { get; set; } Координаты хранятся в структуре Point , которая определена в пространстве имен System.Drawing . Она включает следующие свойства: public int X { get; set; } public int Y { get; set; } Таким образом, чтобы создать кнопку с надписью “Щелкните здесь” и привязать ее к точке с координатами 100, 200, используйте следующую последовательность инструкций: Button MyButton = new Button(); MyButton.Text = "Щелкните здесь"; MyButton.Location = new Point(100, 200); Как поместить кнопку на форму После создания кнопку необходимо поместить на форму. Это реализуется с помощью метода Add() , который вызывается для коллекции элементов управления, связанных с формой. Эта коллекция доступна посредством свойства Controls , которое унаследовано от класса Control . Вот как определяется метод Add() : public virtual void Add(Control cntl ) Здесь параметр cntl означает добавляемый элемент управления. После того как элемент будет добавлен в состав формы, он станет видимым при отображении самой формы. Простой пример с кнопкой В следующей программе на созданную ранее форму помещается кнопка. Пока что эта кнопка бездействует, но на ней можно щелкнуть. // Добавление кнопки. using System; using System.Windows.Forms; using System.Drawing; class ButtonForm : Form { Button MyButton = new Button(); public ButtonForm() { Глава 25. Создание Windows-приложений 697 Text = "Использование кнопки"; MyButton = new Button(); MyButton.Text = "Щелкните"; MyButton.Location = new Point(100, 200); Controls.Add(MyButton); } [STAThread] public static void Main() { ButtonForm skel = new ButtonForm(); Application.Run(skel); } } В этой программе создается класс ButtonForm , который является производным от класса Form . Он содержит поле типа Button с именем MyButton . В конструкторе класса ButtonForm кнопка создается, инициализируется и помещается на форму. При выполнении этой программы отображается окно, показанное на рис. 25.3. Вы можете щелкнуть на кнопке, но ничего не произойдет. Чтобы заставить кнопку выполнять какие- либо действия, необходимо добавить в программу обработчик сообщений, как описано в следующем разделе. Рис. 25.3. Кнопка на форме Обработка сообщений Чтобы программа реагировала на щелчок на кнопке (или на какое-либо другое действие пользователя), необходимо обеспечить обработку сообщения, которое генерирует эта кнопка. В общем случае, когда пользователь воздействует на элемент управления, его действие передается программе в виде сообщения. В C#-программе, основанной на применении окон, такие сообщения обрабатываются обработчиками событий. Следовательно, чтобы получить сообщение, программа должна добавить собственный обработчик событий в список обработчиков, вызываемых при генерировании сообщения. Для сообщений, связанных со щелчком на кнопке, это означает добавление обработчика для события Click Событие Click определяется в классе Button . (Событие Click унаследовано от класса Control .) Его общий формат таков: public Event EventHandler Click; 698 Часть III. Применение языка C# Делегат EventHandler определяется так: public delegate void EventHandler(object who , EventArgs args ) Объект, который сгенерировал событие, передается в параметре who , а информация, связанная с этим событием, — в параметре args . Для многих событий в качестве параметра args будет служить объект класса, выведенного из класса EventArgs Поскольку щелчок на кнопке не требует дополнительной информации, при обработке события щелчка на кнопке не нужно беспокоиться об аргументах этого события. Следующая программа основана на предыдущей, но с добавлением кода реакции на щелчок. При каждом щелчке на кнопке будет изменяться ее местоположение. // Обработка сообщений от кнопки. using System; using System.Windows.Forms; using System.Drawing; class ButtonForm : Form { Button MyButton = new Button(); public ButtonForm() { Text = "Реакция на щелчок"; MyButton = new Button(); MyButton.Text = "Щелкните"; MyButton.Location = new Point(100, 200); // Добавляем в список обработчик событий кнопки. MyButton.Click += new EventHandler(MyButtonClick); Controls.Add(MyButton); } [STAThread] public static void Main() { ButtonForm skel = new ButtonForm(); Application.Run(skel); } // Обработчик для кнопки MyButton. protected void MyButtonClick(object who, EventArgs e) { if(MyButton.Top == 200) MyButton.Location = new Point(10, 10); else MyButton.Location = new Point(100, 200); } } Рассмотрим внимательно код обработчика события щелчка на кнопке: // Обработчик для кнопки MyButton. protected void MyButtonClick(object who, EventArgs e) { if(MyButton.Top == 200) MyButton.Location = new Point(10, 10); else MyButton.Location = new Point(100, 200); } Глава 25. Создание Windows-приложений 699 Обработчик MyButtonClick() использует такую же сигнатуру, как и приведенный выше делегат EventHandler , а это значит, что обработчик можно добавить в цепочку обработчиков для события Click . Обратите внимание на то, что в его определении использован модификатор типа protected . И хотя это не является обязательным требованием, такая модификация имеет смысл, поскольку обработчики событий не предназначены для вызова кодом, а используются лишь для ответа на события, В коде обработчика координаты верхней границы кнопки определяются с помощью свойства Тор . Следующие свойства определяются для всех элементов управления (они задают координаты верхнего левого и нижнего правого углов): public int Top { get; set; } public int Bottom { get; } public int Left { get; set; } public int Right { get; } Обратите внимание на то, что местоположение элемента управления можно изменить с помощью свойств Top и Left , но не свойств Bottom и Right , так как последние предназначены только для чтения. (Для изменения размера элемента управления можно использовать свойства Width и Height .) При получении события, связанного со щелчком на кнопке, проверяется координата ее верхней границы, и, если она равна начальному значению 200, для кнопки устанавливаются новые координаты: 10, 10. В противном случае кнопка возвращается в исходное положение с координатами 100, 200. Поэтому при каждом щелчке на кнопке ее местоположение меняется. Прежде чем обработчик MyButtonClick() сможет получать сообщения, его необходимо добавить в цепочку обработчиков событий, связанную с событием Click . Это реализуется в конструкторе класса ButtonForm с помощью такой инструкции: MyButton.Click += new EventHandler(MyButtonClick); После выполнения этой инструкции при каждом щелчке на кнопке и будет вызываться обработчик событий MyButtonClick() Альтернативная реализация Интересно отметить, что обработчик событий MyButtonClick() можно написать по-другому. Вспомните, что параметр who обработчика событий принимает ссылку на объект, который сгенерировал вызов. Когда происходит событие, связанное со щелчком на кнопке, таким объектом является кнопка, на которой был сделан щелчок. Поэтому обработчик MyButtonClick() может иметь такой код: // Альтернативный вариант обработчика событий, // связанных со щелчком на кнопке. protected void MyButtonClick(object who, EventArgs e) { Button b = (Button) who; if(b.Top == 200) b.Location = new Point(10, 10); else b.Location = new Point(100, 200); } В этой версии обработчика значение параметра who приводится к типу Button , и именно эта ссылка (а не поле MyButton ) используется для доступа к объекту кнопки. И хотя в данном случае этот вариант не демонстрирует никаких преимуществ перед предыдущим, нетрудно представить ситуации, в которых он окажется более подходящим. Например, такой подход позволяет писать обработчик событий кнопки, который не зависит от конкретной кнопки. 700 Часть III. Применение языка C# Использование окна сообщений Одним из самых полезных встроенных средств Windows-приложений является окно сообщений. Как понятно по названию, окно сообщений позволяет отображать сообщения. С его помощью можно также получить от пользователя такие простые ответы (на поставленные вопросы), как Да, Нет или ОК. В программе, основанной на применении окон, окно сообщений поддерживается классом MessageBox . При этом объект класса создавать не нужно. Для отображения окна сообщений достаточно вызвать определенный в этом классе статический метод Show() Метод Show() используется в нескольких форматах. Один из них выглядит так: public static DialogResult Show( string msg , string caption , MessageBoxButtons mbb ) Строка, отображаемая внутри окна, передается в параметре msg , заголовок окна сообщения — в параметре caption . Кнопки, отображаемые в окне, задаются параметром mbb . Метод возвращает ответ пользователя. MessageBoxButtons — это перечисление, которое определяет следующие значения: AbortRetryIgnore OK OKCancel RetryCancel YesNo YesNoCancel Каждое из этих значений описывает кнопки, которые будут включены в окно сообщений. Например, если параметр mbb содержит значение YesNo , то в окне сообщений будут отображены кнопки Да и Нет. Значение, возвращаемое методом Show() , означает, какая кнопка нажата пользователем. Это может быть одно из следующих значений: Abort Cancel Ignore No None OK Retry Yes В своей программе вы можете проверить значение, возвращаемое методом Show() , и определить линию поведения, избранную пользователем. Например, если в окне сообщения пользователь предупреждается о возможности перезаписи файла, то ваша программа предотвратит перезапись, если пользователь щелкнет на кнопке Отменить, или выполнит ее, если пользователь щелкнет на ОК. Следующая программа основана на предыдущей, но с добавлением кнопки останова и окна сообщений. В обработчике событий, связанных с кнопкой останова, организовано отображение окна сообщений, в котором пользователю предлагается ответить на вопрос, желает ли он остановить программу. Если пользователь ответит щелчком на кнопке Да, программа остановится. Если же он щелкнет на кнопке Нет, выполнение программы будет продолжено. // Добавление кнопки останова. using System; using System.Windows.Forms; using System.Drawing; class ButtonForm : Form { Button MyButton; Button StopButton; public ButtonForm() { Text = "Добавление кнопки Стоп"; Глава 25. Создание Windows-приложений 701 // Создаем кнопки. MyButton = new Button(); MyButton.Text = "Щелкните"; MyButton.Location = new Point(100, 200); StopButton = new Button(); StopButton.Text = "Стоп"; StopButton.Location = new Point(100, 100); // Добавляем обработчики событий. MyButton.Click += new EventHandler(MyButtonClick); Controls.Add(MyButton); StopButton.Click += new EventHandler(StopButtonClick); Controls.Add(StopButton); } [STAThread] public static void Main() { ButtonForm skel = new ButtonForm(); Application.Run(skel); } // Обработчик событий для кнопки MyButton. protected void MyButtonClick(object who, EventArgs e) { if(MyButton.Top == 200) MyButton. Location = new Point(10, 10); else MyButton.Location = new Point(100, 200); } // Обработчик событий для кнопки StopButton. protected void StopButtonClick(object who, EventArgs e) { // Если пользователь ответит щелчком на кнопке Yes. // программа будет завершена. DialogResult result = MessageBox.Show( "Остановить программу?", "Завершение", MessageBoxButtons.YesNo); if(result == DialogResult.Yes) Application.Exit(); } } Рассмотрим, как используется окно сообщений. Нетрудно заметить, что в конструктор ButtonForm добавлена вторая кнопка. Эта кнопка содержит текст “Стоп”, и ее обработчик событий связывается с методом StopButtonClick() В обработчике StopButtonClick() с помощью следующей инструкции отображается окно сообщений: // Если пользователь ответит щелчком на кнопке Yes, // программа будет завершена. DialogResult result = MessageBox.Show( "Остановить программу?", "Завершение", MessageBoxButtons.YesNo); 702 Часть III. Применение языка C# Здесь окно сообщения имеет заголовок “Завершение”. Внутри этого окна отображается текст “Остановить программу?” и кнопки Да и Нет. Результат выполнения метода Show() , который содержит ответ пользователя, присваивается переменной result . При выполнении следующей строки кода этот ответ проверяется, и от результата проверки зависит дальнейший ход выполнения программы: if(result == DialogResult.Yes) Application.Exit(); Если пользователь щелкнет на кнопке Да, программа остановится. Это реализуется вызовом метода Application.Exit() , который обеспечивает немедленное завершение программы. В противном случае никакие действия не выполняются, и программа продолжается. Результат выполнения этой программы показан на рис. 25.4. Рис. 25.4. Результат выполнения программы, использующей окно сообщений Создание меню Главное окно практически всех Windows-приложений включает меню, расположенное вдоль верхней его границы. Оно называется основным. Основное меню обычно содержит такие категории верхнего уровня, как Файл, Правка и Сервис. Из основного меню можно получить раскрывающиеся меню, содержащие команды, связанные с соответствующей категорией. При выборе элемента меню генерируется сообщение. Следовательно, чтобы обработать команду меню, программа должна присвоить каждому элементу меню обработчик событий. Основное меню создается путем комбинации двух классов. Первый класс — MainMenu — инкапсулирует общую структуру меню, а второй — MenuItem — отдельный его элемент. Элемент меню может представлять либо конечное действие (например, Закрыть), либо активизировать другое раскрывающееся меню. Оба класса — MainMenu и MenuItem — наследуют класс Menu . Поскольку меню представляют собой основной ресурс в Windows-программировании, эта тема довольно обширна и включает массу возможностей, связанных с построением меню. К счастью, для создания стандартного меню достаточно освоить основные моменты из этой темы. При выборе элемента меню генерируется событие Click , которое определено в классе MenuItem . Следовательно, чтобы обработать выбор элемента меню, в список обработчиков события Click , связанный с этим элементом, необходимо добавить соответствующий обработчик. Каждая форма имеет свойство Menu , определенное таким образом: public MainMenu Menu { get; set; } Глава 25. Создание Windows-приложений 703 По умолчанию этому свойству не присвоено никакое меню. Чтобы отобразить основное меню, это свойство необходимо “настроить” на создаваемое вами меню. Для создания основного меню выполните следующие действия. 1. Создайте объект класса MainMenu 2. В объект класса MainMenu добавьте объекты класса MenuItem , которые описывают категории верхнего уровня. Эти элементы меню добавляются в коллекцию типа MenuItems , связанную с основным меню. 3. Для каждого MenuItem -объекта верхнего уровня добавьте список MenuItem - объектов, который определяет раскрывающееся меню, связанное с элементом меню верхнего уровня. Эти элементы меню добавляются в коллекцию MenuItems , связанную с каждым элементом меню верхнего уровня. 4. Добавьте обработчики событий для каждого элемента меню. 5. Присвойте объект класса MainMenu свойству Menu , связанному с формой. В следующем фрагменте кода показано, как создать меню Файл, которое содержит три команды: Открыть, Закрыть и Выйти. // Создаем объект основного меню. MainMenu MyMenu = new MainMenu(); // Добавляем в это меню элемент верхнего уровня. MenuItem m1 = new MenuItem("Файл"); MyMenu.MenuItems.Add(m1); // Создаем подменю "Файл". MenuItem subm1 = new MenuItem("Открыть"); m1.Menuitems.Add(subm1); MenuItem subm2 = new MenuItem("Закрыть"); m1.Menuitems.Add(subm2); MenuItem subm3 = new MenuItem("Выйти"); m1.Menuitems.Add(subm3); Эта последовательность инструкций заслуживает внимательного рассмотрения. Она начинается с создания объекта класса MainMenu с именем MyMenu . Этот объект будет находиться на верхнем уровне структуры меню. Затем создается элемент меню m1 с заголовком “Файл”. Он добавляется непосредственно к объекту MyMenu . После этого создается раскрывающееся меню, связанное с командой Файл основного меню. Обратите внимание на то, что элементы раскрывающегося меню добавляются к объекту m1 , который является элементом Файл основного меню. Если один MenuItem -объект добавляется к другому, добавляемый объект становится частью раскрывающегося меню, связанного с элементом, к которому добавляется MenuItem -объект. Следовательно, после того как элементы subm1 — subm3 будут добавлены к элементу m1 , при выборе команды File отобразится раскрывающееся меню, содержащее команды Открыть, Закрыть и Выйти. Создав меню, для каждого его элемента необходимо создать связанные с ним обработчики событий. Как разъяснялось выше, при выборе пользователем команды меню генерируется событие Click . Поэтому при выполнении следующей последовательности инструкций элементам subm1 — subm3 будут назначены соответствующие обработчики событий. //Добавляем обработчики событий для всех элементов меню. subm1.Click += new EventHandler(MMOpenClick); subm2.Click += new EventHandler(MMCloseClick); subm3.Click += new EventHandler(MMExitClick); 704 Часть III. Применение языка C# Таким образом, если пользователь выберет команду Выйти, выполнится обработчик событий MMExitClick() Наконец, свойству Menu формы нужно присвоить объект класса MainMenu : Menu = MyMenu; После выполнения этой инструкции окно будет отображаться вместе с меню, при выборе команд которого будут вызываться соответствующие обработчики событий. Следующая программа демонстрирует создание основного меню и обработку событий, связанных с выбором команд меню. // Добавляем основное меню. using System; using System.Windows.Forms; class MenuForm : Form { MainMenu MyMenu; public MenuForm() { Text = "Добавление меню"; // Создаем объект основного меню. MainMenu MyMenu = new MainMenu(); // Добавляем в это меню элемент верхнего уровня. MenuItem m1 = new MenuItem("Файл"); MyMenu.MenuItems.Add(m1); MenuItem m2 = new MenuItem("Сервис"); MyMenu.MenuItems.Add(m2); // Создаем подменю Файл. MenuItem subm1 = new MenuItem("Открыть"); m1.MenuItems.Add(subm1); MenuItem subm2 = new MenuItem("Закрыть"); m1.MenuItems.Add(subm2); MenuItem subm3 = new MenuItem("Выйти"); m1.MenuItems.Add(subm3); // Создаем подменю "Сервис". MenuItem subm4 = new MenuItem("Координаты"); m2.MenuItems.Add(subm4); MenuItem subm5 = new MenuItem("Изменить размер"); m2.MenuItems.Add(subm5); MenuItem subm6 = new MenuItem("Восстановить"); m2.MenuItems.Add(subm6); // Добавляем обработчики событий для элементов меню. subm1.Click += new EventHandler(MMOpenClick); subm2.Click += new EventHandler(MMCloseClick); subm3.Click += new EventHandler(MMExitClick); subm4.Click += new EventHandler(MMCoordClick); subm5.Click += new EventHandler(MMChangeClick); subm6.Click += new EventHandler(MMRestoreClick); Глава 25. Создание Windows-приложений 705 // Назначаем меню форме. Menu = MyMenu; } [STAThread] public static void Main() { MenuForm skel = new MenuForm(); Application.Run(skel); } // Обработчик для команды меню Координаты. protected void MMCoordClick(object who, EventArgs e) { // Создаем строку, которая содержит три координаты. string size = string. Format(" {0}: {1}, {2}\n{3}: {4}, {5} ", "Вверху, Слева", Top, Left, "Внизу, Справа", Bottom, Right); // Отображаем окно сообщений. MessageBox.Show(size, "Координаты окна", MessageBoxButtons.OK); } // Обработчик для команды меню Изменить размер. protected void MMChangeClick(object who, EventArgs e) { Width = Height = 200; } // Обработчик для команды меню Восстановить. protected void MMRestoreClick(object who, EventArgs e) { Width = Height = 300; } // Обработчик для команды меню Открыть. protected void MMOpenClick(object who, EventArgs e) { MessageBox.Show("Неактивная команда", "Заглушка", MessageBoxButtons.OK); } // Обработчик для команды меню Закрыть. protected void MMCloseClick(object who, EventArgs e) { MessageBox.Show("Неактивная команда", "Заглушка", MessageBoxButtons.OK); } // Обработчик для команды меню Выйти. protected void MMExitClick(object who, EventArgs e) { DialogResult result = MessageBox.Show( "Остановить программу?", "Завершение", MessageBoxButtons.YesNo); if(result == DialogResult.Yes) Application.Exit(); } } Результат выполнения этой программы показан на рис. 25.5. 706 Часть III. Применение языка C# Рис. 25.5. Результат выполнения программы, использующей меню В этой программе определяется два раскрывающихся меню. Доступ к первому (оно содержит команды Открыть, Закрыть и Выйти) обеспечивается через меню Файл. Обработчики событий для элементов Открыть и Закрыть представляют собой заглушки, которые не выполняют никаких действий, кроме отображения окна сообщения. Обработчик элемента Выйти в собственном окне сообщения предлагает пользователю подтвердить его желание завершить программу. Если пользователь ответит щелчком на кнопке Да, программа будет завершена. Меню Сервис также содержит три элемента: Координаты, Изменить размер и Восстановить. При выборе команды Координаты в окне сообщения отображаются координаты верхнего левого и нижнего правого углов окна. Попробуйте переместить окно, а затем с помощью этой команды отобразите его координаты. При каждом перемещении окна в новую позицию его координаты будут изменяться соответствующим образом. При выборе команды Изменить размер окно программы уменьшается в размере так, чтобы его ширина и высота составляли 200 пикселей. Это реализуется с помощью свойств Width и Height : public int Width { get; set; } public int Height { get; set; } По умолчанию окно имеет размеры 300x300. При выборе команды Восстановить окно возвращается к своему исходному размеру. Что дальше Как упоминалось выше, Windows-программирование — очень обширная тема. Windows — это среда с богатыми возможностями, которая предъявляет к программисту большие требования. Если вы — новичок в Windows-программировании, то на его изучение может уйти несколько недель. Начать освоение этого материала можно со знакомства с элементами управления, определенными в пространстве имен System.Windows.Forms Необходимо также научиться обрабатывать Windows-сообщения, в частности те, которые запрашивают повторное отображение (перерисовку) окна. Другая важная подсистема, определенная в пространстве имен Windows.Drawing , включает различные классы, которые управляют отображением выходных данных в окне. Пространство имен Windows.Drawing инкапсулирует функции, предоставляемые интерфейсом графических устройств Windows GDI (Graphics Device Interface). Постарайтесь написать как можно больше коротких программ, чтобы понять суть каждого нового средства или метода. |