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

    На этом шаге мы рассмотрим пример использования таких компонентов.

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


Рис.1. Окно с группой переключателей и изображением волка

    Теперь в правой части окна вместо списка размещена группа переключателей. Установлен (выбран) может быть один и только один из них. В соответствии с тем, какой переключатель установлен, в области метки отображается картинка с изображением животного. На рисунке 2 показано окно с изображением медведя (в соответствии с выбранным переключателем).


Рис.2. Окно с группой переключателей и изображением медведя

    Переключатель реализуется как объект класса RadioButton. Особенность переключателей в том, что они объединяются в группы и в группе может быть установлен только один переключатель. Поэтому мало собственно создать переключатели. Их еще нужно сгруппировать. Для этого создается объект для группы переключателей. Такой объект создается на основе класса GroupBox. Все переключатели, добавленные в объект группы, образуют группу переключателей.

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

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

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

namespace pr278_1
{
    // Класс для кнопки: 
    class MyButton: Button {
        // Конструктор:
        public MyButton(string name): base() {
            // Название кнопки: 
            this.Text = name;
            // Обработчик события, связанного со щелчком
            // по кнопке:
            this.Click += (x, y) => {
                Application.Exit();
            };
        }
    }

    // Класс окна: 
    class MyForm: Form {
        // Названия животных:
        private string[] animals = {"Волк", "Лиса", "Медведь", "Енот"};
        // Названия файлов с изображениями:
        private string[] files = {"wolf.jpg", "fox.jpg", "bear.jpg", "raccoon.jpg"};
        // Путь к каталогу с файлами изображений: 
        private string path="";
        // Индекс переключателя, который установлен в начале: 
        private int index = 0;
        // Ссылка на метку: 
        private Label pict;
        // Массив ссылок на переключатели: 
        private RadioButton[] radio;
        // Конструктор: 
        public MyForm(): base() {
            // Ширина окна:  
            this.Width = 310;
            // Высота окна: 
            this.Height = 200;
            // Режим явного определения начального 
            // положения окна:
            this.StartPosition = FormStartPosition.Manual;
            // Координаты окна: 
            this.Location = new Point(400, 300);
            // Заголовок окна: 
            this.Text = "B мире животных";
            // Окно фиксированных размеров: 
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            // Окно нельзя развернуть на весь экран: 
            this.MaximizeBox = false;
            // Объект панели:
            Panel pnl = new Panel();
            // Ширина панели:
            pnl.Width = this.ClientSize.Width - 10;
            // Высота панели:
            pnl.Height = this.ClientSize.Height - 10;
            // Горизонтальная координата панели: 
            pnl.Left = 5;
            // Вертикальная координата панели: 
            pnl.Top = 5;
            // Рамка вокруг панели: 
            pnl.BorderStyle = BorderStyle.FixedSingle;
            // Объект метки: 
            pict = new Label();
            // Положение и размеры метки: 
            pict.SetBounds(5, 5, 154, 104);
            // Рамка вокруг метки: 
            pict.BorderStyle = BorderStyle.FixedSingle;
            // Начальное изображение для метки: 
            pict.Image = Image.FromFile(path + files[index]);
            // Добавление метки на панель: 
            pnl.Controls.Add(pict);
            // Создание массива ссылок на объекты переключателей: 
            radio = new RadioButton[animals.Length];
            // Объект для группы переключателей:
            GroupBox gb = new GroupBox();
            // Координаты группы переключателей:
            gb.Left = pict.Right + 5;
            gb.Top = pict.Top;
            // Размеры группы переключателей:
            gb.Width = 115;
            gb.Height = pict.Height;
            // Заголовок для группы переключателей: 
            gb.Text = "Ваш выбор";
             // Шрифт для группы переключателей: 
            gb.Font = new Font("Courier New", 12, FontStyle.Bold);
            // Высота области для переключателя: 
            int h = 17;
            // Создание объектов для переключателей и добавление 
            // переключателей в группу: 
            for(int k = 0; k < radio.Length; k++) {
                // Объект переключателя: 
                radio[k] = new RadioButton();
                // Подпись для переключателя: 
                radio[k].Text = animals[k];
                // Состояние переключателя (установлен или нет): 
                radio[k].Checked = (k == index);
                // Положение и размеры переключателя: 
                radio[k].SetBounds(10, 20 + k * (h + 4), 100, h);
                // Обработчик для события, связанного с изменением 
                // состояния переключателя: 
                radio[k].CheckedChanged += OnRadioClick;
                // Добавление переключателя в группу: 
                gb.Controls.Add(radio[k]);
            }
            // Добавление группы переключателей на панель: 
            pnl.Controls.Add(gb);
            // Объект кнопки:
            MyButton btn = new MyButton("OK");
            // Высота кнопки: 
            btn.Height = 30;
            // Ширина кнопки: 
            btn.Width = pnl.Width / 3;
            // Горизонтальная координата кнопки: 
            btn.Left = pnl.Width / 3;
            // Вертикальная координата кнопки: 
            btn.Top = pict.Bottom + 5;
            // Шрифт для кнопки: 
            btn.Font = gb.Font;
            // Добавление кнопки на панель:
            pnl.Controls.Add(btn);
            // Добавление панели в окно: 
            this.Controls.Add(pnl);
        }
        // Метод для обработки событий, связанных с изменением 
        // состояния переключателя:
        private void OnRadioClick(object obj, EventArgs ea) {
            // Перебор переключателей: 
            for( int k = 0; k < radio.Length; k++) {
                // Проверка состояния переключателя: 
                if (radio[k].Checked) {
                    // Новое изображение для пиктограммы: 
                    pict.Image = Image.FromFile(path + files[k]);
                    // Завершение выполнения метода: 
                    return;
                }
            }
        }
    }

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

