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

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

Аннотация: В лекции приводятся примеры работы с тремя новыми классами для организации пользовательского интерфейса управления приложением. Простое меню. Меню с флажками. Декларативное создание меню. Программирование меню. Меню с изображениями. Декларативная часть создания меню. Добавление пиктограмм к объектам команд. Загрузка рисунков через локальный файл ресурсов. Назначение рисункам свойств внедряемых ресурсов. Присоединение рисунка к свойству Image элемента меню через стандартный файл глобальных ресурсов проекта. Размещение рисунка в пользовательском файле глобальных ресурсов. Загрузка пиктограммы из файла рисунка во время выполнения. Динамическое присоединение пиктограмм к элементам меню. Создание элементов меню программным способом. Программирование узлов меню верхнего уровня. Программирование команд. Использование списка изображений для хранения пиктограмм меню. Создание файла ресурсов программным способом. Контекстное меню. Создание контекстного меню динамическим способом. Создание линейки контекстных меню декларативным способом.
Ключевые слова: strip, toolbar, ПО, global, Assembler, cache, меню, choose, список, dock, fill, объект, system, Windows, отображение, значение, коллекция объектов, массив, перегрузка метода, локальная переменная, поле класса, indeterminism, uncheck, опция, группа, класс, Menu, узел верхнего уровня, paint, конструктор класса, виртуальный метод, override, архив, переносимость, файл, оболочка, ресурс, Actions, embedding, resource, BMP, доступ, код программы, аргумент, имя файла, буфер, программный способ, позиционирование, курсор, magenta, цвет фона, cutting, этапы проектирования, файлы ресурсов, compilable, Persistence, compilation time, region, управление ресурсами, место, время компиляции, время выполнения, ресурс проекта, tagged, ссылочный тип, значимый тип, сигнатура, перегрузка, адресация, пользователь, exit, статические методы, индекс массива, переполнение, испытание, очередь, консольное приложение, бинарный файл, стартовый проект, виртуальное, свойство класса, orientation, horizontal, BorderStyle, интерфейс, присоединение

Файлы к лабораторной работе Вы можете скачать здесь.

В библиотеке .NET Framework 2.0 появились три новых класса для организации пользовательского интерфейса управления приложением ( Strip - полоса):

  • System.Windows.Forms.MenuStrip - главное меню
  • System.Windows.Forms.ToolStrip - панель инструментов
  • System.Windows.Forms.StatusStrip - панель состояния

Наряду с этими новыми элементами существуют и поддерживаются прежние аналогичные классы, существующие в версиях .NET Framework 1.x:

  • System.Windows.Forms.MainMenu
  • System.Windows.Forms.ToolBar
  • System.Windows.Forms.StatusBar

По умолчанию эти старые классы не подключены к панели Toolbox, поэтому не видны в ней, хотя и находятся в GAC (Global Assembly Cache). Но их легко подключить в любой свиток панели, вызвав для этого свитка контекстное меню и выполнив команду Choose Items

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

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

Заготовка приложения со стартовой формой

Мы еще не знаем, сколько упражнений получится в этой работе, поэтому применим список ListBox, в который можно добавлять сколько угодно опций вызова упражнений. При этом будем использовать рассмотренный ранее прием предотвращения запуска уже запущенной формы.

  • Выполните команду File/New/Project и заполните мастер создания приложения в соответствии с рисунком

  • Через панель Solution Explorer переименуйте файл Form1.cs в Start.cs, а заголовку окна формы присвойте значение Text =" Lab48 - Имя студента "
  • Поместите на форму библиотечный компонент ListBox и настройте его в соответствии с таблицей свойств
Таблица свойств экземпляра ListBox
Свойство Значение
Name listBoxChoice
Items Упражнение 1.
  Упражнение 2.
  Упражнение 3.
Dock Fill
  • Через панель Properties создайте обработчик для события SelectedIndexChanged объекта listBoxChoice, который заполните так
