Программирование / Заочники / 2 семестр / Методичка_ч3_Урок6
.pdf
Урок 6: Создание компонентов пользовательского интерфейса.
Основная цель урока.
1.Научиться создавать новые компоненты на основе уже существующих
2.Научиться оформлять созданные компоненты в виде независимых библиотек
(DLL)
Учебное задание 6.
Создайте новый компонент на основе ComboBox-а, позволяющий выбирать
цвета из списка (рисунок 1).
Рисунок 1. Компонент для выбора цвета.
Технология выполнения учебного задания 6.
Шаг 1. Создайте новый проект Windows Forms, назовите его Lab4.
Шаг 2.. Добавим в проект новый класс (из главного меню Проект – Добавить класс…). Имя файла укажите – ColorComboBox.cs
Шаг 3.. Откройте файл ColorComboBox.cs. В этом файле у вас уже должен быть создан пустой класс ColorComboBox. Изменим класс так, чтобы он наследовал функционал класса ComboBox (листинг 1).
using System;
using System.Collections.Generic; using System.Text;
using System.Windows.Forms;
namespace Lab4
{
public class ColorComboBox : ComboBox
{
}
}
Листинг 1. Создание нового класса, производного от ComboBox.
Шаг 4..На данный момент созданный класс ColorComboBox отличается от оригинального ComboBox только названием, функционал пока что одинаковый.
Сразу создадим код для проверки работоспособности нашего класса. В конструкторе формы (Form1) разместите следующий код из листинга 2.
public Form1()
{
InitializeComponent();
ColorComboBox comboBox = new ColorComboBox();
//координата X = 100 comboBox.Left = 100;
//координата Y = 100 comboBox.Top = 100;
//родительский элемент = текущая форма comboBox.Parent = this;
comboBox.Items.Add(Color.Red);
comboBox.Items.Add(Color.Green);
comboBox.Items.Add(Color.Blue);
}
Листинг 2. Создание экземпляра класса ColorComboBox на форме.
Шаг 5..Запустите программу, посмотрите, как отображаются элементы списка.
Шаг 6..Переопределим метод OnDrawItem, который отвечает за перерисовку каждого элемента. Однако, этот метод будет вызываться только в случае, если свойство DrawMode будет равно DrawMode.OwnerDrawFixed (или
OwnerDrawVariable), а по умолчанию оно равно DrawMode.Normal.
Меняем в конструкторе свойство DrawMode и переопределяем метод OnDrawItem
(листинг 3).
В методе OnDrawItem используется структура Color, не забудьте импортировать пространство имён System.Drawing. (using System.Drawing;)
public class ColorComboBox : ComboBox
{
// конструктор класса public ColorComboBox()
{
// DropDownList - фиксировнный список(нельзя печатать текст в поле) this.DropDownStyle = ComboBoxStyle.DropDownList;
// пользовательская отрисовка this.DrawMode = DrawMode.OwnerDrawFixed;
}
//Переопределяем (override) метод OnDrawItem
//(вызывается каждый раз при перерисовке элемента)
protected override void OnDrawItem(DrawItemEventArgs e)
{
//отрисовываем фон e.DrawBackground();
//проверяем индекс текущего элемента if (e.Index != -1)
{
//если состояение текущего элемента - "Выделено" if (e.State == DrawItemState.Selected)
{
//рисуем фоновое выделение (светло-синий прямоугольник)
//во всю ширину элемента (e.Bounds) e.Graphics.FillRectangle(Brushes.CornflowerBlue,
e.Bounds);
}
//получаем текущий цвет из коллекции Items Color currentColor = (Color)Items[e.Index];
//создаём новую кисть (Brush) на основе этого цвета
SolidBrush brush = new SolidBrush(currentColor);
//вычисляем прямоугольник, который должен быть закрашен
//выбранным цветом
//изначально путь прямоугольник будет таким же,
//как прямоугольник текущего элемента
Rectangle rect = e.Bounds;
//меняем ширину на 30 пикселов rect.Width = 30;
//и уменьшаем размер со всех сторон на 2 пиксела rect.Inflate(-2, -2);
//заполняем получившийся прямоугольник заданным цветом e.Graphics.FillRectangle(brush, rect);
//рисуем вокруг прямоугольнкиа чёрную рамку e.Graphics.DrawRectangle(Pens.Black, rect);
//получаем имя текущего цвета
string nameOfColor = currentColor.ToString();
//Рисуем строку, название цвета (метод DrawString)
//шрифт - текущий (this.Font),
//цвет - чёрный (Brushes.Black),
//координата X - на 2 пиксела правее прямоугольника с
//цветом (rect.Right + 2)
//координата Y - такая же как у прямоугольника с цветом
//(т.е. rect.Top)
e.Graphics.DrawString(nameOfColor, this.Font,
Brushes.Black, rect.Right + 2, rect.Top,
StringFormat.GenericDefault);
}
}
}
Листинг 3. Переопределение метода OnDrawItem.
Шаг 7..Запустите программу, посмотрите, как отображаются элементы списка.
Элементы должны отображаться, как показано на рисунке 2.
Рисунок 2. ColorComboBox после выполнения шага 7
Шаг 8..Добавим возможность задавать свои названия для цветов. К сожалению,
свойство Items у базового класса ComboBox не является виртуальным и его нельзя переопределить. Поэтому придётся создать свои собственные методы для добавления цвета + названия цвета в коллекцию.
В оригинальной коллекции Items так же будем хранить цвета, а названия цветов будем хранить, используя класс Dictonary.
Dictonary – представляет собой коллекцию ключей и значений (т.е. хранит множество записей в виде Ключ – Значение). Возможен быстрый поиск заданного значения по ключу. В качестве Ключа будем использовать цвет (Color), а в качестве Значение название цвета (string), т.о. зная фактическое значение цвета мы всегда можем определить его название (если оно содержится в коллекции).
Пример использования:
Dictionary<Color, string> dict = new Dictionary<Color, string>(); dict[Color.Red] = "Красный";
dict[Color.Green] = "Зелёный";
string whatNameOfColor = dict[Color.Green]; // whatNameOfColor = "Зелёный"
Создадим методы AddColor и RemoveColor, которые будут добавлять цвет и название цвета (листинг 4).
public class ColorComboBox : ComboBox
{
//ColorNames хранит список пар значений Цвет-Название private Dictionary<Color, string> ColorNames;
//конструктор класса
public ColorComboBox()
{
//DropDownList - фиксировнный список, нельзя печатать текст в поле this.DropDownStyle = ComboBoxStyle.DropDownList;
//пользовательская отрисовка
this.DrawMode = DrawMode.OwnerDrawFixed;
// инициализация ColorNames
ColorNames = new Dictionary<Color, string>();
}
public void AddColor(string name, Color color)
{
//добавляем цвет в коллекцию Items Items.Add(color);
//устанавливаем соотношение цвет - название
ColorNames[color] = name;
}
public void RemoveColor(Color color)
{
Items.Remove(color);
ColorNames.Remove(color);
}
Листинг 4. Методы AddColor\RemoveColor.
Шаг 9.. Теперь изменим метод OnDrawString, чтобы он использовал коллекцию
ColorNames для получения цвета (листинг 5)
rect.Width = 30;
//и уменьшаем размер со всех сторон на 2 пиксела rect.Inflate(-2, -2);
//заполняем получившийся прямоугольник заданным цветом e.Graphics.FillRectangle(brush, rect);
//рисуем вокруг прямоугольнкиа чёрную рамку e.Graphics.DrawRectangle(Pens.Black, rect);
//получаем имя текущего цвета string nameOfColor;
if (ColorNames.ContainsKey(currentColor))
{
nameOfColor = ColorNames[currentColor];
}
else
{
//если коллекция не содержит этот цвет
//используем стандартный способ определения имени nameOfColor = currentColor.ToString();
}
//Рисуем строку, название цвета (метод DrawString)
//шрифт - текущий (this.Font),
//цвет - чёрный (Brushes.Black),
//координата X - на 2 пиксела правее прямоугольника с
//цветом (rect.Right + 2)
//координата Y - такая же как у прямоугольника с цветом
//(т.е. rect.Top)
e.Graphics.DrawString(nameOfColor,
this.Font,
Brushes.Black, rect.Right + 2, rect.Top,
StringFormat.GenericDefault);
Листинг 5. Изменения в методе OnDrawString.
Шаг 10. Теперь заменим добавление элементов в комбобокс через коллекцию Items,
на добавление элементов через метод AddColor (листинг 6).
public Form1()
{
InitializeComponent();
ColorComboBox comboBox = new ColorComboBox();
//координата X = 100 comboBox.Left = 100;
//координата Y = 100 comboBox.Top = 100;
//родительский элемент = текущая форма comboBox.Parent = this;
comboBox.AddColor("Красный", Color.Red); comboBox.AddColor("Зелёный", Color.Green); comboBox.AddColor("Синий", Color.Blue); comboBox.AddColor("Оранжевый", Color.Orange); comboBox.AddColor("Фиолетовый", Color.Purple);
}
Листинг 6. Изменения в конструкторе формы.
Шаг 11. Запустите программу, посмотрите, как отображаются элементы списка.
Элементы должны отображаться, как показано на рисунке 1.
Шаг 12. Сделайте после этого шага Commit.
Шаг 13. Разместим, разработанный компонент ColorComboBox, в отдельной библиотеке (DLL). Для этого добавьте в солюшен(решение) проекта новый проект,
для этого в окне Обозревателя решений кликните правым кликом на Решение Lab4
и выберите из контекстного меню пункт Добавить – Создать проект… В появившимся окне выберите « Библиотека классов», имя нового проекта пусть будет ExtendedControls.
Шаг 14. Через окно « Обозреватель решений» перенесите мышкой файл
ColorComboBox.cs в проект ExtendedControls (после этого будет создана копия этого файла в проекте ExtendedControls) и удалите файл ColorComboBox.cs из проекта
Lab4.
Из проекта ExtendedControls удалите файл Class1.cs
Результат того, что должно получиться, показан на рисунке 3.
Рисунок 3. Окно Обозреватель решений после выполнения шага 14
Шаг 15. Следующим шагом исправим ошибки в проекте ExtendedControls. Мы используем сборки System.Windows и System.Drawing, но по умолчанию они не добавляются в библиотеку классов. Их нужно добавить самостоятельно, для этого кликаем правым кликом на папке « Ссылки» проекта ExtendedControls, выбираем добавить ссылку (ссылку на сборку).
Далее в появившимся окне выбираем первую закладку (.NET), ищем там
System.Windows.Forms – добавляем. Затем ищем System.Drawing – добавляем.
Шаг 16. Следующее, что необходимо исправить – название пространства имён. Т.к.
файлы мы просто скопировали из Lab4, то и пространство имён должно было остаться старым (Lab4), а должно быть ExtendedControls.
Через окно « Обозреватель решений» откройте файл ColorComboBox.cs (правым кликом – Перейти к коду), просто по двойному клику он не откроется, как раз из-за неверного пространства имён.
Исправьте название пространства имён в модуле ColorComboBox.cs на
ExtendedControls (namespace ExtendedControls).
После этого нажмите правым кликом на проект ExtendedControls (в окне Обозреватель решений) и из контекстного меню выберите пункт « Перестроить».
В окне « Вывод» должно быть написано:
========== Перестроение всех: успешно: 1, с ошибками: 0, пропущено: 0 ==========
Шаг 17. Библиотека готова, теперь нужно научить Lab4 её использовать. Для этого добавим ссылку на эту библиотеку. Для этого нажимаете правым кликом по папке
« Ссылки» ( окно Обозреватель решений) проекта Lab4.
Из контекстного меню выбираете « Добавить ссылку».
В появившимся окне переходите на вкладку « Обзор», переходите на уровень выше,
там должна быть папка с проектом ExtendedControls, далее идёте
ExtendedControls–> bin –> debug и выбираете файл ExtendedControls.dll (рисунок 4).
Рисунок 4. Добавление ссылки на библиотеку ExtendedControls
Шаг 18. После этого импортируете пространство имён ExtendedControls в модуле
формы.
using System;
using System.Collections.Generic; using System.ComponentModel; using System.Data;
using System.Drawing; using System.Linq; using System.Text;
using System.Windows.Forms; using ExtendedControls;
namespace Lab4
{
public partial class Form1 : Form
{
Листинг 6. Импортируем пространство имён ExtendedControls.
Шаг 19. Можно запустить приложение и проверить его на работоспособность.
Самостоятельное задание 6.
Создайте новый компонент NumericTextBox, на основе элемента управления
TextBox. Компонент NumericTextBox представляет собой так же как и TextBox
текстовое поле, по позволяет вводить только цифры (т.е. не просто должна возникать ошибка при вводе буква, а они в принципе не должны вводиться и при вставке из буфера обмена тоже).
Подсказка: можно переопределить событие OnKeyPress.
Компонент NumericTextBox должен быть размещён так же в библиотеке
ExtendedControls.
Доп. задание (+3 балла):
Создать новый компонент SkinnedButton на основе компонента Button. Кнопка
SkinnedButton должна уметь поддерживать « шкурки» (« скины»), т.е. изменяемый и настраиваемый внешний вид. Скин представляет собой текстовый файл произвольной структуры (а ещё лучше XML-файл), содержащий:
∙Название скина;
∙информацию о рисунке, отображаемом на кнопке;
∙информацию о рисунке, который будет отображаться при наведении на кнопку;
∙информацию о рисунке, который будет отображаться при нажатом состоянии кнопки;
∙ информацию о рисунке, который будет отображаться, когда кнопка
« отключена» (Enabled = False).
Пример файла скина:
Name: ButtonSkin1
Normal: bsNormal1.png
Hover: bsHover1.png
Down: bsDown1.png
Disabled: bsDisabled1.png
Примеры графических файлов:
Состояние |
Рисунок |
Normal
Down
Disabled
У компонента SkinnedButton должно быть свойство Skin, через которое будет указываться путь до файла со скином. Файл со скином может располагаться где угодно на диске; связанные с ним графически ресурсы обязательно должны быть в той же папке, что и сам скин.