    Какие особенности этой программы? Их несколько. Начнем с того, что в программе для кнопки описывается специальный класс MyButton. Класс создается наследованием класса Button. Конструктору класса передается текстовое значение, определяющее название кнопки. Также для кнопки регистрируется обработчик события (анонимный метод на основе лямбда-выражения), связанного со щелчком по кнопке. Обработка состоит в том, что завершается выполнение программы. Таким образом, кнопки, реализованные в виде объектов класса MyButton, сразу функциональные - щелчок по такой кнопке приводит к завершению выполнения программы.

    В классе окна MyForm (подкласс класса Form) много знакомых "мотивов". Но есть и новые команды и инструкции. Так, в классе имеется поле radio, которое является ссылкой на массив объектных переменных класса RadioButton. В конструкторе класса MyForm командой

  this.StartPosition = FormStartPosition.Manual;
выполняется переход в режим явного определения начального положения окна. Это положение определяется командой
  this.Location = new Point(400, 300);
(от левого верхнего угла экрана окно отстоит по горизонтали на 400 пикселей и по вертикали - на 300 пикселей).

    Объект панели pnl создается командой

  Panel pnl = new Panel();               . 
Ширина панели определяется командой
  pnl.Width = this.ClientSize.Width - 10;             . 
Это ширина клиентской области окна, уменьшенная на 10 пикселей. Высота панели определяется командой
  pnl.Height = this.ClientSize.Height - 10;
(высота клиентской области окна минус 10).


Клиентская область - это область внутри окна, доступная для размещения компонентов. Она немного меньше внешних параметров окна (с учетом того, что у окна есть рамка и строка названия).

    Координаты панели определяются командами

  pnl.Left = 5; 
(горизонтальная координата) и
  pnl.Top = 5;
(вертикальная координата). Это координаты компонента (в данном случае панели) внутри контейнера (которым будет окно). Рамка для панели определяется командой
  pnl.BorderStyle = BorderStyle.FixedSingle;   .

    Объект метки pict создается на основе класса Label. Метка добавляется на панель командой

