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

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

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


Рис.1. Окно с полем для ввода названия животного

    В поле нужно ввести название животного. Под полем ввода есть опция. Если она установлена (у опции есть флажок), то не имеет значения, какими буквами (строчными или заглавным) вводится название животного. Если опция не установлена, то название животного нужно вводить с заглавной буквы. На рисунке 2 показано окно, в поле которого введено слово Лиса.


Рис.2. В текстовое поле введено название животного

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


Рис.3. Окно с изображением лисы

    Окно с изображением волка показано на рисунке 4.


Рис.4. Окно с изображением волка

    На рисунке 5 показано, какое окно появится, если пользователь введет в текстовое поле слово Енот.


Рис.5. Окно с изображением енота

    Окно с изображением медведя показано на рисунке 6.


Рис.6. Окно с изображением медведя

    Если пользователь вместо кнопки ОК нажимает кнопку Отмена в окне с полем ввода (см. рисунок 1), то работа программы завершается. Также возможен вариант, когда пользователь неправильно вводит название животного в поле ввода. В этом случае появляется окно с изображением жирафа. Окно показано на рисунке 7.


Рис.7. Окно с изображением жирафа


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

    Теперь проанализируем программный код примера. Сразу отметим несколько принципиальных моментов. Во-первых, как отмечалось выше, мы используем два новых компонента: текстовое поле и опцию. Объект для текстового поля создается на основе класса TextBox. Объект для опции создается на основе класса CheckBox. Во-вторых, мы используем внутренний класс.


Внутренним называется класс, который описан внутри другого класса. Если внутренний класс закрытый, то объекты этого внутреннего класса могут создаваться в программном коде внешнего класса (того, в котором описан внутренний класс). Если внутренний класс открытый, то его можно использовать и вне кода внешнего класса. В таком случае обращение к внутреннему классу выполняется так: указывается имя внешнего класса, точка и имя внутреннего класса.

    Схема следующая: внешний класс MyInputBox используется для создания объекта окна с полем ввода. Закрытый внутренний класс MyForm используется для создания объекта окна с изображением. Программный код примера представлен в примере ниже.

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

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

