Для создания дочерних окон обычно определяется форма-прототип, играющая роль основы для каждого дочернего окна. Поскольку Form является типом класса, любые приватные данные, определенные в дочерней форме, будут для конкретного экземпляра уникальными. Например, при созданий MDI-приложения текстового редактора для отображения текста можно создать дочернюю форму, поддерживающую StringBuilder. Если пользователь создаст пять новых дочерних окон, каждая соответствующая форма будет поддерживать свой собственный экземпляр StringBuilder, которыми можно будет управлять независимо.
Кроме того, MDI-приложения позволяют "объединять" меню. Как уже упоминалось, родительские окна обычно имеют свои системы меню, которые позволяют пользователю создавать и упорядочивать дополнительные дочерние окна. Но что будет в том случае, когда дочернее окно имеет свою систему меню? Если пользователь максимизирует конкретное дочернее окно, то система меню этого дочернего окна должна "поглотиться" родительской формой, чтобы пользователь получил возможность активизировать элементы каждой из имеющихся систем меню. Пространство имен Windows Forms определяет ряд свойств, методов и событий, позволяющих программное слияние систем меню. Имеется также система "слияния по умолчанию", которая оказывается вполне подходящей во многих типичных случаях.
Создание родительской формы
Для демонстрации основ процесса построения MDI-приложения создайте новое приложение Windows, назвав его SimpleMdiApp. При этом почти вся MDI-ин-фраструктура может быть назначена исходной форме с помощью различных инструментов проектирования. Сначала найдите свойство IsMdiContainer в окне свойств и установите его равным true (истина). В результате в окне проектирования формы область клиента изменится – теперь она будет визуально представлять контейнер дочернего окна.
Затем разместите в главной форме новый элемент управления MenuStrip. В этом меню укажите три элемента высшего уровня с названиями Файл, Окно и Упорядочить окна. Меню Файл содержит два подчиненных элемента с названиями Создать и Выход. Меню Окно не содержит никаких подчиненных элементов, потому что при создании пользователем дополнительных дочерних окон новые элементы предполагается добавлять программно. Наконец, меню Упорядочить окна определяет три подчиненных элемента с названиями Каскадом, По вертикали и По горизонтали.
После создания меню пользовательского интерфейса обработайте событие Click для пунктов меню Выход, Создать, Каскадом, По вертикали и По горизонтали (напомним, что меню Окно пока что не имеет никаких подчиненных элементов). Обработчик элемента Файл→Создать мы реализуем в следующем разделе главы, а сейчас рассмотрим программный код для остальных элементов меню.
// Обработка события Файл | Выход и упорядочение дочерних окон.
private void cascadeToolStripMenuItem_Click(object sender, EventArgs e) {
LayoutMdi(MdiLayout.Cascade);
}
private void verticalToolStripMenuItem_Click(object sender, EventArgs e) {
LayoutMdi(MdiLayout.TileVertical);
}
private void horizontalToolStripMenuItem_Click(object sender, EventArgs e) {
LayoutMdi(MdiLayout.TileHorizontal);
}
private void exitToolStripMenuItem_Click (object sender, EventArgs e) {
Application.Exit();
}
Наибольший интерес здесь представляет использование метода LayoutMdi() и соответствующего перечня MdiLayout. Программный код обработки выбора каждого из элементов меню должен быть вам понятен. При выборе элемента пользователем вы даете указание родительской форме выполнить автоматическое размещение всех дочерних окон.
Перед тем как перейти к обсуждению процесса создания дочерних форм, установите еще одно свойство MenuStrip. Свойство MdiWindowListItem используется доя того, чтобы выяснить, какой пункт меню наивысшего уровня должен использоваться для автоматического списка имен всех дочерних икон при соответствующем выборе из меню. Присвойте значение этого свойства члену-переменной windowToolStripMenuItem. По умолчанию для этого списка используется значение дочернего свойства Text с числовым суффиксом (т.е. Form1, Form2, Form3 и т.д.).
Создание дочерней формы
Теперь, когда у вас есть оболочка MDI-контейнера, нужно создать дополнительную форму, выполняющую роль прототипа для данного дочернего окна. Начните со вставки нового типа Form в имеющийся проект (используйте Project→Add Windows Form), присвойте этому типу имя ChidPrototypeForm и обработайте для него событие Сlick. В сгенерированном обработчике события путем случайного выбора установите цвет фона для области клиента. Кроме того, выведите "преобразованное в строку" значение Color (цвет) нового объекта в полосу заголовка дочернего окна. Следующая программная логика реализует поставленные задачи.
private void ChildPrototypeForm_Click(object sender, EventArgs e)
// Получение трех случайных чисел.
int r, g, b;
Random ran = new Random();
r = ran.Next(0, 255);
g = ran.Next(0, 255);
b = ran.Next(0, 255);
// Создание цветового значения для фона.
Color currColor = Color.FromArgb(r, g, b);
this.BackColor = currColor;
this.Text = currColor.ToString();
}
Создание дочерних окон
Заключительным шагом должно быть создание подходящей реализации обработчика событий Файл→Создать родительской формы. Теперь, когда дочерняя форма определена, соответствующая программная логика оказывается очень простой: нужно создать и отобразить новый экземпляр типа ChildPrototypeForm. Кроме того, нужно установить значение свойства MdiParent дочерней формы, указывающее на содержащую ее форму (в данном случае это ваше главное окно). Вот как должны выглядеть соответствующие модификации программы.
private void newToolStripMenuItem_Сlick(object sender, EventArgs e) {
// Создание нового дочернего окна.
ChildPrototypeForm newChild = new ChildPrototypeForm();
// Ссылка на родительскую форму для данного дочернего окна.
newChild.MdiParent = this;
// Отображение новой формы.
newChild.Show();
}
Замечание. Дочерняя форма имеет возможность использовать свойство MdiParent непосредственно, когда требуется выполнить какие-то действия (или организовать сообщение) с родительским окном.
При тестировании этого приложения начните с создания нескольких дочерних окон и, щелкнув на каждом из них, создайте уникальные цвета для их фона, Если теперь рассмотреть подчиненные элементы меню Окно, вы должны обнаружить, что там представлена и учтена каждая дочерняя форма. Точно так же с помощью элементов меню Упорядочить окна вы можете дать указание родительской форме разместить дочерние формы по вертикали, горизонтали или каскадом. На рис. 19.26 показано окно готового приложения.
Рис. 19.26. Окно MDI-приложения
Исходный код. Проект SimpleMdiApp размещен в подкаталоге, соответствующем главе 19.
Резюме
Эта глава рассказывает об основах построения графического интерфейса с помощью типов, содержащихся в пространстве имен System.Windows.Forms. Сначала вам предлагается создать несколько приложений вручную, и в процессе этого выясняется, что GUI-приложение, как минимум, должно иметь класс, производный от Form, и метод Main(), вызывающий Application.Run().
В этой главе показано, как строить меню верхнего уровня (а также всплывающие меню) и как обрабатывать события меню. Было также выяснено, как можно расширить функциональные возможности типа Form с помощью панелей инструментов и строк состояния. В .NET 2.0 при создании таких элементов пользовательского интерфейса предлагается использовать MenuStrip, ToolStrip и StatusStrip, а не типы MainMenu, ToolBar и StatusBar из .NET 1.x (хотя эти, уже устаревшие типы, тоже поддерживаются). В завершение главы было продемонстрировано, как с помощью средств Windows Forms можно создавать MDI-приложения.
ГЛАВА 20. Визуализация графических данных средствами GDI+
Предыдущая глава предлагала вводное описание процесса построения GUI-приложений с помощью System.Windows.Forms. Целью этой главы является рассмотрение возможностей визуализации графических данных в окне формы (включая как вывод изображений, так и вывод текста различными стилями). Мы начнем с общего рассмотрения пространств имен, связанных с выводом графических данных, ради события Paint и "всемогущего" объекта Graphics.
Остальная часть этой главы будет посвящена способам манипуляции цветами, шрифтами, геометрическими формами и графическими образами. В этой главе также исследуется ряд программных подходов, связанных с визуализацией графических данных, например, таких как проверка доступа пользователя к непрямоугольным областям экрана, логика перетаскивания объектов и формат ресурсов .NET. И хотя, строго говоря, это не относится к GDI+ непосредственно, при операциях с ресурсами нередко приходится использовать манипуляции графическими данными (что оказывается достаточно важным для того, чтобы представить соответствующий материал здесь).