Form frm;   // Объявили поле
        private void listBoxChoice_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Привязали номер упражнения к индексу списка
            ListBox list = (ListBox)sender;
            string formName = "Form" + (list.SelectedIndex + 1);
    
            ///////////////////////////////////////////////////
            // Следующий код взят из лабораторной работы №47
            ///////////////////////////////////////////////////
            // Читаем коллекцию запущенных форм
            FormCollection fc = Application.OpenForms;
            bool IsRun = false;
            // Перебираем коллекцию
            foreach (Form form in fc)
            {
                // Имя очередной запущенной формы сравниваем с закрепленным за кнопкой
                if (form.Name == formName)
                {
                    IsRun = true;   // Нашли, что форма запущена, поднимаем флаг
                    frm = form;     // Сохраняем ссылку на запущенную форму для фокуса
                    break;          // Выходим из цикла
                }
            }
    
            // Если форма не запущена - запускаем
            if (!IsRun)
            {
                switch (formName)
                {
                    case "Form1":
                        frm = new Form1();
                        break;
                    case "Form2":
                        frm = new Form2();
                        break;
                    case "Form3":
                        frm = new Form3();
                        break;
                }
    
                this.AddOwnedForm(frm);     // Сделать новую frm подчиненной Start
                // frm.Owner = this;        // Алтернативный способ назначить владельца
                frm.ShowInTaskbar = false;  // Не отображать метку окна в панели задач
                frm.Show();                 // Показать новую форму
            }
            else
                frm.Focus();                // Передать фокус запущенной форме        
        }
Листинг 28.1. Обработчик события SelectedIndexChanged в файле Start.cs

Недостаток данного кода в том, что мы привязали вызов формы упражнения к индексу списка.

  • Командой меню оболочки Project/Add Windows Form добавьте в проект еще три формы с именами Form1, Form2, Form3
  • Запустите приложение и убедитесь в работоспособности механизма вызова отдельных упражнений

Упражнение 1. Простое меню

Рассмотрим простую программу, имитирующую работу меню.

  • Откройте файл Form1.cs в режиме View Code и добавьте к конструктору класса код создания простого меню
public Form1()
        {
            InitializeComponent();
    
            this.Text = "Простое меню";
    
            // Главное меню
            MenuStrip menu = new MenuStrip();
            this.Controls.Add(menu);
    
            // Раздел File
            ToolStripMenuItem itemFile = new ToolStripMenuItem();
            itemFile.Text = "&File";
            menu.Items.Add(itemFile);// Элемент верхнего уровня
    
            // Раздел Help
            ToolStripMenuItem itemHelp = new ToolStripMenuItem();
            itemHelp.Text = "&Help";
            menu.Items.Add(itemHelp);
    
            // Заполнение раздела File
            // Команда Open...
            ToolStripMenuItem itemOpen = new ToolStripMenuItem();
            itemOpen.Text = "&Open...";
            itemOpen.ShortcutKeys = Keys.Control | Keys.O; // Ctrl+O
            itemOpen.ShowShortcutKeys = true;// Отображать в команде
            // Регистрировать вручную!!!!!!!!!!!!!!
            itemOpen.Click += new EventHandler(itemOpen_Click);
            itemFile.DropDownItems.Add(itemOpen);
            // itemOpen.ShowShortcutKeys = false;// Скрыть комбинацию 
    
            // Разделитель
            ToolStripSeparator itemSep = new ToolStripSeparator();
            itemFile.DropDownItems.Add(itemSep);
    
            // Команда Exit
            ToolStripMenuItem itemExit = new ToolStripMenuItem();
            itemExit.Text = "E&xit";
            // Регистрировать вручную!!!!!!!!!!!!!!
            itemExit.Click += new EventHandler(itemExit_Click);
            itemFile.DropDownItems.Add(itemExit);
    
            // Заполнение раздела Help
            // Команда About...
            ToolStripMenuItem itemAbout = new ToolStripMenuItem();
            itemAbout.Text = "&About...";
            itemAbout.ShortcutKeys = Keys.Control | Keys.A; // Ctrl+A
            itemAbout.ShortcutKeyDisplayString = "Ctrl^A";// Свое отображение
            itemAbout.ShowShortcutKeys = true;// Отображать в команде
            // Регистрировать вручную!!!!!!!!!!!!!!
            itemAbout.Click += new EventHandler(itemAbout_Click);
            itemHelp.DropDownItems.Add(itemAbout);
        }
Листинг 28.2. Программа с меню в файле Form1.cs
  • Перепишите выделенные строки кода регистрации обработчиков события Click вручную, чтобы правильно создать заготовки обработчиков, и заполните обработчики следующим кодом
