В этой заключительной лекции новый материал появляться не будет, не будет и традиционных вопросов в конце лекции. Лекция особенная - она посвящена описанию финального проекта, в котором объединены многие, надеюсь, уже хорошо знакомые элементы.
В финальном проекте создается семейство классов, описывающих геометрические фигуры. Проектирование начинается с абстрактного класса поведения, который описывает общие свойства и методы, характерные для всех фигур семейства. Затем, используя наследование, создаются классы конкретных геометрических фигур, начиная с простейших, таких, как круги и прямоугольники, до составных, таких, как класс Person. Мы добавим в наш проект динамические структуры данных, такие, как список с курсором, для хранения в нем фигур семейства. Наконец, мы создадим интерфейс, включающий меню с десятками команд и панель с инструментальными кнопками. Интерфейс позволяет конечному пользователю выполнять различные действия над геометрическими фигурами - создавать, рисовать их на форме, перемещать их с помощью команд и перетаскивать их мышью, менять их размеры и цвет, сохранять в списке и удалять из списка, отображать все фигуры списка или очистить его полностью.
Проект может служить образцом полноценного Windows-приложения, примером проектирования в классах с демонстрацией преимуществ, предоставляемых наследованием. Закончим на этом рекламную часть и приступим к делу. Хочу предупредить, вас ждут программные тексты, почти без всяких комментариев. Все нужные комментарии были даны в предыдущих лекциях. С моей точки зрения, наиболее интересная часть программистских книжек - это та, в которой приводится программный код. И значит, эта глава самая интересная.
Абстрактный класс Figure
Приведем код класса:
using System;
using System.Drawing; namespace Shapes
{
///
/// Figure - это абстрактный класс; прародитель семейства
/// классов геометрических фигур. Все фигуры имеют:
/// центр - center, масштаб - scale. статус
/// перетаскивания - dragged center - объект встроенного
/// класса (структуры) Point. Этот объект задает характерную
/// точку фигуры - чаще всего ее центр (тяжести)
/// scale задает масштаб фигуры, первоначально единичный.
/// drugged = true, когда фигура следует за курсором мыши.
/// над фигурами определены операции: параллельный
/// перенос - Move(a,b) масштабирование - Scale(s)
/// Показ фигуры - Show. Область захвата - Region_Capture
/// возвращает прямоугольник, характерный для фигуры,
/// перетаскивание фигуры возможно при установке курсора
/// мыши в области захвата.
///
abstract public class Figure
{
///
/// закрытые для клиентов атрибуты класса - center, scale
/// protected Point center;
protected double scale ; protected bool dragged; protected Color color;
//Доступ к свойствам
public Point center_figure
{
get{return(center);} get {center = value;}
}
public double scale_figure
{
get{return(scale);} get {scale = value;}
}
public bool dragged_figure
{
get{return(dragged);} get {dragged = value;}
}
public Color color_figure
{
get{return(color);} set {color = value;}
}
///
/// базовый конструктор фигур
///
/// координата X характерной точки
///фигуры
/// Координата Y характерной точки
///фигуры
public Figure(int x, int y)
{
center = new Point(x,y); scale = 1;
dragged = false;
color = Color.ForestGreen;
}
///
/// отложенный метод
/// Параллельный перенос фигуры на (a,b)
/// require : true;
/// ensure : для любой точки фигуры p(x,y):
/// x = old(x) +a; y = old(y) + b;
///
/// a - перемещение по горизонтали
///вправо
/// b - перемещение по вертикали
///вниз
/// Замечание: Для того, чтобы фигура при рисовании была
/// полностью видимой, координаты всех ее точек должны
/// быть в пределах области рисования. public void Move (int a,int b)
{
center.X +=a; center.Y += b;
}
///
/// изменяет масштаб фигуры
///
/// name="s"масштаб изменяется в s раз public void Scale(double s)
{
scale*=s;
}
///
/// рисование фигуры в окне, передающем объекты g и pen
///
/// графический объект, методы которого
/// рисуют фигуру
/// перо рисования public abstract void Show(Graphics g, Pen pen,
Brush brush);
public abstract System.Drawing.Rectangle Region_Capture();
}
Абстрактный класс, относящийся к этапу проектирования системы, вместе с тем является важнейшим элементом заключительного семейства классов. В этом проявляется мощь объектно-ориентированного подхода к разработке программных систем. Заметьте, на данном уровне большая часть текста представляет документацию, являющуюся неотъемлемой частью программного проекта. Документация записана в тегах , что позволяет автоматически ее извлечь и сохранить в виде XML-отчета.
Классы семейства геометрических фигур
Приведем теперь программные коды классов, являющихся потомками класса Figure.
Класс Ellipse
Вот программный код этого класса:
using System;
using System.Drawing; namespace Shapes
{
///
/// Класс Ellipse - потомок класса Figure.
///
public class Ellipse: Figure
{
int axisA,axisB;
Rectangle rect;
public Ellipse(int A, int B, int x, int y ): base(x,y)
{
axisA = A; axisB = B; rect =Init();
}
public override void Show(Graphics g, Pen pen, Brush brush)
{
rect = Init(); g.DrawEllipse(pen,rect); g.FillEllipse(brush, rect);
}
public override Rectangle Region_Capture()
{
rect = Init(); return rect;
}
Rectangle Init()
{
int a =Convert.ToInt32(axisA*scale); int b =Convert.ToInt32(axisB*scale); int leftupX = center.X - a;
int leftupY = center.Y - b;
return( new Rectangle(leftupX,leftupY,2*a,2*b));
}
}
}
Класс Circle
Этот класс является потомком класса Ellipse: using System;
using System.Drawing; namespace Shapes
{
///
/// Класс Circle - потомок класса Ellipse.
///
public class Circle: Ellipse
{
public Circle( int radius,int x, int y):base(radius,radius,x,y)
{
//Круг - это эллипс с равными полуосями (радиусом круга)
}
}
}
Здесь опять-таки проявляется мощь наследования. Потомок наследует все свойства и методы родителя. Ему остается только указать собственный конструктор объектов класса, да и в нем главное состоит в вызове конструктора родительского класса с передачей ему нужных аргументов.
Класс LittleCircle
Этот класс, задающие маленькие кружочки фиксированного радиуса, в свою очередь, является наследником класса Circle. Устроен он также чрезвычайно просто:
using System; namespace Shapes
{
///
/// Класс LittleCircle - потомок класса Circle.
///
public class LittleCircle:Circle
{
public LittleCircle(int x,int y): base(4,x,y)
{
// маленький круг радиуса 4
}
}
}
Класс Rect
Этот класс является еще одним прямым потомком класса Figure: using System;
using System.Drawing; namespace Shapes
{
///
/// Класс Rect - потомок класса Figure.
///
public class Rect:Figure
{
int sideA, sideB;
Rectangle rect;
public Rect(int sideA,int sideB, int x, int y): base(x,y)
{
this.sideA = sideA; this.sideB = sideB; rect =Init();
}
public override void Show(Graphics g, Pen pen, Brush brush)
{
rect = Init(); g.DrawRectangle(pen,rect); g.FillRectangle(brush,rect);
}
public override Rectangle Region_Capture()
{
rect = Init(); return rect;
}
Rectangle Init()
{
int a =Convert.ToInt32(sideA*scale); int b =Convert.ToInt32(sideB*scale); int leftupX = center.X - a/2;
int leftupY = center.Y - b/2;
return( new Rectangle(leftupX,leftupY,a,b));
}
}
}
Класс Square
Квадрат - это частный случай прямоугольника. Соответствующий класс является потомком класса Rect:
using System; namespace Shapes
{
///
/// Класс Square - потомок класса Rect.
///
public class Square:Rect
{
public Square(int side, int x, int y): base(side,side,x,y)
{
//квадрат - это прямоугольник с равными сторонами
}
}
}
Класс Person
Этот класс является прямым потомком класса Figure. Вместе с тем, класс является клиентом трех других классов семейства - Circle, Rect и LittleCircle, поскольку элементы фигуры, составляющие человечка, являются объектами этих классов%
namespace Shapes
{
///
/// Класс Person - потомок класса Figure,
/// клиент классов Circle, Rect, LittleCircle.
///
public class Person:Figure
{
int head_h;
Circle head;
Rect body;
LittleCircle nose;
public Person(int head_h, int x, int y): base(x,y)
{
//head_h - радиус головы, x,y - ее центр.
//остальные размеры исчисляются относительно
//размера головы. this.head_h = head_h;
head = new Circle(head_h,x,y); int body_x = x;
int body_y = y + 3*head_h;
int body_w =2*head_h; int body_h = 4*head_h;
body = new Rect(body_w, body_h, body_x,body_y); nose = new LittleCircle(x+head_h +2, y);
}
public override void Show(System.Drawing.Graphics g, System.Drawing.Pen pen, System.Drawing.Brush brush)
{
int h = Convert.ToInt32(head_h*scale);
//head
int top_x = center.X - h; int top_y = center.Y - h;
g.DrawEllipse(pen, top_x,top_y, 2*h,2*h); g.FillEllipse(brush, top_x,top_y, 2*h,2*h);
//body
top_y += 2*h;
g.DrawRectangle(pen, top_x,top_y, 2*h,4*h); g.FillRectangle(brush, top_x,top_y, 2*h,4*h);
//nose top_y -=h;
top_x += 2*h;
g.DrawEllipse(pen, top_x,top_y, 8,8);
g.FillEllipse(brush, top_x,top_y, 8,8);
}
public override System.Drawing.Rectangle Region_Capture()
{
int h = Convert.ToInt32(head_h*scale); int top_x = center.X - h;
int top_y = center.Y - h; return new
System.Drawing.Rectangle(top_x,top_y,2*h,2*h);
}
}
}
Список с курсором. Динамические структуры данных
Добавим в проект классы, задающие динамические структуры данных. Конечно, можно было бы воспользоваться стандартными... Но для обучения крайне полезно уметь создавать собственные классы, задающие такие структуры данных. Список с курсором - один из важнейших образцов подобных классов%:
using System; namespace Shapes
{
///
/// Класс TwoWayList(G) описывает двусвязный список с
/// курсором. Элементами списка являются объекты
/// TwoLinkable, хранящие, помимо указателей на двух
/// преемников, объекты типа G.Курсор будет определять /// текущий
(активный) элемент списка. Класс будет
/// определять симметричные операции по отношению к
/// курсору.
/// Конструкторы:
/// Конструктор без параметров будет создавать пустой
/// список
/// Запросы:
/// empty: require: true; возвращает true для
/// непустого списка item: require: not empty();
/// возвращает активный элемент типа G; count:
/// require: true; возвращает число элементов списка;
/// count in[0,n]
/// (count == 0) eqviv empty();
/// index: require: not empty(); возвращает индекс
/// активного элемента.
/// search_res: require: true; возвращает true,
/// если последний поиск был успешным.
/// Команды:
/// put_left(elem): require: true;
/// ensure: добавить новый элемент (elem) слева от курсора;
/// put_right(elem): require: true;
/// ensure: добавить новый элемент (elem) справа от
/// курсора;
/// remove: require: not empty();
/// ensure: удалить активный элемент;
/// особо обрабатывается удаление последнего и
/// единственного элементов
/// операции с курсором:
/// start: require: true;
/// ensure: сделать активным первый элемент;
/// finish: require: true;
/// ensure: сделать активным последний элемент;
/// go_prev: require: not (index = 1);
/// ensure: сделать активным предыдущий элемент;
/// go_next: require: not (index = count);
/// ensure: сделать активным последующий элемент;
/// go_i(i): require: (i in [1, count]);
/// ensure: сделать активным элемент с индексом i;
/// операции поиска:
/// search_prev(elem): require: not (index = 1);
/// ensure: сделать активным первый элемент elem
/// слева от курсора;
/// Успех или неуспех поиска сохранять в булевской
/// переменной search_res
/// search_next: require: not (index = count);
/// ensure: сделать активным первый элемент elem
/// справа от курсора;
/// успех или неуспех поиска сохранять в булевской
/// переменной search_res
///
public class TwoWayList
{
public TwoWayList()
{
first = cursor = last = null; count = index = 0;
search_res = false;
}//конструктор
///
/// first, cursor, last - ссылки на первый,
/// активный и последний элементы списка
/// Запросы count, index search_res также
/// реализуются атрибутами.
/// Запросы empty, item реализуются функциями
///
protected TwoLinkable first, cursor, last; protected int count, index;
protected bool search_res;
//доступ на чтение к закрытым свойствам; public int Count
{
get
{
return(count);
}
}
public int Index
{
get
{
return(index);
}
}
public bool Search_res
{
get
{
return(search_res);
}
}
///
/// require: true; возвращает true для непустого списка
///
/// public bool empty()
{
return(first == null);
}//empty
///
/// require: not empty(); возвращает активный
/// элемент типа G;
///
/// public Figure item()
{
return(cursor.Item);
}//item
///
/// require: true;
/// ensure: добавить новый элемент (elem) слева
/// от курсора;
///
/// Тип Figure играет роль
/// родового типа G
/// хранимого элемента elem public void put_left(Figure elem)
{
TwoLinkable newitem = new TwoLinkable(); newitem.Item = elem;
newitem.Next = cursor;
if (empty()) //список пуст
{
first = cursor = last = newitem; index =1; count = 1;
}
else
{
if (index == 1) first =newitem;
else
cursor.Prev.Next = newitem;
newitem.Prev = cursor.Prev; cursor.Prev = newitem; count++; index++;
}
}//put_right
///
/// require: true;
/// ensure: добавить новый элемент (elem) справа
/// от курсора;
///
/// Тип Figure играет роль
/// родового типа G
/// хранимого элемента elem public void put_right(Figure elem)
{
TwoLinkable newitem = new TwoLinkable(); newitem.Item = elem;
newitem.Prev = cursor;
if (empty()) //список пуст
{
first = cursor = last = newitem; index =1; count = 1;
}
else
{
if (index == count) last =newitem;
else
cursor.Next.Prev = newitem;
newitem.Next = cursor.Next; cursor.Next = newitem; count++;
}
}//put_right
public void remove()
{
if(count == 1)
{
first = last = cursor = null; index=0;
}
else if(index==1)
{
first = cursor.Next; cursor.Prev = null; cursor = cursor.Next;
}
else if(index == count)
{
last = cursor.Prev; cursor.Next = null; cursor = cursor.Prev; index--;
}
else
{
cursor.Prev.Next = cursor.Next; cursor.Next.Prev = cursor.Prev; cursor = cursor.Next;
}
count--;
}//remove
/// операции с курсором:
///
/// start: require: true;
/// ensure: сделать активным первый элемент;
/// public void start()
{
cursor = first; index = 1;
}//start
///
/// finish: require: true;
/// ensure: сделать активным последний элемент;
/// public void finish()
{
cursor = last; index = count;
}//finish
///
/// go_prev: require: not (index = 1);
/// ensure: сделать активным предыдущий элемент;
///
public void go_prev()
{
cursor = cursor.Prev; index--;
}// go_prev
///
/// go_next: require: not (index = count);
/// ensure: сделать активным последующий элемент;
///
public void go_next()
{
cursor = cursor.Next; index++;
}// go_next
///
/// go_i(i): require: (i in [1, count]);
/// ensure: сделать активным элемент с индексом i;
///
/// public void go_i(int i)
{
if(i index)
while (iindex)
{
cursor = cursor.Next; index++;
}
else if(i while (i
{
cursor = cursor.Prev; index--;
}
}// go_i
/// операции поиска:
///
/// search_prev(elem): require: not (index = 1);
/// ensure: сделать активным первый элемент elem
/// слева от курсора;
///
/// искомый элемент public virtual void search_prev(Figure elem)
{
bool found = false;
while (!found && (index !=1))
{
cursor = cursor.Prev; index--; found = (elem == item());
}
search_res = found;
}// search_prev
///
/// успех или неуспех поиска сохранять в булевской
/// переменной search_res
/// search_next: require: not (index = count);
/// ensure: сделать активным первый элемент elem
/// справа от курсора;
/// успех или неуспех поиска сохранять в булевской
/// переменной search_res
///
/// name="elem"
public virtual void search_next(Figure elem)
{
bool found = false;
while (!found && (index !=count))
{
cursor = cursor.Next; index++; found = (elem == item());
}
search_res = found;
}//search_next
}
}
Заметьте, класс подробно документирован. Для методов класса указываются предусловия и постусловия. Обратите внимание, в соответствии с принципами контрактного программирования клиент класса, прежде чем вызвать метод, должен проверить выполнимость предусловия, что повышает корректность работы системы в целом. Именно так и будет реализован вызов этих методов в классе формы, где осуществляется работа со списком.
Классы элементов списка
Рассмотрим классы, описывающие элементы списков - элементы с одним и с двумя указателями:
using System; namespace Shapes
{
///
/// Класс Linkable(T)задает элементы списка,включающие:
/// информационное поле типа T - item
/// ссылку на элемент типа Linkable - next
/// Функции:
/// конструктор new: - Linkable
/// запросы:
/// Get_Item: Linkable - T
/// Get_Next: Linkable - Linkable
/// процедуры:
/// Set_Item: Linkable*T - Linkable
/// Set_Next: Linkable*Linkable - Linkable
/// Роль типа T играет Figure
///
public class Linkable
{
public Linkable()
{
item =null; next = null;
}
///
/// закрытые атрибуты класса
/// Figure item; Linkable next;
///
/// процедуры свойства для доступа к полям класса
/// public Figure Item{ get{
return(item);
}
set{
item = value;
}
}
public Linkable Next{ get{
return(next);
}
set{
next = value;
}
}
}//class Linkable
///
/// Класс TwoLinkable задает элементы с двумя ссылками
///
public class TwoLinkable
{
public TwoLinkable()
{
prev = next = null;
}
///
/// закрытые атрибуты класса
/// TwoLinkable prev, next; Figure item;
///
/// процедуры свойства для доступа к полям класса
/// public Figure Item
{
get
{
return(item);
}
set
{
item = value;
}
}
public TwoLinkable Next
{
get
{
return(next);
}
set
{
next = value;
}
}
public TwoLinkable Prev
{
get
{
return(prev);
}
set
{
prev = value;
}
}
}//class TwoLinkable
}
Организация интерфейса
Создадим теперь интерфейс, позволяющий конечному пользователю работать с объектами наших классов. Как всегда, интерфейс создавался вручную в режиме проектирования. На форме я создал меню с большим числом команд и инструментальную панель с 18 кнопками, команды которых повторяли основную команду меню. Описывать процесс создания интерфейса не буду - он подробно рассмотрен в предыдущей главе. Поскольку вся работа по созданию интерфейса транслируется в программный код формы, то просто приведу этот достаточно длинный текст почти без всяких купюр:
using System;
using System.Drawing; using System.Collections;
using System.ComponentModel; using System.Windows.Forms; using System.Data;
using Shapes;
namespace Final
{
///
/// Эта форма обеспечивает интерфейс для создания,
/// рисования, показа, перемещения, сохранения в списке
/// и выполнения других операций над объектами семейства
/// геометрических фигур. Форма имеет меню и
/// инструментальные панели.
///
public class Form1 : System.Windows.Forms.Form
{
//fields
Graphics graphic;
Brush brush, clearBrush; Pen pen, clearPen;
Color color;
Figure current;
TwoWayList listFigure;
private System.Windows.Forms.MainMenu mainMenu1; private System.Windows.Forms.ImageList imageList1; private System.Windows.Forms.ToolBar toolBar1; private System.Windows.Forms.MenuItem menuItem1;
// аналогичные определения для других элементов меню private System.Windows.Forms.MenuItem menuItem35; private System.Windows.Forms.ToolBarButton
toolBarButton1;
// аналогичные определения для других командных кнопок
private System.Windows.Forms.ToolBarButton toolBarButton18;
private System.ComponentModel.IContainer components; public Form1()
{
InitializeComponent(); InitFields();
}
void InitFields()
{
graphic = CreateGraphics();
color = SystemColors.ControlText; brush = new SolidBrush(color);
clearBrush = new SolidBrush(SystemColors.Control); pen = new Pen(color);
clearPen = new Pen(SystemColors.Control); listFigure = new Figure_List();
current = new Person(20, 50, 50);
}
///
/// Clean up any resources being used.
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
// Код, инициализирующий компоненты и построенный
// дизайнером, опущен
}
#endregion
///
/// Точка входа в приложение - процедура Main,
/// запускающая форму
/// [STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void menuItem7_Click(object sender, System.EventArgs e)
{
createEllipse();
}
void createEllipse()
{
//clear old figure
if (current != null) current.Show(graphic, clearPen, clearBrush);
//create ellipse
current = new Ellipse(50, 30, 180,180);
}
private void menuItem8_Click(object sender, System.EventArgs e)
{
createCircle();
}
void createCircle()
{
//clear old figure
if (current != null) current.Show(graphic, clearPen, clearBrush);
//create circle
current = new Circle(30, 180,180);
}
private void menuItem9_Click(object sender, System.EventArgs e)
{
createLittleCircle();
}
void createLittleCircle()
{
//clear old figure
if (current != null) current.Show(graphic, clearPen, clearBrush);
//create littlecircle
current = new LittleCircle(180,180);
}
private void menuItem10_Click(object sender, System.EventArgs e)
{
createRectangle();
}
void createRectangle()
{
//clear old figure
if (current != null) current.Show(graphic, clearPen, clearBrush);
//create rectangle
current = new Rect(50, 30, 180,180);
}
private void menuItem11_Click(object sender, System.EventArgs e)
{
createSquare();
}
void createSquare()
{
//clear old figure
if (current != null) current.Show(graphic, clearPen, clearBrush);
//create square
current = new Square(30, 180,180);
}
private void menuItem12_Click(object sender, System.EventArgs e)
{
createPerson();
}
void createPerson()
{
//clear old figure
if (current != null) current.Show(graphic, clearPen, clearBrush);
//create person
current = new Person(20, 180,180);
}
private void menuItem13_Click(object sender, System.EventArgs e)
{
showCurrent();
}
void showCurrent()
{
//Show current current.Show(graphic, pen, brush);
}
private void menuItem14_Click(object sender, System.EventArgs e)
{
clearCurrent();
}
void clearCurrent()
{
//Clear current
current.Show(graphic, clearPen, clearBrush);
}
private void menuItem17_Click(object sender, System.EventArgs e)
{
incScale();
}
void incScale()
{
//Increase scale
current.Show(graphic, clearPen, clearBrush); current.Scale(1.5);
current.Show(graphic, pen, brush);
}
private void menuItem18_Click(object sender, System.EventArgs e)
{
decScale();
}
void decScale()
{
//Decrease scale
current.Show(graphic, clearPen, clearBrush);
current.Scale(2.0/3); current.Show(graphic, pen, brush);
}
private void menuItem19_Click(object sender, System.EventArgs e)
{
moveLeft();
}
void moveLeft()
{
//Move left
current.Show(graphic, clearPen, clearBrush); current.Move(-20,0);
current.Show(graphic, pen, brush);
}
private void menuItem20_Click(object sender, System.EventArgs e)
{
moveRight();
}
void moveRight()
{
//Move right
current.Show(graphic, clearPen, clearBrush); current.Move(20,0);
current.Show(graphic, pen, brush);
}
private void menuItem21_Click(object sender, System.EventArgs e)
{
moveTop();
}
void moveTop()
{
//Move top
current.Show(graphic, clearPen, clearBrush); current.Move(0,-20);
current.Show(graphic, pen, brush);
}
private void menuItem22_Click(object sender, System.EventArgs e)
{
moveDown();
}
void moveDown()
{
//Move down
current.Show(graphic, clearPen, clearBrush); current.Move(0, 20);
current.Show(graphic, pen, brush);
}
private void menuItem23_Click(object sender, System.EventArgs e)
{
//choose color
ColorDialog dialog = new ColorDialog();
if (dialog.ShowDialog() ==DialogResult.OK) color =dialog.Color;
pen = new Pen(color); brush = new SolidBrush(color);
}
private void menuItem24_Click(object sender, System.EventArgs e)
{
//Red color
color =Color.Red;
pen = new Pen(color); brush =
new SolidBrush(color);
}
private void menuItem25_Click(object sender, System.EventArgs e)
{
//Green color
color =Color.Green;
pen = new Pen(color); brush = new SolidBrush(color);
}
private void menuItem26_Click(object sender, System.EventArgs e)
{
//Blue color
color =Color.Blue;
pen = new Pen(color); brush = new SolidBrush(color);
}
private void menuItem27_Click(object sender, System.EventArgs e)
{
//Black color
color =Color.Black;
pen = new Pen(color); brush = new SolidBrush(color);
}
private void menuItem28_Click(object sender, System.EventArgs e)
{
//Gold color
color =Color.Gold;
pen = new Pen(color); brush = new SolidBrush(color);
}
private void menuItem29_Click(object sender, System.EventArgs e)
{
//put_left: добавление фигуры в список
listFigure.put_left(current);
}
private void menuItem30_Click(object sender, System.EventArgs e)
{
//put_right: добавление фигуры в список
listFigure.put_right(current);
}
private void menuItem31_Click(object sender, System.EventArgs e)
{
//remove: удаление фигуры из списка
if(!listFigure.empty()) listFigure.remove();
}
private void menuItem32_Click(object sender, System.EventArgs e)
{
goPrev();
}
void goPrev()
{
//go_prev: передвинуть курсор влево
if(!(listFigure.Index == 1))
{
listFigure.go_prev(); current = listFigure.item();
}
}
private void menuItem33_Click(object sender, System.EventArgs e)
{
goNext();
}
void goNext()
{
//go_next: передвинуть курсор вправо
if( !(listFigure.Index == listFigure.Count))
{
listFigure.go_next(); current = listFigure.item();
}
}
private void menuItem34_Click(object sender, System.EventArgs e)
{
//go_first listFigure.start(); if(!listFigure.empty())
current = listFigure.item();
}
private void menuItem35_Click(object sender, System.EventArgs e)
{
//go_last listFigure.finish(); if(!listFigure.empty())
current = listFigure.item();
}
private void menuItem15_Click(object sender, System.EventArgs e)
{
showList();
}
void showList()
{
//Show List listFigure.start();
while(listFigure.Index listFigure.Count)
{
current = listFigure.item(); current.Show(graphic,pen,brush); listFigure.go_next();
}
listFigure.finish();
}
private void menuItem16_Click(object sender, System.EventArgs e)
{
clearList();
}
void clearList()
{
//Clear List listFigure.start(); while(!listFigure.empty())
{
current = listFigure.item(); current.Show(graphic,clearPen,clearBrush); listFigure.remove();
}
}
private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if((current != null) && current.dragged_figure)
{
current.Show(graphic,clearPen,clearBrush); Point pt = new Point(e.X, e.Y); current.center_figure = pt; current.Show(graphic,pen,brush);
}
}
private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
current.dragged_figure = false;
}
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Point mousePoint = new Point (e.X, e.Y); Rectangle figureRect = current.Region_Capture(); if ((current != null) &&
(figureRect.Contains(mousePoint))) current.dragged_figure = true;
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
//show current figure current.Show(graphic, pen, brush);
}
private void toolBar1_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
int buttonNumber = toolBar1.Buttons.IndexOf(e.Button);
switch (buttonNumber)
{
case 0:
createEllipse(); break; case 1:
createCircle(); break; case 2:
createLittleCircle(); break; case 3:
createRectangle(); break; case 4:
createSquare(); break; case 5:
createPerson(); break; case 6:
showCurrent(); break; case 7:
clearCurrent(); break; case 8:
showList(); break; case 9:
clearList(); break; case 10:
incScale(); break; case 11:
decScale(); break; case 12:
moveLeft(); break; case 13:
moveRight(); break; case 14:
moveTop(); break; case 15:
moveDown(); break; case 16:
goNext(); break; case 17:
goPrev(); break;
}
}
}
}
Команд меню и кнопок в нашем интерфейсе много, поэтому много и обработчиков событий, что приводит к разбуханию кода. Но каждый из обработчиков событий довольно прост.
Ограничусь кратким описанием главного меню:
команды пункта главного меню Create позволяют создавать геометрические фигуры разных классов;
команды пункта главного меню Show позволяют показать или стереть текущую фигуру или все фигуры, сохраняемые в списке;
две команды пункта Scale позволяют изменить масштаб фигуры (увеличить ее или уменьшить);
команды пункта Move позволяют перемещать текущую фигуру в четырех направлениях;
команды пункта Color позволяют либо задать цвет фигур в диалоговом окне, либо выбрать один из предопределенных цветов;
группа команд пункта List позволяет помещать текущую фигуру в список, перемещаться по списку и удалять из списка ту или иную фигуру;
командные кнопки инструментальной панели соответствуют наиболее важным командам меню;
реализована возможность перетаскивания фигур по экрану мышью.
В заключение взгляните, как выглядит форма в процессе работы с объектами:
Рис. 25.1. Финальный проект. Форма в процессе работы