Шаг 281.
Язык программирования C#. Начала.
Приложения с графическим интерфейсом. Контекстное меню

    На этом шаге мы рассмотрим создание и настройку такого меню.

    Далее мы познакомимся с контекстным меню. Это меню, которое открывается при щелчке правой кнопкой мыши на компоненте. В следующей программе создается и отображается окно традиционно с изображением животного. Окно представлено на рисунке 1.


Рис.1. При первом отображении окна оно содержит изображение волка, флажок опции установлен, а поле ввода заблокировано

    В центральной части окна сначала появляется изображение волка. Если щелкнуть правой кнопкой мыши на изображении, появляется контекстное меню из четырех команд, названия которых совпадают с названиями животных. Ситуация проиллюстрирована на рисунке 2.


Рис.2. Выбор команды в контекстном меню изображения

    Выбрав команду в контекстном меню, мы меняем изображение в окне. Одновременно с изображением меняется и заголовок окна. На рисунке 3 показан результат, который получим при выборе команды Лиса в контекстном меню.


Рис.3. В результате выбора команды в контекстном меню меняется изображение и заголовок окна

    Кроме изображения, в окне под изображением есть опция Заблокировать поле и поле ввода над изображением. При установленном флажке опции поле заблокировано (выделено серым цветом и недоступно для ввода). Если отменить флажок для опции, то в поле можно вводить текст, как показано на рисунке 4.


Рис.4. Пока в поле ввода не указано корректное название животного, изображение в окне не меняется

    Как только в поле ввода будет введено название животного (Волк, Лиса, Медведь или Енот), в окне изменится изображение животного и заголовок окна. На рисунке 5 показано, как выглядит окно, если в текстовое поле ввести слово Енот.


Рис.5. При вводе в текстовое поле корректного названия животного, его изображение появляется в окне

    Если установить флажок опции, то поле снова станет неактивным, а текст из поля будет удален. Как и ранее, мы можем выбрать команду из контекстного меню. На рисунке 6 показано, как при активном текстовом поле в контекстном меню выбирается команда Медведь.


Рис.6. Выбор команды из контекстного меню при активном поле ввода

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


Рис.7. После выбора команды из контекстного меню меняется изображение и заголовок окна, устанавливается флажок опции и блокируется поле ввода

    Далее мы проанализируем программный код программы, который представлен ниже.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;
using System.Windows.Forms;