void itemAbout_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Заготовка опции \"About...\"", this.Text);
        }
    
        void itemExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    
        void itemOpen_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Заготовка опции \"Open\"", this.Text);
        }
    }
Листинг 28.3. Коды обработчиков выбора опций меню

В программе мы создаем объект меню, как экземпляр класса MenuStrip, и привязали его к объекту формы . У класса MenuStrip есть свойство Items, которое является коллекцией элементов меню верхнего уровня. Мы создаем два таких объекта itemFile и itemHelp типа ToolStripMenuItem и добавляем их в свойство Items. У каждого объекта типа ToolStripMenuItem есть свойство DropDownItems, готовое хранить коллекцию команд и разделителей, в том числе вложенных для построения меню сложной иерархии. В эти свойства элементов верхнего уровня мы добавляем объекты команд.

Схематично такая процедура построения меню примера изображена на рисунке

Символ амперсанда & в значении свойства Text наименования команды ассоциируется со знаком подчеркивания следующей за ним буквы и позволяет после нажатия клавиши Alt (не удерживая) вызывать команды простым нажатием соответствующих клавиш. Знак подчеркивания в работающей программе появляется только после щелчка на клавише Alt.

Свойство ShortcutKeys объекта команды ожидает побитовую комбинацию элементов перечисления System.Windows.Forms. Keys, задающую клавиши быстрого вызова этой команды. Логическое свойство ShowShortcutKeys объекта команды включает или выключает отображение заданной комбинации быстрого вызова справа от команды. По умолчанию задано значение true и комбинация клавиш отображается в том случае, если она назначена в свойстве ShortcutKeys. Свойство ShortcutKeyDisplayString позволяет задать иную строку отображения установленной комбинации, чем принято по умолчанию (например, вместо Ctrl+A по умолчанию можно задать Ctrl^A ).

Событие Click объекта команды возникает при выборе соответствующей команды и вызывает выполнение закрепленного обработчика.

Следует иметь ввиду, что как в коллекции Items меню верхнего уровня, так и в коллекциях DropDownItems выпадающих меню элементы отображаются в порядке их добавления в коллекцию. Свойства Items и DropDownItems являются экземплярами класса ToolStripItemCollection, который имеет метод Add(). Именно этим методом мы добавляем в коллекции объекты элементов меню. Сами элементы меню, добавляемые в коллекции, являются экземплярами класса ToolStripMenuItem.

Однако можно использовать и метод коллекции AddRange(), который ожидает ссылку на массив объектов команд. Так, например, пусть объекты itemFile, itemOpen, itemSep, itemExit уже созданы. Тогда к объекту верхнего уровня можно присоединить сразу все подчиненные объекты команд такой строкой кода:

itemFile.DropDownItems.AddRange(new ToolStripMenuItem[]{
            itemOpen, itemSep, itemExit});

Перегрузки метода Add() позволяют добавить команду меню вместе с текстом, текстом и изображением, текстом + изображением + именем обработчика события Click.

В коде упражнения есть один недостаток. Ссылки на команды меню объявляются внутри конструктора как локальные переменные. Если элементами меню нужно управлять из других мест программы, то эти переменные будут недоступны. Логичнее объявлять ссылки на элементы меню как поля класса.

Упражнение 2. Меню с флажками

В современных меню слева от команд находится столбец, в котором могут отображаться изображения или флажки. В этом упражнении рассмотрим управление флажками.

Появление флажка слева от команды включается булевым свойством Checked объекта команды. В качестве альтернативы можно установить свойство CheckState в одно из значений одноименного перечисления. Например для объекта itemOpen это можно определить так

  • itemOpen.CheckState = CheckState.Indeterminate ;
  • itemOpen.CheckState = CheckState.Checked ;
  • itemOpen.CheckState = CheckState.Unchecked ;

Опция Indeterminate позволяет отобразить неопределенное состояние, когда на месте флажка помещается точка.

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

В этом упражнении мы создадим меню Font, которое будет выводить список шрифтов, поддерживаемых компьютером. Обычно у современных операционных систем этот список большой и не помещается на экране, поэтому будем использовать объект класса ToolStripDropDownMenu. Этот класс отвечает за появление стрелок, позволяющих перемещаться по меню, не вмещающему команды. Здесь мы используем создание и настройку меню частично в декларативном, частично в программном режиме. Ну уж а управление логикой работы меню можно выполнить только в программном режиме.

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000