  pnl.Controls.Add(pict);            . 
Координаты, заданные для метки, - это координаты внутри контейнера. Для метки контейнером является панель. Изображение, которое задается для метки, определяется файлом, название которого содержится в массиве files с индексом index.

    Массив со ссылками на объекты переключателей создаем командой

  radio = new RadioButton[animals.Length];    . 
Размер массива определяется размером массива animals с названиями животных. Также командой
  GroupBox gb = new GroupBox();
создается объект gb класса GroupBox (объект для группы переключателей). Координаты группы переключателей определяются командами
  gb.Left = pict.Right + 5; 
и
  gb.Top = pict.Top;    . 
Таким образом, группа переключателей по высоте размещается на том же уровне, что и метка, а по горизонтали группа переключателей сдвинута на 5 пикселей по отношению к правой границе метки.

    Размеры группы переключателей определяются командами

  gb.Width = 115; 
и
  gb.Height = pict.Height; 
(высота группы переключателей такая же, как и высота метки). Заголовок для группы переключателей (отображается сверху над группой) определяется командой
  gb.Text = "Ваш выбор";   . 
Также мы задаем шрифт и его начертание для группы переключателей (команда
  gb.Font = new Font("Courier New", 12, FontStyle.Bold);
). Для добавления переключателей в группу используем конструкцию цикла. Индексная переменная k пробегает значения индексов элементов из массива radio. За каждую итерацию цикла командой
  radio[k] = new RadioButton();
создается объект переключателя. Командой
  radio[k].Text = animals[k];
определяется подпись для переключателя. Состояние переключателя (установлен или нет) определяется командой
  radio[k].Checked = (k == index);    . 
Здесь свойству Checked переключателя значением присваивается выражение k==index. Значение выражения k==index рано true, если переменная k имеет такое же значение, что и поле index, и false в прочих случаях. Командой
  radio[k].SetBounds(10, 20 + k * (h + 4), 100, h); 
определяются положение и размеры переключателя (предварительно в переменную h записано значение высоты переключателя). Обработчик для события, связанного с изменением состояния переключателя, определяется командой
  radio[k].CheckedChanged += OnRadioClick;    . 
Таким образом, при изменении статуса переключателя будет вызываться метод OnRadioClick(), описанный в классе MyForm. Наконец, с помощью команды
  gb.Controls.Add(radio[k]); 
переключатель добавляется в группу переключателей.

    После завершения оператора цикла группа переключателей добавляется на панель командой

  pnl.Controls.Add(gb);    .

    Объект кнопки btn создается на основе класса MyButton. При создании объекта название кнопки передается аргументом конструктору класса MyButton. Обработчик для этой кнопки уже определен, а параметры и координаты кнопки определяем явно. Ширина кнопки равна трети от ширины панели (команда

  btn.Width = pnl.Width / 3;
). Высота кнопки определяется командой
  btn.Height = 30;     . 
По горизонтали кнопка смещена от левой границы контейнера (панель) на расстояние, равное трети ширины панели (команда
  btn.Left = pnl.Width / 3;
). По вертикали кнопка смещена вниз на 5 пикселей от нижней границы метки (команда
  btn.Top = pict.Bottom + 5;
). Шрифт для кнопки устанавливается такой же, как и для группы переключателей (команда
  btn.Font = gb.Font;
). Кнопка добавляется на панель (команда
  pnl.Controls.Add(btn);
), после чего панель добавляется в окно командой
  this.Controls.Add(pnl);    .

    Закрытый метод OnRadioClick() предназначен для обработки событий, связанных с изменением состояния переключателей. В теле метода выполняется конструкция цикла, в которой перебираются все переключатели из массива radio. Для каждого переключателя выполняется проверка состояния (значение свойства Checked объекта переключателя - true для установленного переключателя и false для неустановленного переключателя). Если переключатель установлен, то командой

  pict.Image = Image.FromFile(path + files[k]);
для метки задается новое изображение (в соответствии с установленным переключателем), а командой return завершается работа метода.

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

    На следующем шаге мы рассмотрим опцию и поле ввода.




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