namespace pr281_1
{
    // Класс окна: 
    class MyForm: Form {
        // Ссылка на текстовое поле: 
        private TextBox tb;
        // Ссылка на метку: 
        private Label lbl;
        // Закрытый метод для проверки названия животного: 
        private bool checkIt(string name) { 
            switch(name) { 
                case "Волк": 
                case "Лиса": 
                case "Медведь": 
                case "Енот": 
                    return true; 
                default:
                    return false;
            }
        }
        // Закрытый метод для определения по названию животного 
        // названия файла с изображением: 
        private string getFile(string name) {
            string path=""; 
            string res=""; 
            switch(name){ 
                case "Волк":
                    res = "wolf.jpg";
                    break;
                case "Лиса": 
                    res = "fox.jpg"; 
                    break;
                case "Медведь": 
                    res = "bear.jpg"; 
                    break;
                case "Енот":
                    res = "raccoon.jpg";
                    break;
            }
            return path + res;
        }
        // Конструктор: 
        public MyForm(): base() {
            // Локальные переменные: 
            int H = 104; 
            int W = 154;
            // Размеры окна: 
            this.Width = W + 25; 
            this.Height = 240;
            // Шрифт для окна:
            this.Font = new Font("Arial", 9, FontStyle.Bold);
            // Окно постоянных размеров:
            this.FormBorderStyle = FormBorderStyle.FixedToolWindow; 
            // Начальное положение окна: 
            this.StartPosition = FormStartPosition.CenterScreen;
            // Объект текстового поля: 
            tb = new TextBox();
            // Положение текстового поля: 
            tb.Location = new Point(5, 5);
            // Ширина текстового поля: 
            tb.Width = W;
            // Шрифт для текстового поля:
            tb.Font = new Font("Courier New", 12, FontStyle.Bold);
            // Обработчик события, связанного с отпусканием
            // клавиши на клавиатуре:
            tb.KeyUp += (x, y) => {
                // Если в поле название животного: 
                if (checkIt(tb.Text)) {
                    // Заголовок окна: 
                    this.Text = tb.Text;
                    // Изображение для метки:  
                    lbl.Image = Image.FromFile(getFile(tb.Text));
                }
            };
            // Добавление поля в окно: 
            this.Controls.Add(tb);
            // Объект метки: 
            lbl = new Label();
            // Положение и размеры метки:
            lbl.Top = tb.Bottom + 5;
            lbl.Left = 5;
            lbl.Size = new Size(W, H);
            // Рамка для метки:
            lbl.BorderStyle = BorderStyle.FixedSingle;
            // Добавление метки в окно: 
            this.Controls.Add(lbl);
            // Объект опции:
            CheckBox option = new CheckBox();
            // Размеры и положение опции:
            option.Width = W;
            option.Height = 20;
            option.Left = 5;
            option.Top = lbl.Bottom + 5;
            // Подпись для опции: 
            option.Text = "Заблокировать поле";
            // Обработчик для события, связанного с изменением 
            // состояния опции: 
            option.CheckedChanged += (x, y) => {
                // Доступность поля для ввода текста: 
                tb.Enabled = !option.Checked;
                // Очистка содержимого поля: 
                tb.Text = "";
            };
            // Добавление опции в окно: 
            this.Controls.Add(option);
            // Объект контекстного меню:
            ContextMenuStrip menu = new ContextMenuStrip();
            // Добавление команд в контекстное меню: 
            menu.Items.Add("Волк"); 
            menu.Items.Add("Лиса"); 
            menu.Items.Add("Медведь"); 
            menu.Items.Add("Енот");
            // Перебор элементов из контекстного меню: 
            for(int k = 0; k < menu.Items.Count; k++) {
                // Обработчик для команды из контекстного меню: 
                menu.Items[k].Click += (x, y) => {
                    // Название команды:
                    string txt = ((ToolStripMenuItem)x).Text;
                    // Изображение для метки: 
                    lbl.Image = Image.FromFile(getFile(txt));
                    // Заголовок окна: 
                    this.Text = txt;
                    // Устанавливается флажок опции:
                    option.Checked = true;
                };
            }
            // Контекстное меню для метки: 
            lbl.ContextMenuStrip = menu;
            // Объект кнопки:
            Button btn = new Button();
            // Название кнопки: 
            btn.Text = "OK";
            // Положение и размеры кнопки: 
            btn.SetBounds(5, option.Bottom + 5, W ,30);
            // Обработчик для события, связанного со щелчком
            // по кнопке:
            btn.Click += (x, y) => {
                Application.Exit();
            };
            // Добавление кнопки в окно: 
            this.Controls.Add(btn);
            // Программный щелчок на первой команде 
            // из контекстного меню: 
            menu.Items[0].PerformClick();
        }
    }

    // Главный класс: 
    class Program
    {
        [STAThread]
        // Главный метод: 
        static void Main()
        {
            // Отображение окна с полем ввода: 
            Application.Run(new MyForm());
        }
    }
}
Архив проекта можно взять здесь.

    В классе окна MyForm есть закрытое поле tb класса TextBox (ссылка на текстовое поле) и закрытое поле lbl класса Label (ссылка на метку). Также в классе описан закрытый метод checkIt(), аргументом которому передается текстовое значение, а результатом метод возвращает логическое значение true или false в зависимости от того, является ли переданный текст названием животного или нет (допускаются варианты "Волк", "Лиса", "Медведь" и "Енот").

    В классе есть закрытый метод getFile() для определения по названию животного (аргумент метода) названия файла с изображением (результат метода). Причем возвращается текст с полным путем к файлу.


Если аргументом методу getFile() передать текст, который не является названием животного (имеются в виду названия "Волк", "Лиса", "Медведь" или "Енот"), то результатом метод возвращает текстовую строку с путем к каталогу с файлами изображений. Но поскольку в программе этот метод вызывается только в случае, если аргумент является названием животного, то проблем не возникает.

    В конструкторе класса задаются размеры и начальное положение окна, шрифт для окна, а также командой

  this.FormBorderStyle = FormBorderStyle.FixedToolWindow; 
