Стандартные меню приложений
Декларативное создание меню
- Откройте форму Form2 в режиме View Designer и поместите из панели Toolbox на форму экземпляр компонента MenuStrip с именем menu
- При выделенном элементе меню в панели Properties раскройте свойство Items
- В окне редактора меню выберите из раскрывающегося списка элемент MenuItem и щелчком на кнопке Add добавьте в коллекцию Items узел верхнего уровня
- Присвойте добавленному элементу через таблицу свойств редактора меню Name = itemFormat, Text = &Format и щелчком на кнопке OK завершите редактирование
- При выделенном элементе ItemFormat в панели Properties раскройте свойство DropDownItems
- В окне редактора меню выберите из раскрывающегося списка элемент MenuItem и щелчком на кнопке Add добавьте в коллекцию DropDownItems объект команды меню
- Присвойте добавленному элементу через таблицу свойств редактора меню Name = itemFont, Text = &Font и щелчком на кнопке OK завершите редактирование
- Выполните приложение и проверьте работоспособность Form2 на данном этапе
- Поместите из панели Toolbox экземпляр элемента Panel и настройте его свойства так:
- Выделите объект panel и через панель Properties в режиме Events зарегистрируйте для события Paint обработчик и именем PanelOnPaint
На этом декларативная часть работы закончена. Далее займемся программной частью.
Программирование меню
- Перейдите в режим View Code формы Form2 и добавьте перед конструктором класса Form2 объявление ссылки на элемент меню
public partial class Form2 : Form { // Объявили поле-ссылку на объект команды меню ToolStripMenuItem itemSelectedFont; public Form2() { InitializeComponent(); } private void PanelOnPaint(object sender, PaintEventArgs e) { } }Листинг 28.5. Добавление поля-ссылки на экземпляр элемента меню
- Добавьте в конструктор класса Form2 после вызова функции инициализации компонентов код динамического заполнения списка команд в коллекцию команды Font
public Form2() { InitializeComponent(); // Заполнение коллекции объекта itemFont // списком доступных шрифтов стиля "Обычный" Graphics gr = CreateGraphics(); // Ссылка на контекст устройства // Читаем все шрифты FontFamily[] fonts = FontFamily.GetFamilies(gr); // Перебираем шрифты и формируем команды меню Font foreach (FontFamily font in fonts) { // Выбираем шрифты одного стиля "Обычный" if (font.IsStyleAvailable(FontStyle.Regular)) { // Добавляем в коллекцию команды Font ToolStripMenuItem item = (ToolStripMenuItem)itemFont.DropDownItems.Add(font.Name); // Если встретился текущий шрифт формы, // запоминаем эту команду и отмечаем флажком if (font.Name == this.Font.Name) { itemSelectedFont = item; itemSelectedFont.Checked = true; } } } gr.Dispose(); // Освобождаем ограниченный ресурс }Листинг 28.6. Код динамического формирования команд меню в конструкторе класса Form2
- Запустите приложение и удостоверьтесь, что при раскрытии команды меню Font она уже заполнена элементами названий шрифтов
Теперь обеспечим нужную функциональность выбора шрифтов и отображения их названия на клиентской области панели panel.
- Подпишите добавленный в коллекцию команды Font элемент item на событие Click. Для этого наберите вручную!!!, чтобы правильно создать обработчик, следующий код в конце условия if
public Form2() { .................................................... // Перебираем шрифты и формируем команды меню Font foreach (FontFamily font in fonts) { // Выбираем шрифты одного стиля "Обычный" if (font.IsStyleAvailable(FontStyle.Regular)) { ............................................... // Следующую строчку введите вручную!!! item.Click += new EventHandler(item_Click); } } gr.Dispose(); // Освобождаем ограниченный ресурс }Листинг 28.7. Регистрация обработчика для события Click в динамически формируемой команде
- Заполните обработчик item_Click() следующим кодом, который будет сбрасывать флажок с выбранного ранее шрифта и устанавливать его на новом выбранном шрифте
void item_Click(object sender, EventArgs e) { // Повышаем полномочия ссылки для адресации к выделенной команде ToolStripMenuItem item = (ToolStripMenuItem)sender; itemSelectedFont.Checked = false; // Сбрасываем предыдущий флажок item.Checked = true; // Поднимаем новый флажок itemSelectedFont = item;// Запоминаем отмеченную команду panel.Invalidate(); // Перерисовываем панель с новым шрифтом }Листинг 28.8. Код обработчика выделения нового шрифта в классе Font2
- Найдите созданный ранее обработчик события Paint панели и заполните его кодом перерисовки панели с новым шрифтом
private void PanelOnPaint(object sender, PaintEventArgs e) { Graphics gr = e.Graphics; // Получаем контекст устройства // Создаем новый шрифт по выбранному в меню с заведомо // большим размером, чтобы потом подогнать уменьшением float emSize = 100.0F; System.Drawing.Font font = new Font(itemSelectedFont.Text.Trim(), emSize); String str = font.Name; // Строка для рисования // Подгоняем размер текстового блока под ширину формы float widthText = gr.MeasureString(str, font = new Font(itemSelectedFont.Text, emSize)).Width; while ((panel.ClientSize.Width - widthText) < 0.0F) { emSize -= 0.5F; widthText = gr.MeasureString(str, font = new Font(itemSelectedFont.Text, emSize)).Width; } // Настроим точку привязки текстового блока System.Drawing.StringFormat fmt = new StringFormat(); fmt.Alignment = StringAlignment.Center; // По горизонтали fmt.LineAlignment = StringAlignment.Center; // По вертикали // Настроим точку привязки клиентской области панели PointF point = new PointF(panel.ClientSize.Width / 2, panel.ClientSize.Height / 2); // Рисуем на панели название выбранного шрифта текущим цветом формы gr.DrawString(str, font, new SolidBrush(this.ForeColor), point, fmt); }Листинг 28.9. Код обработчика перерисовки панели в классе Form2
- В классе Form2 переопределите унаследованный виртуальный метод диспетчеризации OnResize() (ввод начните с ключевого слова override ) и заполните его следующим кодом
protected override void OnResize(EventArgs e) { panel.Invalidate(); base.OnResize(e); }Листинг 28.10. Переопределенный метод диспетчеризации события Resize формы
Этот метод нужен для перерисовки панели внутри формы при изменении пользователем ее размеров.
- Запустите Form2 и удостовертесь в ее работоспособности, результат будет таким
Обратите внимание, что мы обеспечили центрирование текста на панели и автоматическую его подгонку под размеры формы.
Упражнение 3. Меню с изображениями
Хотя информативность названий команд меню может оказаться достаточной, в современных меню применяются еще и смысловые пиктограммы. Это нужно для того, чтобы постепенно приучить пользователя к изображениям команд и безболезненно перевести его на более быстрый способ использования кнопок панели инструментов с теми же самыми изображениями.
Если распаковать этот архив, то используемые в меню изображения хранятся в папке bitmaps/commands, рассортированные по разной глубине цвета. Если в Вашей системе нет этих пиктограмм, то их можно найти в прилагаемом к данной лабораторной работе каталоге Source.
Служебные изображения в программе удобнее использовать как ресурсы, внедренные в исполнимую сборку и переносимые вместе с этой сборкой. Файл изображения добавляется к проекту командой Project/Add Existing Item, после чего оболочка физически скопирует его в каталог размещения проекта и он появится в панели Solution Explorer.
Далее можно использовать один из способов превращения этого файла в ресурс приложения: выделить этот файл и через панель Properties установить для него опцию Build Action равной Embedded Resource. Это заставит оболочку при компиляции внедрять указанный файл как ресурс в сборку приложения. Внутри самого кода приложения мы можем адресоваться к этому файлу.
Пусть, например, мы хотим использовать пиктограмму Open.bmp и добавили этот файл в проект. Доступ к изображению из кода программы можно осуществить разными способа, например, с помощью следующего кода
Bitmap bmCut = new Bitmap(this.GetType(), "path.Open.bmp");
Первый аргумент должен ссылаться на класс приложения, в нашем случае это порождающий класс текущего объекта. Второй аргумент, это имя файла изображения с путем относительно корневой папки проекта
Присоединить изображение к элементу меню можно присвоением ссылки свойству Image соответствующей команды, например
itemCut.Image = bmCut;
После таких действий пиктограмма элемента будет отображаться слева от текста меню на месте отображения флажка.
В данном упражнении разработаем простой редактор изображений, в котором можно будет загружать и сохранять файлы изображений, использовать буфер обмена и отображать рисунки несколькими способами. При этом задействуем ряд стандартных диалоговых окон. Для тренировки рассмотрим несколько способов загрузки изображений в элементы меню.
- Откройте файл Form3.cs в режиме View Designer и задайте свойству Text формы значение " Простой редактор изображений "
- Поместите на форму компонент PictureBox и настройте его так: Name = pictureBox, Dock = Fill
В дальнейшем экземпляр элемента управления PictuteBox будет служить контейнером при просмотре изображений в нашем законченном упражнении.
Декларативная часть создания меню
Меню для нашего упражнения мы создадим, чередуя декларативный и программный способ. Мы с вами знаем, что при декларативном способе создания объектов работу по написанию кода за нас выполняет оболочка в закулисной части класса формы, который имеет расширение Designer.cs. По большому счету разницы нет, как создавать код: с помощью графического инструмента или непосредственно вручную. Главное знать, что писать и как позиционировать объекты. При создании меню проблемы с позиционированием не возникает, главное - порядок следования компонентов. Но познакомиться с графическими возможностями оболочки по созданию меню не помешает.
- Поместите на форму компонент MenuStrip с именем menu и настройте его декларативно в соответствии с приведенным ниже деревом свойств
Создавать декларативным способом новые элементы меню любого уровня удобнее, если навести курсор справа от заготовки команды и раскрыть список предлагаемых типов, затем выделенный элемент меню можно настроить через панель Properties.