namespace pr279_1
{
    // Класс для окна с полем ввода: 
    class MyInputBox: Form {
        // Внутренний закрытый класс для окна с изображением: 
        private class MyForm: Form {
            // Закрытое поле внутреннего класса (массив с 
            // названиями животных):
            private string[] animals = {"Волк", "Лиса", "Медведь", "Енот"};
            // Закрытое поле внутреннего класса (массив с 
            // названиями файлов с изображениями животных):
            private string[] files = {"wolf.jpg", "fox.jpg", "bear.jpg", "raccoon.jpg"};
            // Закрытое поле внутреннего класса (путь к каталогу
            // с файлами изображений):
            private string path = "";
            // Конструктор внутреннего класса: 
            public MyForm(string t, bool state): base() {
                // Название животного и название файла,
                // используемые по умолчанию: 
                string txt = "Жиpaф", file = "giraffe.jpg";
                // Перебор элементов массива с названиями 
                // животных:
                for(int k = 0; k < animals.Length; k++) {
                    // Сравнение текстовых значений
                    if ( (t==animals[k]) || ((t.ToLower()==animals[k].ToLower()) & state) ) {
                        // Название животного: 
                        txt = animals[k];
                        // Файл с изображением животного: 
                        file = files[k];
                        // Завершение выполнения оператора цикла: 
                        break;
                    }
                }
                // Заголовок для окна: 
                this.Text = txt;
                // Шрифт для окна:
                this.Font = new Font("Courier New", 12, FontStyle.Bold);
                // Окно постоянных размеров: 
                this.FormBorderStyle = FormBorderStyle.Fixed3D;
                // Окно нельзя развернуть на весь экран: 
                this.MaximizeBox = false;
                // Объект изображения:
                Image img = Image.FromFile(path + file);
                // Высота изображения:
                int h = img.Height;
                // Ширина изображения: 
                int w = img.Width;
                // Объект метки:
                Label lbl = new Label();
                // Изображение для метки: 
                lbl.Image = img;
                // Положение и размеры метки: 
                lbl.SetBounds(10, 10, w + 4, h + 4);
                // Рамка для метки:
                lbl.BorderStyle = BorderStyle.FixedSingle;
                // Объект кнопки:
                Button btn = new Button();
                // Название кнопки: 
                btn.Text = "OK";
                // Положение и размеры кнопки: 
                btn.SetBounds(w / 4 + 10, lbl.Bottom + 5, w / 2, 30);
                // Обработчик для события, связанного со щелчком
                // по кнопке:
                btn.Click += (x, y) => {
                    Application.Exit();
                };
                // Размеры окна:
                this.Size = new Size(w + 40, btn.Bottom + 50);
                // Начальное положение окна: 
                this.StartPosition = FormStartPosition.CenterScreen; 
                // Добавление метки в окно: 
                this.Controls.Add(lbl);
                // Добавление кнопки в окно: 
                this.Controls.Add(btn);
            }
        }
        // Закрытое поле внешнего класса (ссылка на опцию): 
        private CheckBox option;
        // Закрытое поле внешнего класса (ссылка на кнопку): 
        private Button ok;
        // Закрытое поле внешнего класса (ссылка на кнопку): 
        private Button cancel;
        // Закрытое поле внешнего класса (ссылка на поле): 
        private TextBox tb;
        // Конструктор внешнего класса: 
        public MyInputBox(): base() {
            // Размеры окна: 
            this.Size = new Size(250, 190);
            // Положение окна:
            this.StartPosition = FormStartPosition.CenterScreen;
            // Заголовок окна: 
            this.Text = "Название животного";
            // Окно постоянных размеров: 
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            // Окно нельзя развернуть на весь экран: 
            this.MaximizeBox = false; 
            // Шрифт для окна:
            this.Font = new Font("Times New Roman", 13, FontStyle.Regular); 
            // Объект метки:
            Label lbl = new Label();
            // Текст для метки:
            lbl.Text = "Какое животное показать?";
            // Высота и ширина метки:
            lbl.Height = 30;
            lbl.Width = this.Width - 30;
            // Координаты метки:
            lbl.Left = 10;
            lbl.Top = 10;
            // Добавление метки в окно: 
            this.Controls.Add(lbl);
            // Объект текстового поля: 
            tb = new TextBox();
            // Ширина поля: 
            tb.Width = this.Width - 30;
            // Координаты поля: 
            tb.Left = lbl.Left; 
            tb.Top = lbl.Bottom + 5;
            // Добавление поля в окно: 
            this.Controls.Add(tb);
            // Объект опции: 
            option = new CheckBox();
             // Подпись для опции: 
            option.Text ="He учитывать регистр"; 
            // Координаты опции: 
            option.Left = tb.Left; 
            option.Top = tb.Bottom + 5;
            // Размеры опции: 
            option.Height = 30; 
            option.Width = tb.Width;
            // Состояние опции (по умолчанию - установлена)
            option.Checked = true;
            // Добавление опции в окно: 
            this.Controls.Add(option);
            // Объект кнопки: 
            ok = new Button();
            // Текст для кнопки: 
            ok.Text = "OK";
            // Размеры кнопки:
            ok.Width = this.Width / 2 - 20;
            ok.Height = 30; 
            // Координаты кнопки:
            ok.Left = tb.Left;
            ok.Top = option.Bottom + 5;
            // Обработчик для события, связанного со щелчком
            // по кнопке:
            ok.Click += OnBtnsClick;
            // Объект кнопки: 
            cancel = new Button();
            // Текст для кнопки: 
            cancel.Text = "Отмена";
            // Размеры кнопки: 
            cancel.Size = ok.Size;
            // Координаты кнопки:
            cancel.Top = ok.Top;
            cancel.Left = tb.Right - cancel.Width;
            // Обработчик для события, связанного со щелчком 
            // по кнопке:
            cancel.Click += OnBtnsClick;
            // Добавление кнопок в окно:
            this.Controls.Add(ok);
            this.Controls.Add(cancel);
        }
        // Открытый метод (внешнего класса) для отображения
        // окна с полем ввода:
        public static void ShowInputBox() {
            // Создание и отображение окна:
            Application.Run(new MyInputBox());
        }
        // Закрытый метод (внешнего класса), используемый для 
        // обработки событий, связанных со щелчками по кнопкам: 
        private void OnBtnsClick(object obj, EventArgs ea) {
            // Ссылка на объект кнопки, вызвавшей событие:
            Button btn = (Button)obj;
            // Идентификация кнопки: 
            if(btn == ok) { 
                // Если первая кнопка 
                // Окно убирается с экрана: 
                this.Visible = false;
                // Создается и отображается окно с изображением: 
                new MyForm(tb.Text, option.Checked).ShowDialog(); 
            } else { 
                // Если вторая кнопка 
                // Завершение работы программы: 
                Application.Exit();
            }
        }
    }

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

