Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторный_практикум.doc
Скачиваний:
74
Добавлен:
15.11.2019
Размер:
45.35 Mб
Скачать

4. О будущей функциональности векторного редактора изображений

LWP15Tools:

Библиотека LWP15Tools содержит набор классов, которые могут быть использованы для работы с документами в приложении Windows Forms. Экземпляры классов, из библиотеки LWP15Tools хранятся на главной форме проекта LWP15Draw и используются для общих операций, связанных с файлом документа.

Библиотека LWP15Tools будет состоять из следующих полноценных классов:

  • Класс DocManager: осуществляет операции, связанные с файлом: открытие, создание, сохранение, обновление названия формы и регистрация типа файлов для оболочки Windows.

  • Класс DragDropManager: позволяет открывать файлы из проводника Windows в приложении Windows Forms.

  • Класс MruManager: список управляет наиболее часто используемыми файлами (Последние файлы в пункте меню Файл).

  • Класс PersistWindowState: позволяет сохранить последнее состояние окна в реестре и восстановить его при загрузке главной формы.

LWP15Draw:

Структура классов приложения и наследование реализовано следующим образом:

Рис. 4. 1. Классы проекта LWP15Draw

Назначения классов (файлов) следующее:

  • DrawArea пользовательский элемент управления, который заполняет главное окно клиентской области. Содержит экземпляр класса GraphicsList. Рисует графические объекты, обрабатывает ввод от мыши передачей команд в GraphicsList. Реализует графическое пространство в явном виде для интерфейса формы.

  • GraphicsList список графических объектов. Содержит ArrayList графических объектов. «Общается» с графическими объектами в общем виде, с использованием методов DrawObject. Реализует графическое пространство в виртуальном виде приложения.

  • DrawObject абстрактный базовый класс для всех графических объектов.

  • DrawRectangle рисование графического объекта прямоугольника.

  • DrawEllipise рисование графического объекта эллипса.

  • DrawLine рисование графического объекта линии.

  • DrawPolygon рисование графического объекта непрерывной линии/карандаш.

  • Tool абстрактный базовый класс для всех инструментов рисования.

  • ToolPointer указатель инструмента (нейтральный инструмент). Содержит реализации для выбора, перемещения, изменения размера графических объектов.

  • ToolObject абстрактный базовый класс для всех инструментов, создающих новый графический объект.

  • ToolRectangle реализует инструмент «прямоугольник».

  • ToolEllipse реализует инструмент «эллипс».

  • ToolLine реализует инструмент «линия».

  • ToolPolygon реализует инструмент «непрерывная линия/карандаш».

Сериализация:

Класс GraphicList реализует интерфейс ISerializable, который позволяет производить двоичной сериализации объекта класса. Класс DrawObject имеет две virtual-функции, используемые для сериализации:

public virtual void SaveToStream(SerializationInfo info, int orderNumber)

{

// ...

}

public virtual void LoadFromStream(SerializationInfo info, int orderNumber)

{

// ...

}

Эти функции реализованы в каждом производном классе. Двоичный сохранённый файл имеет следующий формат:

Число объектов

Имя типа

Объект

Имя типа

Объект

...

Имя типа

Объект

Это позволяет писать код общий сериализации в классе GraphicList не зная никаких подробностей о сериализованных объектов (абстрактно, для любого объекта):

private const string entryCount = "Count";

private const string entryType = "Type";

// Сохранить список в поток

[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]

public virtual void GetObjectData(SerializationInfo info, StreamingContext context)

{

// Число объектов

info.AddValue(entryCount, graphicsList.Count);

int i = 0;

foreach (DrawObject o in graphicsList)

{

// Тип объекта

info.AddValue(

String.Format(CultureInfo.InvariantCulture,

"{0}{1}",

entryType, i),

o.GetType().FullName);

// Сам объект

o.SaveToStream(info, i);

i++;

}

}

// Загружаем из потока

protected GraphicsList(SerializationInfo info, StreamingContext context)

