Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 28:

Стандартные меню приложений

Декларативное создание меню

  • Откройте форму 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 и настройте его свойства так:
    • Name = panel, Dock = Fill
  • Выделите объект 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. Меню с изображениями

Хотя информативность названий команд меню может оказаться достаточной, в современных меню применяются еще и смысловые пиктограммы. Это нужно для того, чтобы постепенно приучить пользователя к изображениям команд и безболезненно перевести его на более быстрый способ использования кнопок панели инструментов с теми же самыми изображениями.

В поставку оболочки Visual Studio 2005 Standard Edition входит архив с большим набором готовых пиктограмм, который после установки на компьютере находится в каталоге C:\Program Files\Microsoft Visual Studio 8\Common7\VS2005ImageLibrary

Если распаковать этот архив, то используемые в меню изображения хранятся в папке 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.


Александр Очеретяный
Александр Очеретяный
Украина, Киев
Анастасия Балыбердина
Анастасия Балыбердина
Украина, Киев, НТУУ КПИ