определяется тип окна. Это окно постоянных размеров без пиктограмм минимизации и максимизации окна (в правом верхнем углу есть только одна системная пиктограмма для закрытия окна).

    Также в конструкторе создается объект для текстового поля. Определяется положение поля и его ширина, задается шрифт для поля (высота поля автоматически определяется на основе шрифта). Для поля регистрируется обработчик события, связанного с отпусканием клавиши на клавиатуре (событие происходит, если поле активно и пользователь отпускает ранее нажатую клавишу). Для этого в список обработчиков события KeyUp объекта поля tb добавляется ссылка на анонимный метод, реализованный с помощью лямбда-выражения. В теле метода в условной конструкции проверяется условие checkIt(tb.Text). Условие истинно, если в текстовом поле содержится название животного. Если так, то командой

  this.Text = tb.Text;
содержимое текстового поля становится заголовком окна. Затем командой
  lbl.Image = Image.FromFile(getFile(tb.Text));
определяется изображение для метки. В этом случае по названию животного в текстовом поле определяется название файла с изображением (инструкция getFile(tb.Text)), и оно передается аргументом методу FromFile().

    Помимо перечисленного выше, в конструкторе создается метка, определяются ее параметры, а также создается опция. Для опции определяется обработчик события, связанного с изменением состояния опции: в список обработчиков для события CheckedChanged объекта опции option добавляется ссылка на анонимный метод, реализованный с помощью лямбда-выражения. В теле метода командой

  tb.Enabled = !option.Checked;
определяется значение свойства Enabled текстового поля. Если значение свойства равно true, то поле доступно для ввода текста. Если значение свойства равно false, то поле заблокировано. В данном случае значение свойства Enabled противоположно значению свойства Checked опции.


То есть если опция установлена, то поле заблокировано, а если опция не установлена, то поле доступно для редактирования.

    Также командой

  tb.Text = "";
содержимое поля «обнуляется»: в поле записывается пустой текст.

    Для контекстного меню на основе класса ContextMenuStrip создается объект menu. Для добавления команд в контекстное меню из свойства Items объекта меню вызывается метод Add(), аргументом которому передается текст с названием команды. Для каждой команды определяется обработчик события, связанного со щелчком на команде меню. Для перебора элементов (команд) из контекстного меню используем цикл. Команды контекстного меню образуют коллекцию, ссылку на которую получаем с помощью свойства Items объекта меню menu. У свойства Items есть свойство Count, возвращающее в качестве значения количество элементов (команд) в коллекции. В конструкции цикла индексная переменная k пробегает значения индексов элементов в коллекции. На каждой итерации цикла в список обработчиков события Click элемента Items[k] добавляется ссылка на анонимный метод, реализованный с помощью лямбда-выражения. В лямбда-выражении командой

  string txt = ((ToolStripMenuItem)x).Text;
в текстовую переменную txt записывается название команды, на которой произошло событие (на которой был выполнен щелчок).


В лямбда-выражении первый аргумент (обозначен как х) обозначает объект компонента, на котором произошло событие. В соответствии с определением делегата EventHandler этот аргумент относится к классу object. Мы знаем, что этот объект - команда контекстного меню. Поэтому объект приводится к типу ToolStripMenuItem (инструкция (ToolStripMenuItem)x). Свойство Text этого объекта - это название команды, что нам и нужно.

    Командой

  lbl.Image = Image.FromFile(getFile(txt));
задается изображение для метки. Заголовок окна определяем командой
  this.Text = txt;                  . 
С помощью команды
  option.Checked = true; 
устанавливается флажок опции (при этом выполняется обработка события, связанного с изменением статуса опции). Чтобы созданное меню стало контекстным меню метки с изображением, используем команду
  lbl.ContextMenuStrip = menu;
(свойству ContextMenuStrip в качестве значения присваивается ссылка на объект контекстного меню).

    Также мы создаем объект кнопки, задаем ее параметры и определяем обработчик события, связанного со щелчком по кнопке. Компоненты (поле, метка, опция и кнопка) добавляются в окно, после чего командой

  menu.Items[0].PerformClick();
выполняется программный щелчок на первой команде из контекстного меню. В результате в окне появляется изображение волка и выполняются прочие сопутствующие настройки. В главном методе создается и отображается окно.

    На следующем шаге мы рассмотрим получение координат курсора мыши.




Предыдущий шаг Содержание Следующий шаг