{

graphicsList = new ArrayList();

// Число объектов

int n = info.GetInt32(entryCount);

string typeName;

object drawObject;

for ( int i = 0; i < n; i++ )

{

// Тип объекта

typeName = info.GetString(

String.Format(CultureInfo.InvariantCulture,

"{0}{1}",

entryType, i));

// Создаём объект по имени типа через using Reflection)

drawObject = Assembly.GetExecutingAssembly().CreateInstance(

typeName);

// Заполняем объект из потока

((DrawObject)drawObject).LoadFromStream(info, i);

graphicsList.Add(drawObject);

}

}

Проверка нажатия кнопки мыши:

Как определить, что под указателем мыши находится нарисованный ранее объект?

Класс DrawObject имеет virtual-функцию HitTest, которая определяет, принадлежит ли точка графическому объекту (проверят, куда нажал пользователь):

public virtual int HitTest(Point point)

{

return -1;

}

Производные классы используют virtual PointInObject для проверки нажатия. Эта функция вызывается из HitTest. Класс DrawRectangle реализует эту функцию:

protected override bool PointInObject(Point point)

{

return rectangle.Contains(point);

// rectangle - принадлежит типу Rectangle

}

Чуть более сложный вариант определения нажатия по линии:

protected override bool PointInObject(Point point)

{

GraphicsPath areaPath;

Pen areaPen;

Region areaRegion;

// Создаём путь, который содержит широкую линию

// Для лёгкого выбора мышью

AreaPath = new GraphicsPath();

AreaPen = new Pen(Color.Black, 7);

AreaPath.AddLine(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);

// startPoint и endPoint - принадлежат типу Point

AreaPath.Widen(AreaPen);

// Создаём область из пути

AreaRegion = new Region(AreaPath);

return AreaRegion.IsVisible(point);

}

Обработка состояния бездействия приложения:

Каждое Windows Forms приложение в своём составе имеет элементы управления такие как кнопки пунктов меню, кнопки панелей инструментов и прочее. В зависимости от текущей ситуации и команды пользователя, эти элементы управления могут иметь различные состояния: включены/выключены, отмечены/не отмечены, видимые/невидимые и так далее. Действие пользователя может изменить это состояние. Настройка состояний элементов управления в каждом обработчике сообщений вызывать ошибку. Вместо этого, это управлять состояние элемента управления лучше через функции, которые вызываются после каждого действия пользователя. В MFC (Visaul C++) существует функция ON_UPDATE_COMMAND_UI, которая позволяет обновить состояние кнопок панели инструментов во время бездействия приложения. Такая возможность может осуществляться также и в .NET программе.

Рассмотрим ситуацию, когда пользователь нажимает кнопку на панели инструментов (Прямоугольник). Эта кнопка должна активироваться, а ранее активный инструмент должен быть снят. Обработчик сообщений кнопки (Прямоугольник) не изменяет состояние элементов управления формы, он просто сохраняет текущее выделение кнопки в некоторой переменной. Обработчик сообщений Idle активирует инструмент и снимает выделение с неактивного инструмента. Передача изменения состояния кнопок происходит через метод, а не напрямую:

public void SetStateOfControls()

{

// Выбор активного инструмента

tbPointer.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Pointer);

tbRectangle.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Rectangle);

tbEllipse.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Ellipse);

tbLine.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Line);

tbPolygon.Pushed = (drawArea.ActiveTool == DrawArea.DrawToolType.Polygon);

menuDrawPointer.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Pointer);

menuDrawRectangle.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Rectangle);

menuDrawEllipse.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Ellipse);

menuDrawLine.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Line);

menuDrawPolygon.Checked = (drawArea.ActiveTool == DrawArea.DrawToolType.Polygon);

// ...

}

// Инструмент "Прямоугольник" выбран

private void CommandRectangle()

{

drawArea.ActiveTool = DrawArea.DrawToolType.Rectangle;

}