    Класс MyInputBox для окна с полем ввода создается путем наследования класса Form. В классе есть закрытое поле option класса CheckBox. Это ссылка на объект опции. Закрытые поля ok и cancel класса Button являются ссылками на объекты кнопок OK и Отмена, которые отображаются в окне. Еще в классе есть закрытое поле tb класса TextBox (ссылка на объект текстового поля).

    В конструкторе внешнего класса задаются размеры и положение окна, заголовок окна, тип рамки и шрифт. Также создается метка, которая содержит текст, размещаемый над полем ввода.

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

  tb = new TextBox();      . 
Мы задаем ширину поля (команда
  tb.Width = this.Width - 30;
) и координаты поля (команды
  tb.Left = lbl.Left; 
и
  tb.Top = lbl.Bottom + 5;
), после чего поле добавляется в окно командой
  this.Controls.Add(tb);     .


Таким образом, ширина поля на 30 пикселей меньше ширины окна. Горизонтальная координата поля такая же, как и у метки. По вертикали поле смещено на 5 пикселей вниз по сравнению с нижней границей метки. Высота поля определяется размером шрифта, заданным для поля.

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

  option = new CheckBox();    . 
Подпись для опции определяем командой
  option.Text ="He учитывать регистр";      . 
Координаты и размеры опции задаем командами
  option.Left = tb.Left; 
(горизонтальная координата опции совпадает с горизонтальной координатой текстового поля),
  option.Top = tb.Bottom + 5; 
(по вертикали опция сдвинута на 5 пикселей вниз по отношению к нижней границе текстового поля),
  option.Height = 30; 
(высота опции в пикселях равна 30) и
  option.Width = tb.Width; 
(ширина опции равна ширине текстового поля). Состояние опции определяется командой
  option.Checked = true;             , 
что означает наличие "флажка" у опции (опция установлена). В окно опция добавляется командой
  this.Controls.Add(option);     .

    Объект ok для кнопки OK и объект cancel для кнопки Отмена создаются на основе класса Button. Задается текст кнопок, их размеры и положение.


Чтобы размер второй кнопки был таким же, как и первой, используем команду
  cancel.Size = ok.Size;    . 
Для выравнивания второй кнопки по правому краю текстового поля используем команду
  cancel.Left = tb.Right - cancel.Width;    . 
Здесь горизонтальная координата кнопки вычисляется как разность правой координаты поля и ширины кнопки.

    Достоин внимания тот факт, что для обеих кнопок в качестве обработчика события, связанного со щелчком по кнопке, зарегистрирован метод OnBtnsClick(): команды

  ok.Click += OnBtnsClick; 
и
  cancel.Click += OnBtnsClick;    .


В классе MyInputBox описан открытый статический метод ShowInputBox(). При вызове этого метода выполняется команда
  Application.Run( new  MyInputBox());    . 
Командой создается объект класса MyInputBox для окна с полем ввода, и окно отображается на экране. В главном методе программы для отображения окна с полем ввода из класса MyInputBox запускается метод ShowInputBox().

    Закрытый метод OnBtnsClick() внешнего класса MyInputBox, используемый для обработки событий, связанных со щелчками по кнопкам, получает два аргумента. Нас интересует первый аргумент obj (класса object), являющийся ссылкой на объект компонента, на котором произошло событие.


Проблема в том, что кнопки две, а метод-обработчик один. Поэтому при вызове метода необходимо определить, по какой из двух кнопок сделан щелчок.

    Ссылка obj на объект, на котором произошло событие, передается как ссылка класса object. Мы знаем, что событие произошло на кнопке (объект класса Button). Поэтому выполняется команда

