О будущей функциональности векторного редактора изображений
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-функции, используемые для сериализации:
publicvirtualvoidSaveToStream(SerializationInfoinfo, intorderNumber)
{
// ...
}
publicvirtualvoid LoadFromStream(SerializationInfo info, int orderNumber)
{
// ...
}
Эти функции реализованы в каждом производном классе. Двоичный сохранённый файл имеет следующий формат:
Число объектов
Имя типа
Объект
Имя типа
Объект
...
Имя типа
Объект
Это позволяет писать код общий сериализации в классе GraphicList не зная никаких подробностей о сериализованных объектов (абстрактно, для любого объекта):
privateconststring entryCount = "Count";
privateconststring entryType = "Type";
// Сохранитьсписоквпоток
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
publicvirtualvoid 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));
// СоздаёмобъектпоименитипачерезusingReflection)
drawObject = Assembly.GetExecutingAssembly().CreateInstance(
typeName);
// Заполняемобъектизпотока
((DrawObject)drawObject).LoadFromStream(info, i);
graphicsList.Add(drawObject);
}
}
Проверканажатиякнопкимыши:
Как определить, что под указателем мыши находится нарисованный ранее объект?
Класс DrawObjectимеет virtual-функциюHitTest, которая определяет, принадлежит ли точка графическому объекту (проверят, куда нажал пользователь):
publicvirtualint HitTest(Point point)
{
return -1;
}
Производные классы используют virtual PointInObject для проверки нажатия. Эта функция вызывается из HitTest. КлассDrawRectangle реализует эту функцию:
protectedoverridebool PointInObject(Point point)
{
return rectangle.Contains(point);
// rectangle - принадлежиттипу Rectangle
}
Чуть более сложный вариант определения нажатия по линии:
protectedoverridebool PointInObject(Point point)
{
GraphicsPath areaPath;
Pen areaPen;
Region areaRegion;
// Создаём путь, который содержит широкую линию
// Длялёгкоговыборамышью
AreaPath = new GraphicsPath();
AreaPen = newPen(Color.Black, 7);
AreaPath.AddLine(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
// startPoint и endPoint - принадлежаттипу Point
AreaPath.Widen(AreaPen);
// Создаём область из пути
AreaRegion = newRegion(AreaPath);
return AreaRegion.IsVisible(point);
}
Обработка состояния бездействия приложения:
Каждое Windows Forms приложениев своём составе имеетэлементы управлениятакие каккнопки пунктов меню, кнопки панелей инструментов и прочее. В зависимости от текущей ситуации и команды пользователя, эти элементы управления могут иметь различные состояния: включены/выключены, отмечены/не отмечены, видимые/невидимые и так далее. Действие пользователя может изменить это состояние. Настройка состояний элементов управления в каждом обработчике сообщений вызывать ошибку. Вместо этого, это управлять состояние элемента управлениялучше через функции, которые вызываются после каждого действия пользователя. В MFC(VisaulC++)существует функцияON_UPDATE_COMMAND_UI, которая позволяет обновить состояние кнопок панели инструментов во время бездействия приложения. Такая возможность может осуществляться также и в .NET программе.
Рассмотрим ситуацию, когда пользователь нажимает кнопку на панели инструментов (Прямоугольник). Эта кнопка должна активироваться, а ранее активный инструмент должен быть снят. Обработчик сообщений кнопки(Прямоугольник) не изменяет состояние элементов управления формы, он просто сохраняет текущее выделение кнопки в некоторой переменной. Обработчик сообщений Idle активирует инструмент и снимает выделение с неактивного инструмента. Передача изменения состояния кнопок происходит через метод, а не напрямую:
publicvoid 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);
// ...
}
// Инструмент "Прямоугольник" выбран
privatevoid CommandRectangle()
{
drawArea.ActiveTool = DrawArea.DrawToolType.Rectangle;
}
5. Модификация приложения WindowsForms: подготовка библиотеки классов
Проект LWP15Toolsбудет содержать четыре самостоятельных класса.
Для выбора, куда именно вставлять новый класс, выбираем в обозревателе решений проект LWP15Tools:
Для добавления нового файла в проект необходимо выполнить: Проект ->Добавить класс... (Shift+Alt+C). Также аналогично действие можно произвести щёлкнув на имени проекта правой кнопкой мыши, затем Добавить->Класс...:
В окне Добавление нового элемента – LWP15Tools в поле Имя вводим DocManager.cs. Также добавим в проект добавим ссылку на библиотеку System.Windows.Forms (вкладка .NETокна Добавить ссылку). Для добавления ссылки в обозревателе решений нажмём правую кнопку мыши по пункту Ссылки в проекте LWP15Toolsзатем Добавить ->Добавить ссылку...:
Текст первого файла класса DocManager.cs:[искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].
Небольшое замечание. Ранее они уже были даны в предыдущих лабораторных работах, но приводим напоминание...
Обратим внимание на следующий код:
#regionКлассDocManagerData
...
#endregion
Этот код формирует из участков кода файла блоки, которые можно закрыть нажав на «минус» слева от строчи #regionи развернуть нажав «плюс» слева от свёрнутого элемента. Выглядит это так:
Также обратим внимание вот на этот код:
///<summary>
///Открываемдокумент
///</summary>
///<param name="newFileName">
/// Имя файла документа. Empty - функция выводит OpenFileDialog
///</param>
///<returns></returns>
Это описание, в данном случае для функции. Отображается во время использования функции в любом месте, при наведении мыши на экземпляр самой функции. Например, подсвечиваем функцию из этого класса:
О самом классе. Класс выполняет достаточно много функций связанных с сопровождением файлов приложения (создание нового документа, сохранение и открытие), а также работает с системным реестром (ассоциирует тип файла программы с нашим приложением). Забегая вперёд, можно сказать что для поддержки работы с реестром необходимо Запустить приложение один раз от имени администратора для WindowsVistaи Windows 7 (если включён UACи параметрами для него выставлены по умолчанию). В этом случае всех ключи в реестре будут созданы, и дальнейшая работа приложения с ними будет обеспечена. Основной функцией класса является следующая функция:
///<summary>
///Инициализация
///</summary>
///<paramname="data"></param>
publicDocManager(DocManagerDatadata)
{
Функция инициализирует класс и принимает данные (data) для работы класса.Это данные связанные с типом файлов для приложения, в частности основная инициализация для главной формы LWP15Mainвыглядит так:
privateDocManager docManager;
...
// DocManager
DocManagerData data = newDocManagerData();
data.FormOwner = this;
data.UpdateTitle = true;
data.FileDialogFilter = "Файлы LWP15Draw (*.lwp)|*.lwp|Всефайлы (*.*)|*.*";
data.NewDocName = "New.lwp";
data.RegistryPath = registryPath;
docManager = newDocManager(data);
docManager.RegisterFileType("lwp", "lwpfile", "Файл LWP15Draw");
...
Переходим к следующему классу. Назовём файл для него PersistWindowState.cs. Для работы кода добавим новую ссылку System.Drawing.Код файла такой:[искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].
Класс отвечает за работу с окном приложения (сохраняет в реестр размер и положение окна, а также состояние минимизации окна, если приложение было свёрнуто).
Следующий файл класса будет носить имя MruManager.cs (класс MruManager). Класс будет обеспечивать работу со список недавно использованных (последних) файлов. По умолчанию будет отображаться 10 наиболее часто используемых файлов. Число символов в пути и имени не будет превышать 40. Работа списка будет выглядеть примерно так:
Код файла класса следующий: [искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].
Последний класс отвечает за открытие файла приложение перетаскиванием из проводника Windows. Имя файла класса: DragDropManager.cs. Код файла следующий:[искомый код можно найти в приложении к данной лабораторной работе в (описания можно того или иного приложения можно посмотреть в пунтке № 8 протокола работы), а именно необходимо открыть Приложение № 1 (Библиотека классов LWP15Tools)].
Такимобразом,был сформированфайлбиблиотекиLWP15Tools.dll для приложения (можно откомпилировать). Можно переходить к самому приложению.