Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Список с курсором. Динамические структуры данных





Добавим в проект классы, задающие динамические структуры данных. Конечно, можно было бы воспользоваться стандартными... Но для обучения крайне полезно уметь создавать собственные классы, задающие такие структуры данных. Список с курсором - один из важнейших образцов подобных классов%:

using System;namespace Shapes{ /// <summary> /// Класс 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 /// </summary> public class TwoWayList { public TwoWayList() { first = cursor = last = null; count = index = 0; search_res = false; }//конструктор /// <summary> /// first, cursor, last - ссылки на первый, /// активный и последний элементы списка /// Запросы count, index search_res также /// реализуются атрибутами. /// Запросы empty, item реализуются функциями /// </summary> 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); } } /// <summary> /// require: true; возвращает true для непустого списка /// </summary> /// <returns></returns> public bool empty() { return(first == null); }//empty /// <summary> /// require: not empty(); возвращает активный /// элемент типа G; /// </summary> /// <returns></returns> public Figure item() { return(cursor.Item); }//item /// <summary> /// require: true; /// ensure: добавить новый элемент (elem) слева /// от курсора; /// </summary> /// <param name="elem">Тип Figure играет роль /// родового типа G /// хранимого элемента elem</param> 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 /// <summary> /// require: true; /// ensure: добавить новый элемент (elem) справа /// от курсора; /// </summary> /// <param name="elem">Тип Figure играет роль /// родового типа G /// хранимого элемента elem</param> 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 /// операции с курсором: /// <summary> /// start: require: true; /// ensure: сделать активным первый элемент; /// </summary> public void start() { cursor = first; index = 1; }//start /// <summary> /// finish: require: true; /// ensure: сделать активным последний элемент; /// </summary> public void finish() { cursor = last; index = count; }//finish /// <summary> /// go_prev: require: not (index = 1); /// ensure: сделать активным предыдущий элемент; /// </summary> public void go_prev() { cursor = cursor.Prev; index--; }// go_prev /// <summary> /// go_next: require: not (index = count); /// ensure: сделать активным последующий элемент; /// </summary> public void go_next() { cursor = cursor.Next; index++; }// go_next /// <summary> /// go_i(i): require: (i in [1, count]); /// ensure: сделать активным элемент с индексом i; /// </summary> /// <param name="i"></param> public void go_i(int i) { if(i >index) while (i>index) { cursor = cursor.Next; index++; } else if(i<index) while (i<index) { cursor = cursor.Prev; index--; } }// go_i /// операции поиска: /// <summary> /// search_prev(elem): require: not (index = 1); /// ensure: сделать активным первый элемент elem /// слева от курсора; /// </summary> /// <param name="elem">искомый элемент</param> 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 /// <summary> /// успех или неуспех поиска сохранять в булевской /// переменной search_res /// search_next: require: not (index = count); /// ensure: сделать активным первый элемент elem /// справа от курсора; /// успех или неуспех поиска сохранять в булевской /// переменной search_res /// </summary> /// <param name="elem"></param> 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{ /// <summary> /// Класс 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 /// </summary> public class Linkable { public Linkable() { item =null; next = null; } /// <summary> /// закрытые атрибуты класса /// </summary> Figure item; Linkable next; /// <summary> /// процедуры свойства для доступа к полям класса /// </summary> public Figure Item{ get{ return(item); } set{ item = value; } } public Linkable Next{ get{ return(next); } set{ next = value; } } }//class Linkable /// <summary> /// Класс TwoLinkable задает элементы с двумя ссылками /// </summary> public class TwoLinkable { public TwoLinkable() { prev = next = null; } /// <summary> /// закрытые атрибуты класса /// </summary> TwoLinkable prev, next; Figure item; /// <summary> /// процедуры свойства для доступа к полям класса /// </summary> 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{ /// <summary> /// Эта форма обеспечивает интерфейс для создания, /// рисования, показа, перемещения, сохранения в списке /// и выполнения других операций над объектами семейства /// геометрических фигур. Форма имеет меню и /// инструментальные панели. /// </summary> 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); } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose(bool disposing) { if(disposing) { if (components!= null) { components.Dispose(); } } base.Dispose(disposing); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { // Код, инициализирующий компоненты и построенный // дизайнером, опущен } #endregion /// <summary> /// Точка входа в приложение - процедура Main, /// запускающая форму /// </summary> [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. Финальный проект. Форма в процессе работы

 







ЧТО ТАКОЕ УВЕРЕННОЕ ПОВЕДЕНИЕ В МЕЖЛИЧНОСТНЫХ ОТНОШЕНИЯХ? Исторически существует три основных модели различий, существующих между...

Конфликты в семейной жизни. Как это изменить? Редкий брак и взаимоотношения существуют без конфликтов и напряженности. Через это проходят все...

Что способствует осуществлению желаний? Стопроцентная, непоколебимая уверенность в своем...

Что делать, если нет взаимности? А теперь спустимся с небес на землю. Приземлились? Продолжаем разговор...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.