  Button btn = (Button)obj     , 
которой ссылка на вызвавший событие объект преобразуется к типу Button (то есть мы получаем возможность работать с объектом как с объектом кнопки). Идентификация кнопки выполняется в условном операторе. Там проверяется условие btn==ok. Истинность условия означает, что событие произошло на кнопке ok. Если так, то командой
  this.Visible = false; 
окно с полем ввода становится невидимым (убирается с экрана), а командой new MyForm(tb.Text, option.Checked).ShowDialog(); создается анонимный объект внутреннего класса MyForm, и из этого объекта вызывается метод ShowDialog(). В результате вызова этого метода окно с изображением животного появляется на экране. Аргументами конструктору передаются текст из текстового поля (выражение tb.Text) и состояние опции (логическое значение option.Checked).


Метод ShowDialog() наследуется из класса Form. При вызове метода отображается окно, из объекта которого вызывается метод. Метод Run() из класса Application в данном случае не используется, поскольку этот метод вызывается только один раз.

    Если условие btn==ok ложно, то, рассуждая методом исключения, получаем, что событие произошло на кнопке cancel. В этом случае командой

  Application.Exit(); 
завершается выполнение программы.

    Осталось расставить все точки на "i" в отношении внутреннего закрытого класса MyForm (создается наследованием класса Form). Напомним, что это класс используется для создания объекта окна с изображением животного. Большинство команд должны быть вам знакомы. Мы, как и ранее, имеем дело с текстовыми массивами, содержащими названия животных и названия файлов с изображениями, и полем с путем к каталогу с изображениями. Конструктору класса передается два аргумента: текст (название животного, которое ввел пользователь в текстовое поле) и логическое значение (состояние опции в окне с полем ввода). В теле метода текстовой переменной txt присваивается значение "Жираф", а текстовой переменной file присваивается значение "giraffe.jpg". Это название животного и файл с его изображением - такие значения используются, если пользователь ввел некорректное имя для животного. Далее перебираются элементы массива animals, в котором хранятся названия животных. Элементы из массива сравниваются с текстовым значением t, переданным аргументом конструктору. В условном операторе проверяется условие (t==animals[k]) || ((t.ToLower()==animals[k].ToLower()) & state). Это сложное условие, которое истинно, если истинно хотя бы одно из двух условий: t==animals[k] (текстовые значения равны) или (t.ToLower()==animals[k].ToLower()) &state. Второе условие истинно, если одновременно истинны условия t.ToLower()==animals[k].ToLower() и state. Истинность условия t.ToLower()==animals[k].ToLower() означает, что тексты равны без учета состояния регистра букв. Значение true для переменной state означает, что установлен флажок опции в окне с полем ввода.


Напомним, что вторым аргументом конструктору класса MyForm при создании объекта передается значение свойства Checked объекта опции. Поэтому значение аргумента state отождествляется со значением свойства Checked.

    Значение выражения t.ToLower()==animals[k].ToLower() вычисляется так: два текстовых значения (из аргумента t и элемента animals[k]) переводятся в нижний регистр, и полученные значения сравниваются на предмет равенства.

    Таким образом, условие в условном операторе истинно, если текстовые значения из аргумента t и элемента animals[k] полностью совпадают или если они совпадают без учета состояния регистра букв, но при этом установлена опция в окне с полем ввода.

    Если для какого-то индекса k условие истинно, то командой

  txt = animals[k];
в переменную txt записывается название выбранного животного, командой
  file = files[k];
в переменную file записывается название соответствующего файла, а командой break; завершается выполнение цикла.

    После завершения цикла определяется заголовок окна (команда

  this.Text = txt;
). Это название животного. Также задаются другие параметры окна (шрифт и рамка). Командой
  Image img = Image.FromFile(path + file);
создается объект изображения (с учетом определенного названия файла с изображением). Это изображение используется как изображение для метки lbl (команда
  lbl.Image = img;
). Мы определяем высоту (инструкция img.Height) и ширину (инструкция img.Width) изображения. Эти параметры используются при определении размеров метки, а также кнопки, используемой для завершения работы приложения. Выполняются и другие операции: определяются размеры окна, начальное положение окна, а также добавляются компоненты (метка и кнопка) в окно. В главном методе из класса MyInputBox вызывается статический метод ShowInputBox(), в результате чего отображается первое окно с полем ввода и опцией.

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




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