В мире, где визуальная коммуникация играет ключевую роль, а цифровые изображения стали неотъемлемой частью повседневности, инструменты для их создания и редактирования приобретают особую значимость. От простых Paint-подобных программ до мощных профессиональных пакетов, графические редакторы являются одним из самых распространенных типов прикладного программного обеспечения. Их разработка, в свою очередь, представляет собой отличную платформу для освоения фундаментальных принципов программирования, особенно объектно-ориентированного подхода, что делает эту тему весьма актуальной для академических исследований.
Цель данной курсовой работы — разработать простейший графический редактор для платформы Windows, применяя принципы объектно-ориентированного программирования (ООП) на языке C#. В рамках этой работы будут решены следующие задачи:
- Исследование теоретических основ ООП и их адаптация к специфике графических приложений.
- Анализ и выбор оптимальных технологических решений для создания Windows-приложения.
- Проектирование модульной и расширяемой архитектуры редактора с использованием паттернов проектирования.
- Реализация базового функционала графического редактора.
- Изучение и применение актуальных стандартов документирования и оценки качества программного обеспечения.
Выбор платформы Windows и языка C# обусловлен их доминирующим положением в корпоративной и пользовательской среде, а также мощной и развитой экосистемой .NET, предлагающей широкий спектр инструментов для разработки настольных приложений. C#, как современный объектно-ориентированный язык, предоставляет все необходимые конструкции для эффективной реализации сложных логических моделей, что особенно важно для управления графическими объектами.
Простейший графический редактор, который будет разработан в ходе курсовой работы, будет включать в себя базовые возможности, такие как рисование основных геометрических примитивов (линия, прямоугольник, окружность), изменение их свойств (цвет), а также интерактивное выделение и перемещение созданных объектов на холсте. Это послужит прочным фундаментом для дальнейшего расширения функционала и глубокого понимания принципов построения подобных систем, подтверждая практическую ценность освоенных навыков.
Теоретические основы объектно-ориентированного программирования в разработке графических приложений
Объектно-ориентированное программирование (ООП) — это не просто набор синтаксических правил, а целая философия построения программного обеспечения, основанная на концепции «объектов». Эти объекты, как миниатюрные автономные сущности, способны хранить данные (поля, атрибуты) и выполнять действия (методы, процедуры), имитируя объекты реального мира, что позволяет значительно повысить модульность и повторное использование кода. Именно такой подход позволяет создавать сложные, но при этом легко управляемые и масштабируемые системы, что особенно актуально для графических редакторов, где каждый элемент (фигура, инструмент) может быть представлен как отдельный объект.
В контексте графического редактора, где пользователь взаимодействует с разнообразными визуальными элементами, ООП позволяет создать стройную иерархию классов, где каждый графический примитив, будь то линия, прямоугольник или окружность, является экземпляром определенного класса. Эти классы, в свою очередь, могут обладать общими характеристиками, унаследованными от базового класса, и индивидуальными особенностями.
Инкапсуляция: сокрытие деталей реализации
Инкапсуляция, один из краеугольных камней ООП, заключается в строгом разграничении внутренней реализации объекта от его внешнего интерфейса. Это подобно черному ящику: вы знаете, что он делает, но не знаете, как он это делает. В программировании это означает, что внутренние данные объекта (например, координаты точек, цвет, толщина линии) скрыты от прямого доступа извне и могут быть изменены только через публичные методы. Таким образом, инкапсуляция обеспечивает целостность данных и защищает от нежелательных побочных эффектов.
Пример применения в графическом редакторе:
Представьте класс Line (Линия). Его внутренние данные — это две пары координат (X1, Y1) и (X2, Y2), а также цвет и толщина. Прямой доступ к этим полям извне может привести к некорректному состоянию объекта (например, одна из координат будет изменена без обновления соответствующего визуального представления). Инкапсуляция предлагает сделать эти поля приватными (private) и предоставить публичные методы-аксессоры (public properties или get/set методы) для контролируемого доступа к ним.
public class Line
{
private Point _startPoint; // Приватное поле
private Point _endPoint; // Приватное поле
private Color _color; // Приватное поле
public Point StartPoint // Публичное свойство с контролируемым доступом
{
get { return _startPoint; }
set { _startPoint = value; /* Дополнительная логика, например, перерисовка */ }
}
public Color LineColor // Публичное свойство
{
get { return _color; }
set { _color = value; /* Дополнительная логика */ }
}
public void Draw(Graphics g) // Публичный метод для рисования
{
// ... реализация рисования линии ...
}
}
Такой подход защищает данные от несанкционированного изменения, позволяет изменять внутреннюю реализацию без воздействия на внешний код, использующий объект, и делает код более надежным и легким для сопровождения. В чем же заключается основная практическая выгода? Она состоит в снижении сложности системы и повышении ее стабильности, поскольку изменения в логике хранения данных одного объекта не потребуют модификации всей программы.
Наследование: построение иерархии графических объектов
Наследование — это мощный механизм, позволяющий создавать новые классы на основе уже существующих, перенимая их свойства и методы. Это способствует повторному использованию кода и созданию иерархических структур, отражающих отношения «является» (is-a).
Пример применения в графическом редакторе:
В графическом редакторе логично предположить, что все фигуры имеют общие характеристики: цвет, положение, возможность быть нарисованными, перемещенными или измененными в размере. Создание базового абстрактного класса Shape (Фигура) позволяет инкапсулировать эту общую логику.
public abstract class Shape
{
public Color ShapeColor { get; set; }
public Point Location { get; set; } // Например, верхний левый угол bounding box
protected Shape(Color color, Point location)
{
ShapeColor = color;
Location = location;
}
public abstract void Draw(Graphics g); // Абстрактный метод, который должен быть реализован в потомках
public virtual void Move(int dx, int dy)
{
Location = new Point(Location.X + dx, Location.Y + dy);
}
// ... другие общие методы ...
}
public class Line : Shape
{
public Point EndPoint { get; set; }
public Line(Color color, Point startPoint, Point endPoint) : base(color, startPoint)
{
EndPoint = endPoint;
}
public override void Draw(Graphics g) // Переопределение абстрактного метода
{
using (Pen pen = new Pen(ShapeColor))
{
g.DrawLine(pen, Location, EndPoint);
}
}
public override void Move(int dx, int dy)
{
base.Move(dx, dy); // Вызов базового метода для перемещения StartPoint
EndPoint = new Point(EndPoint.X + dx, EndPoint.Y + dy); // Перемещение EndPoint
}
}
public class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
public Rectangle(Color color, Point location, int width, int height) : base(color, location)
{
Width = width;
Height = height;
}
public override void Draw(Graphics g)
{
using (Pen pen = new Pen(ShapeColor))
{
g.DrawRectangle(pen, Location.X, Location.Y, Width, Height);
}
}
}
Таким образом, классы Line и Rectangle наследуют общие свойства и методы от Shape, но при этом реализуют специфичное для себя поведение, например, в методе Draw(). Это уменьшает дублирование кода и упрощает добавление новых типов фигур.
Полиморфизм: унифицированная обработка различных фигур
Полиморфизм (от греч. «много форм») позволяет объектам разных классов, но имеющим общего предка или реализующим общий интерфейс, реагировать на один и тот же вызов метода по-разному, в зависимости от своего конкретного типа. Это обеспечивает гибкость и расширяемость, так как позволяет обрабатывать коллекции разнородных объектов единообразно.
Пример применения в графическом редакторе:
В редакторе имеется список всех нарисованных фигур. Без полиморфизма пришлось бы проверять тип каждой фигуры и вызывать соответствующий метод рисования:
// Без полиморфизма (неправильно)
foreach (object obj in shapes)
{
if (obj is Line)
{
((Line)obj).DrawLineSpecificMethod(g);
}
else if (obj is Rectangle)
{
((Rectangle)obj).DrawRectangleSpecificMethod(g);
}
// ... и так далее
}
С использованием полиморфизма, благодаря наследованию от Shape и переопределению метода Draw(), код становится значительно проще и чище:
// С полиморфизмом (правильно)
List<Shape> shapes = new List<Shape>();
shapes.Add(new Line(Color.Black, new Point(10, 10), new Point(100, 100)));
shapes.Add(new Rectangle(Color.Red, new Point(50, 50), 80, 60));
shapes.Add(new Circle(Color.Blue, new Point(120, 120), 40));
foreach (Shape shape in shapes)
{
shape.Draw(g); // Вызов Draw() для каждого объекта, который знает, как себя нарисовать
}
Здесь каждый объект в списке shapes, несмотря на то что он хранится как Shape, при вызове Draw() выполняет свою специфическую реализацию. Это позволяет легко добавлять новые типы фигур в список без изменения логики перерисовки всего холста.
Абстракция: выделение общих характеристик
Абстракция — это процесс выделения существенных характеристик объекта и игнорирования несущественных деталей для создания более общего и понятного представления. В ООП она реализуется через абстрактные классы и интерфейсы. Абстрактный класс может содержать как реализованные методы, так и абстрактные (без реализации), которые должны быть переопределены в классах-наследниках. Интерфейс же определяет только «контракт» — набор методов, которые должны быть реализованы.
Пример применения в графическом редакторе:
Абстрактный класс Shape, рассмотренный в разделе о наследовании, является ярким примером абстракции. Он определяет, что любая фигура должна иметь цвет, положение и уметь рисоваться (Draw()), но не диктует, как именно она должна рисоваться. Это позволяет создать универсальный каркас для всех графических примитивов.
Другим примером может быть интерфейс IMovable (Перемещаемый) или ISelectable (Выделяемый), если не все фигуры могут быть перемещены или выделены по одному и тому же принципу:
public interface IMovable
{
void Move(int dx, int dy);
}
public interface ISelectable
{
bool ContainsPoint(Point p); // Определяет, находится ли точка внутри фигуры
void Select();
void Deselect();
}
public class Line : Shape, IMovable, ISelectable
{
// ... реализация методов Move и ContainsPoint ...
}
public class TextBlock : Shape // Предположим, текстовый блок не перемещается, а только рисуется
{
// ... реализация только Draw(), без IMovable ...
}
Абстракция позволяет сосредоточиться на «что» объект делает, а не на «как», упрощая проектирование и делая систему более гибкой и модульной. В графическом редакторе это критически важно для управления сложностью и обеспечения возможности добавления новых, совершенно разных по своей природе элементов. Разве не в этом заключается истинная сила хорошо спроектированной системы?
Выбор технологической платформы и инструментальных средств для Windows-приложений
Выбор технологического стека является фундаментальным шагом в разработке любого приложения, определяющим его производительность, внешний вид, сложность поддержки и потенциал для дальнейшего развития. В контексте создания графического редактора для Windows, ключевыми игроками являются платформы .NET Framework и современные версии .NET, а также фреймворки пользовательского интерфейса WinForms и WPF.
Обзор .NET Framework и .NET (Core)
Платформа .NET от Microsoft прошла долгий путь эволюции. Изначально, в начале 2000-х, был представлен .NET Framework — комплексная платформа для разработки различных типов приложений, включая настольные, веб- и мобильные. Он принес такие инновации, как Common Language Runtime (CLR) для управления выполнением кода и унифицированную библиотеку классов (BCL).
Однако со временем стало ясно, что .NET Framework, будучи тесно привязанным к Windows и обладая значительным монолитным объемом, не всегда отвечал требованиям кросс-платформенной и облачной разработки. Это привело к появлению .NET Core в 2016 году — модульной, кросс-платформенной и высокопроизводительной реализации .NET, ориентированной на облачные сервисы и контейнеризацию.
Впоследствии, начиная с версии 5, Microsoft объединила .NET Framework и .NET Core под единым названием .NET. Сегодня, 28.10.2025, актуальными являются версии .NET 5, .NET 6, .NET 7, .NET 8 и уже анонсирован .NET 9, которые представляют собой унифицированную, кросс-платформенную платформу с открытым исходным кодом. Она включает в себя все лучшее от своих предшественников, предлагая современный стек для разработки настольных, веб-, мобильных, облачных и IoT-приложений. Для курсовой работы, ориентированной на актуальные практики, предпочтительно использовать именно современные версии .NET (начиная с .NET 5 и выше). Этот выбор обусловлен не только современными тенденциями, но и активной поддержкой со стороны Microsoft, гарантирующей постоянное развитие и улучшение платформы.
Сравнительный анализ Windows Forms (WinForms) и Windows Presentation Foundation (WPF)
В экосистеме .NET для создания настольных Windows-приложений исторически конкурируют две основные технологии: Windows Forms (WinForms) и Windows Presentation Foundation (WPF).
Windows Forms (WinForms)
- Архитектура: WinForms появилась в 2002 году как часть .NET Framework 1.0. Она представляет собой высокоуровневую обертку вокруг низкоуровневого Win32 API, что делает её по сути надстройкой над традиционной Windows-графикой GDI/GDI+.
- Преимущества:
- Простота и интуитивность: Использование визуального дизайнера в Visual Studio делает быстрое прототипирование и создание простых интерфейсов чрезвычайно легким. Кривая обучения для новичков относительно пологая.
- Зрелость и проверенность: Технология существует более двух десятилетий, что означает огромное количество примеров, готовых решений и сторонних компонентов.
- Активная поддержка в .NET 5+: Вопреки распространенному заблуждению, WinForms не заброшена. В современном .NET (начиная с .NET 5 и далее, например, в .NET 9) она активно развивается, получает улучшения производительности, безопасности, новые возможности и обновленную поддержку в Visual Studio. Сторонние разработчики элементов управления также продолжают активно поддерживать свои продукты для WinForms.
- Недостатки:
- Ограниченная гибкость стилизации: Изменение внешнего вида стандартных элементов управления часто требует сложной ручной прорисовки.
- Отсутствие аппаратного ускорения: Рендеринг через GDI+ не использует GPU, что может быть заметно для ресурсоемкой графики или анимации.
- Проблемы с масштабированием и DPI: Приложения могут выглядеть неоптимально на экранах с высоким разрешением или при изменении системного масштаба, хотя в современных .NET версиях эти проблемы активно решаются.
- Не отвечает некоторым современным стандартам разработки в части гибкости стилизации, анимации и расширенных возможностей привязки данных по сравнению с WPF.
Windows Presentation Foundation (WPF)
- Архитектура: WPF, представленная с .NET Framework 3.0, является более современной и мощной графической системой. Она спроектирована под влиянием технологий HTML и Flash и полностью использует аппаратное ускорение через DirectX для рендеринга.
- Преимущества:
- Аппаратное ускорение: Использование DirectX обеспечивает высокую производительность и плавность анимаций, что критично для сложных графических приложений.
- Гибкость настройки внешнего вида (стилизация и шаблоны): WPF использует язык декларативной разметки XAML (XML-based Application Extensible Markup Language), который позволяет создавать сложные, кастомизированные интерфейсы, легко применять стили и шаблоны к любым элементам управления.
- Поддержка мультимедиа: Встроенная поддержка анимации, звука, видео и 3D-графики.
- Улучшенная привязка данных (Data Binding): Мощная система привязки данных значительно упрощает синхронизацию UI с бизнес-логикой.
- Независимость от разрешения: Векторный рендеринг позволяет приложениям масштабироваться без потери качества на любых экранах.
- Недостатки:
- Крутая кривая обучения: Изучение XAML, паттерна MVVM (Model-View-ViewModel) и специфики WPF требует значительно больше времени и усилий, чем освоение WinForms.
- Более долгая начальная разработка: Для простых приложений WPF может показаться избыточным, и время разработки может быть дольше из-за необходимости более глубокого проектирования и использования XAML.
- Потенциальное непредсказуемое поведение при изменении темы: Приложения могут перезагружаться или переинициализироваться, а также демонстрировать неожиданное визуальное поведение при изменении системных тем, например, режима высокой контрастности. Это часто требует явной обработки системных сообщений, таких как
WM_DWMCOMPOSITIONCHANGEDиWM_THEMECHANGED, или переопределения соответствующих методов для корректной адаптации. - Размер приложения: WPF-приложения обычно имеют больший размер по сравнению с WinForms.
Обоснование выбора для курсовой работы:
Для простейшего графического редактора, котор��й является частью курсовой работы и нацелен на демонстрацию принципов ООП и базовых графических операций, Windows Forms (WinForms) в связке с современным .NET (например, .NET 7 или .NET 8) является оптимальным выбором.
- Быстрота реализации: WinForms позволяет быстро создать функциональный прототип и сосредоточиться на логике, а не на дизайне.
- Простота освоения: Для студента, который только начинает изучать разработку GUI, WinForms предлагает более мягкий входной барьер, позволяя сосредоточиться на ООП и алгоритмах рисования.
- Достаточность функционала: GDI+ в WinForms более чем достаточно для рисования базовых геометрических примитивов.
- Актуальность: Хотя WPF считается более современным, активная поддержка и развитие WinForms в .NET 5+ делает её вполне релевантным инструментом для обучения и практического применения.
| Характеристика | Windows Forms (WinForms) | Windows Presentation Foundation (WPF) |
|---|---|---|
| Год выпуска | 2002 (Framework 1.0) | 2006 (Framework 3.0) |
| Основа рендеринга | GDI/GDI+ (Win32 API), пиксельно-ориентированная | DirectX, векторная, аппаратное ускорение |
| Язык UI | C#, VB.NET (код-ориентированный, дизайнер) | XAML (декларативный), C# (код-логика) |
| Кривая обучения | Пологая, быстрое прототипирование | Крутая, требует изучения XAML и MVVM |
| Гибкость UI | Ограниченная стилизация, сложно кастомизировать | Высокая кастомизация, мощная система стилей и шаблонов |
| Производительность | Хорошая для простых UI, без аппаратного ускорения | Высокая, благодаря аппаратному ускорению (особенно для сложной графики) |
| Привязка данных | Базовая, требует ручной синхронизации | Продвинутая, мощные механизмы Data Binding |
| Масштабирование DPI | Могут быть проблемы (улучшения в .NET 5+) | Отличная, векторная природа |
| Поддержка в .NET | Активно поддерживается и развивается в .NET 5+ | Активно поддерживается и развивается в .NET 5+ |
| Целевое применение | Простые бизнес-приложения, быстрые прототипы, утилиты | Сложные LOB-приложения, мультимедийные, с кастомным UI, научные визуализации |
Графический интерфейс программирования (API) GDI+
GDI+ (Graphics Device Interface Plus) — это основной интерфейс программирования приложений (API) в Microsoft Windows для работы с двумерной векторной и растровой графикой. Он является неотъемлемой частью WinForms и предоставляет набор классов в управляемом коде через пространства имен System.Drawing, System.Drawing.Drawing2D, System.Drawing.Imaging, System.Drawing.Text и System.Drawing.Printing.
Назначение и возможности:
- Изоляция от устройства: GDI+ позволяет разработчику рисовать на логической поверхности, не заботясь о деталях конкретного графического устройства (экран, принтер). Система сама адаптирует команды рисования под особенности драйвера и аппаратного обеспечения.
- Рисование примитивов: С помощью GDI+ можно легко отображать различные графические примитивы: линии, прямоугольники, эллипсы, дуги, многоугольники, кривые Безье.
- Текст и изображения: Предоставляет функционал для вывода текста с различными шрифтами и стилями, а также для загрузки, отображения и манипуляции растровыми изображениями.
- Заливка и обводка: Позволяет использовать объекты
Penдля определения характеристик линий (цвет, ширина, стиль) иBrushдля заливки замкнутых фигур (сплошной цвет, градиент, текстура).
Сравнение подходов к рендерингу:
- GDI+ (немедленный рендеринг): В GDI+ используется модель «немедленного рендеринга» (immediate mode rendering). Это означает, что каждый раз, когда требуется обновить часть экрана (например, при перерисовке окна, изменении размера или перемещении фигуры), приложение должно самостоятельно перерисовать всю затронутую область. Система не хранит информацию о том, что было нарисовано, а лишь предоставляет контекст рисования (
Graphicsобъект). Разработчик должен хранить состояние всех объектов для рисования и вызывать их методыDraw()в соответствующем событии (например,Paintдля WinForms). - WPF (retained rendering): WPF, напротив, использует модель «сохраняемого рендеринга» (retained mode rendering) на базе DirectX. Здесь система отслеживает информацию о рисовании (векторные инструкции, описание объектов), а сам процесс рисования (рендеринг) выполняет графическая подсистема. Разработчик описывает, что должно быть нарисовано (в XAML или коде), а WPF берет на себя эффективное управление и перерисовку. Это обеспечивает аппаратное ускорение и более сложную композицию.
Концепция пиксельно-ориентированной графики GDI+:
GDI+ по своей природе является пиксельно-ориентированным, то есть работает с растровыми изображениями и примитивами, которые в конечном итоге преобразуются в набор пикселей на экране. При масштабировании такой графики могут наблюдаться артефакты (ступенчатость, размытость), так как увеличиваются или уменьшаются сами пиксели. WPF же основан на векторной графике, где объекты описываются математически. Это позволяет масштабировать их без потери качества на любой размер.
Несмотря на пиксельно-ориентированную природу, GDI+ остается мощным и достаточно быстрым инструментом для реализации большинства 2D-графических операций в WinForms, что делает его идеальным для создания простейшего графического редактора в рамках курсовой работы.
Архитектура приложения: применение паттернов проектирования
Разработка сложного программного продукта требует не только понимания синтаксиса языка, но и умения строить масштабируемые, гибкие и поддерживаемые системы. Именно здесь на помощь приходят архитектурные паттерны и паттерны проектирования. Шаблон проектирования (паттерн) — это не готовый код, а проверенное временем, повторяемое архитектурное решение для часто встречающихся проблем в разработке. Объектно-ориентированные шаблоны фокусируются на отношениях и взаимодействиях между классами и объектами, а архитектурные паттерны охватывают структуру всей программной системы.
Паттерн Model-View-ViewModel (MVVM)
Паттерн MVVM (Model-View-ViewModel) является одним из наиболее популярных архитектурных паттернов для разработки клиентских приложений, особенно в экосистеме .NET. Он был представлен Джоном Госсманом в 2005 году как модификация шаблона Presentation Model и первоначально был нацелен на разработку приложений в WPF, где мощные возможности привязки данных (data binding) позволяют ViewModel напрямую предоставлять данные и команды, к которым View может привязываться.
Компоненты MVVM:
- Модель (Model): Представляет данные и бизнес-логику приложения. Она независима от пользовательского интерфейса и содержит информацию о состоянии приложения (например, список графических фигур, их свойства). Модель может уведомлять ViewModel об изменениях своего состояния.
- Представление (View): Это пользовательский интерфейс приложения (UI). В WPF это XAML-файлы, в WinForms — формы и элементы управления. View отображает данные, предоставляемые ViewModel, и отправляет пользовательские действия (клики, ввод) в ViewModel через команды или события. View не содержит бизнес-логики.
- Модель Представления (ViewModel): Является связующим звеном между View и Model. ViewModel преобразует данные из Model в формат, удобный для отображения в View, и обрабатывает команды из View, обновляя Model. Она содержит логику представления, которая не относится напрямую к бизнес-логике Model. ViewModel также реализует интерфейс
INotifyPropertyChangedдля уведомления View об изменениях своих свойств, обеспечивая двустороннюю привязку данных.
Применимость MVVM:
MVVM идеально подходит для WPF-приложений благодаря тесной интеграции с XAML и мощными механизмами привязки данных. Для WinForms, особенно в устаревшем .NET Framework 4.x, чаще использовались паттерны MVP (Model-View-Presenter) или классический MVC, так как встроенные возможности привязки данных были менее развиты. Однако в современных версиях .NET (начиная с .NET 7 и новее), где WinForms активно развивается, паттерн MVVM также может быть успешно адаптирован и применен. Это требует создания более явных механизмов привязки данных и команд, но позволяет сохранить преимущества разделения логики.
В графическом редакторе MVVM может использоваться следующим образом:
- Model: Классы
Shape,Line,Rectangle,Circleи коллекция этих фигур. - View: Основная форма WinForms с
PictureBox(холстом для рисования) и панелями для выбора цвета, типа фигуры и т.д. - ViewModel: Класс
EditorViewModel, который содержит коллекциюObservableCollection<ShapeViewModel>, гдеShapeViewModelявляется оберткой дляShapeс логикой представления (например, выделение фигуры). ViewModel предоставляет команды для рисования, перемещения, изменения цвета и свойств фигур.
Паттерн Model-View-Controller (MVC)
Паттерн MVC (Model-View-Controller) является одним из самых ранних и фундаментальных архитектурных паттернов, разработанным Трюгве Реенскаугом в 1979 году для языка Smalltalk. Он стал «непреходящим шаблоном проектирования», используемым в системах с конца 1970-х годов и до сих пор.
Компоненты MVC:
- Модель (Model): Аналогично MVVM, это данные и бизнес-логика приложения. Модель не имеет прямого знания о View или Controller. Она уведомляет View об изменениях своего состояния.
- Представление (View): Ответственно за отображение данных Модели пользователю. View получает данные от Модели и отображает их. При этом View не обрабатывает пользовательский ввод напрямую.
- Контроллер (Controller): Связующее звено. Он принимает пользовательский ввод (например, клики мыши, нажатия клавиш), интерпретирует его, передает соответствующие команды Модели для изменения данных и/или сообщает View о необходимости обновления. Контроллер не содержит бизнес-логики, но координирует взаимодействие между View и Model.
Применение в графическом редакторе:
В графическом редакторе MVC мог бы быть реализован так:
- Model: Классы
Shape,Line,Rectangle,Circleи коллекция этих фигур. - View: Основная форма WinForms с
PictureBox, которая отображает фигуры. - Controller: Класс
EditorController, который обрабатывает события мыши (MouseDown,MouseMove,MouseUp) наPictureBox. Он определяет, какая фигура была выбрана, изменяет её свойства через Model и затем сообщает View о необходимости перерисовки.
MVC обеспечивает четкое разделение обязанностей, что упрощает разработку, тестирование и поддержку кода, но может быть менее гибок в плане UI-специфической логики, чем MVVM, особенно когда дело доходит до сложных привязок данных.
Порождающие паттерны: Фабричный метод
Фабричный метод (Factory Method) — это порождающий паттерн проектирования, который определяет интерфейс для создания объектов, но делегирует решение о том, объект какого класса создавать, подклассам. Этот паттерн применяется, когда заранее неизвестно, объекты каких типов необходимо создавать, или когда система должна быть независимой от процесса создания новых объектов и расширяемой.
Применение в графическом редакторе:
В графическом редакторе пользователю предоставляется выбор инструмента для рисования (линия, прямоугольник, окружность). Вместо того чтобы в одном месте иметь громоздкий if-else или switch блок для создания разных типов фигур, можно использовать Фабричный метод.
// Абстрактный "продукт"
public abstract class Shape
{
// ... как описано ранее ...
}
// Конкретные "продукты"
public class Line : Shape { /* ... */ }
public class Rectangle : Shape { /* ... */ }
public class Circle : Shape { /* ... */ }
// Абстрактный "создатель"
public abstract class ShapeFactory
{
public abstract Shape CreateShape(Color color, Point startPoint, Point endPoint);
}
// Конкретные "создатели"
public class LineFactory : ShapeFactory
{
public override Shape CreateShape(Color color, Point startPoint, Point endPoint)
{
return new Line(color, startPoint, endPoint);
}
}
public class RectangleFactory : ShapeFactory
{
public override Shape CreateShape(Color color, Point startPoint, Point endPoint)
{
// Для прямоугольника endPoint может быть нижним правым углом
int width = Math.Abs(endPoint.X - startPoint.X);
int height = Math.Abs(endPoint.Y - startPoint.Y);
Point topLeft = new Point(Math.Min(startPoint.X, endPoint.X), Math.Min(startPoint.Y, endPoint.Y));
return new Rectangle(color, topLeft, width, height);
}
}
// Использование
ShapeFactory currentFactory;
// ... в зависимости от выбранного инструмента ...
// currentFactory = new LineFactory();
// currentFactory = new RectangleFactory();
Shape newShape = currentFactory.CreateShape(currentColor, clickPoint, releasePoint);
shapes.Add(newShape);
Это позволяет легко добавлять новые типы фигур, создавая для них новые фабрики, без изменения кода, который использует эти фабрики.
Поведенческие паттерны: Стратегия
Паттерн Стратегия (Strategy) определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Это позволяет алгоритму изменяться независимо от клиента, который его использует. Применяется, когда есть несколько способов выполнения одной и той же задачи, и необходимо иметь возможность переключаться между ними во время выполнения программы.
Применение в графическом редакторе:
В графическом редакторе могут быть различные режимы работы: рисование линии, рисование прямоугольника, выделение, перемещение. Каждый из этих режимов требует своей логики обработки событий мыши. Вместо того чтобы использовать большой switch оператор, можно применить паттерн Стратегия.
// Интерфейс стратегии
public interface IDrawingStrategy
{
void OnMouseDown(MouseEventArgs e, List<Shape> shapes, Graphics g);
void OnMouseMove(MouseEventArgs e, List<Shape> shapes, Graphics g);
void OnMouseUp(MouseEventArgs e, List<Shape> shapes, Graphics g);
}
// Конкретная стратегия для рисования линии
public class LineDrawingStrategy : IDrawingStrategy
{
private Point _startPoint;
private Line _currentLine;
public void OnMouseDown(MouseEventArgs e, List<Shape> shapes, Graphics g)
{
_startPoint = e.Location;
_currentLine = new Line(Color.Black, _startPoint, _startPoint);
shapes.Add(_currentLine); // Добавляем временную линию
}
public void OnMouseMove(MouseEventArgs e, List<Shape> shapes, Graphics g)
{
if (_currentLine != null && e.Button == MouseButtons.Left)
{
_currentLine.EndPoint = e.Location;
// Перерисовка только текущей линии или всей области
}
}
public void OnMouseUp(MouseEventArgs e, List<Shape> shapes, Graphics g)
{
_currentLine = null; // Завершили рисование
}
}
// Класс-контекст, который использует стратегию
public class DrawingPanel
{
public IDrawingStrategy CurrentStrategy { get; set; }
private List<Shape> _shapes;
private Graphics _graphics;
public DrawingPanel(List<Shape> shapes, Graphics g)
{
_shapes = shapes;
_graphics = g;
}
public void HandleMouseDown(MouseEventArgs e)
{
CurrentStrategy?.OnMouseDown(e, _shapes, _graphics);
}
// ... аналогично для MouseMove, MouseUp ...
}
В зависимости от выбранного инструмента, CurrentStrategy будет меняться на LineDrawingStrategy, RectangleDrawingStrategy или SelectionStrategy. Это позволяет легко добавлять новые режимы работы, не затрагивая основной код панели рисования. Практическая выгода здесь очевидна: значительное упрощение расширения функционала без риска внесения ошибок в уже работающие части системы.
Принципы SOLID и их роль в архитектуре
Принципы SOLID — это пять основных принципов объектно-ориентированного проектирования, которые помогают создавать более чистое, гибкое, расширяемое и легко поддерживаемое программное обеспечение. Они были сформулированы Робертом Мартином и являются неотъемлемой частью современного подхода к разработке.
- S — Single Responsibility Principle (Принцип единственной ответственности): Каждый класс должен иметь только одну причину для изменения, то есть одну ответственность. В графическом редакторе класс
Shapeдолжен отвечать только за описание фигуры, а классDrawingEngine— за её отрисовку. - O — Open/Closed Principle (Принцип открытости/закрытости): Программные сущности (классы, модули, функции) должны быть открыты для расширения, но закрыты для модификации. Это означает, что можно добавлять новую функциональность, не изменяя существующий, уже протестированный код. Наследование и полиморфизм, а также паттерны Фабричный метод и Стратегия, напрямую реализуют этот принцип, позволяя добавлять новые фигуры или режимы рисования без изменения базовых классов или основной логики.
- L — Liskov Substitution Principle (Принцип подстановки Барбары Лисков): Объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы. Если
LineявляетсяShape, то любой код, работающий сShape, должен корректно работать и сLine. Это обеспечивает надежность и предсказуемость полиморфного поведения. - I — Interface Segregation Principle (Принцип разделения интерфейса): Клиенты не должны зависеть от интерфейсов, которые они не используют. Вместо одного большого интерфейса лучше создать несколько маленьких, специфичных для конкретных нужд. Например,
IMovableиISelectableвместо одногоIShapeOperations. - D — Dependency Inversion Principle (Принцип инверсии зависимостей): Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. Это достигается за счет использования интерфейсов и абстрактных классов, а также внедрения зависимостей. Например,
DrawingPanelзависит отIDrawingStrategy, а не отLineDrawingStrategyнапрямую.
Применение принципов SOLID в архитектуре графического редактора приведет к созданию более гибкой, тестируемой и легко сопровождаемой системы, способной к будущему расширению.
Реализация ключевых функций графического редактора
После тщательного анализа теоретических основ ООП и выбора технологического стека, переходим к практической реализации базовых функций простейшего графического редактора. Этот раздел детализирует алгоритмы и подходы, необходимые для создания интерактивного холста, способного отображать и манипулировать графическими примитивами.
Проектирование классов графических примитивов
Центральным элементом любого графического редактора является способность работать с различными фигурами. Объектно-ориентиро��анный подход позволяет создать логичную иерархию классов, которая упрощает управление этими фигурами. Как уже упоминалось, базовый абстрактный класс Shape станет фундаментом.
public abstract class Shape
{
public Color ShapeColor { get; set; }
public Point Location { get; set; } // Координаты (например, верхний левый угол bounding box)
public bool IsSelected { get; set; } // Флаг для выделения фигуры
protected Shape(Color color, Point location)
{
ShapeColor = color;
Location = location;
IsSelected = false;
}
public abstract void Draw(Graphics g); // Метод для отрисовки
public virtual void Move(int dx, int dy) // Метод для перемещения
{
Location = new Point(Location.X + dx, Location.Y + dy);
}
public abstract void Resize(int newWidth, int newHeight); // Абстрактный метод для изменения размера
public abstract bool ContainsPoint(Point p); // Проверка попадания точки в фигуру
}
public class Line : Shape
{
public Point EndPoint { get; set; }
public Line(Color color, Point startPoint, Point endPoint) : base(color, startPoint)
{
EndPoint = endPoint;
}
public override void Draw(Graphics g)
{
using (Pen pen = new Pen(ShapeColor, IsSelected ? 3 : 1)) // Увеличиваем толщину при выделении
{
g.DrawLine(pen, Location, EndPoint);
}
}
public override void Move(int dx, int dy)
{
base.Move(dx, dy);
EndPoint = new Point(EndPoint.X + dx, EndPoint.Y + dy);
}
public override void Resize(int newWidth, int newHeight)
{
// Для линии изменение размера может означать пропорциональное изменение конечной точки
// Или пересчет на основе bounding box
// В простейшем редакторе можно не реализовывать или сделать базовую логику.
// Для примера оставим заглушку
}
public override bool ContainsPoint(Point p)
{
// Проверка попадания точки на линию (сложнее, чем для прямоугольника, нужно учитывать толщину)
// Для простоты можно использовать приблизительный метод:
// расстояние от точки до линии должно быть меньше некоторого порога.
// Или для курсовой работы ограничиться bounding box.
RectangleF boundingBox = GetBoundingBox();
return boundingBox.Contains(p);
}
private RectangleF GetBoundingBox()
{
float minX = Math.Min(Location.X, EndPoint.X);
float minY = Math.Min(Location.Y, EndPoint.Y);
float maxX = Math.Max(Location.X, EndPoint.X);
float maxY = Math.Max(Location.Y, EndPoint.Y);
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
}
}
public class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
public Rectangle(Color color, Point location, int width, int height) : base(color, location)
{
Width = width;
Height = height;
}
public override void Draw(Graphics g)
{
using (Pen pen = new Pen(ShapeColor, IsSelected ? 3 : 1))
{
g.DrawRectangle(pen, Location.X, Location.Y, Width, Height);
}
}
public override void Resize(int newWidth, int newHeight)
{
Width = newWidth;
Height = newHeight;
}
public override bool ContainsPoint(Point p)
{
return p.X >= Location.X && p.X <= Location.X + Width &&
p.Y >= Location.Y && p.Y <= Location.Y + Height;
}
}
public class Circle : Shape
{
public int Radius { get; set; }
public Circle(Color color, Point center, int radius) : base(color, new Point(center.X - radius, center.Y - radius))
{
Radius = radius;
}
public override void Draw(Graphics g)
{
using (Pen pen = new Pen(ShapeColor, IsSelected ? 3 : 1))
{
g.DrawEllipse(pen, Location.X, Location.Y, Radius * 2, Radius * 2);
}
}
public override void Move(int dx, int dy)
{
base.Move(dx, dy); // Перемещаем верхний левый угол ограничивающего прямоугольника
}
public override void Resize(int newRadius, int newHeight = 0) // newHeight игнорируется для круга
{
Radius = newRadius;
// Пересчет Location, чтобы она оставалась верхним левым углом нового ограничивающего прямоугольника
Location = new Point(Location.X + (Radius - newRadius), Location.Y + (Radius - newRadius));
}
public override bool ContainsPoint(Point p)
{
Point center = new Point(Location.X + Radius, Location.Y + Radius);
// Проверка по формуле расстояния до центра
double distance = Math.Sqrt(Math.Pow(p.X - center.X, 2) + Math.Pow(p.Y - center.Y, 2));
return distance <= Radius;
}
}
Механизм рисования на поверхности
В WinForms основной механизм рисования связан с классом Graphics и событием Paint элемента управления (чаще всего PictureBox или сама Form).
- Класс
Graphics: ОбъектGraphicsпредставляет собой поверхность для рисования. Он предоставляется в аргументах событияPaint(PaintEventArgs e.Graphics). Все операции рисования выполняются через методы этого объекта. - Объект
Pen: Используется для рисования линий, контуров фигур и текста. Он определяет цвет, ширину и стиль линии. - Объект
Brush: Используется для заливки внутренних областей замкнутых фигур.
Пример реализации события
Paint:
// В классе формы или пользовательского элемента управления (например, MyDrawingPanel)
private List<Shape> _shapes = new List<Shape>(); // Список всех нарисованных фигур
private void drawingPanel_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
// Опционально: включить сглаживание для более качественной графики
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
foreach (Shape shape in _shapes)
{
shape.Draw(g); // Полиморфный вызов метода рисования для каждой фигуры
}
}
// Когда нужно перерисовать холст (например, после добавления фигуры или изменения её свойств)
private void InvalidateDrawingPanel()
{
drawingPanel.Invalidate(); // Заставляет элемент управления перерисоваться, вызывая событие Paint
}
Обработка пользовательского ввода
Интерактивное рисование и манипуляция фигурами требуют обработки событий мыши. Основные события: MouseDown, MouseMove, MouseUp.
// В классе формы или DrawingPanel
private Point _lastMousePosition;
private Shape _selectedShape;
private bool _isDrawing = false;
private ShapeFactory _currentShapeFactory; // Для использования Фабричного метода
private Shape _currentDrawingShape; // Фигура, которая рисуется в данный момент
public DrawingPanel()
{
// ... инициализация ...
_currentShapeFactory = new LineFactory(); // По умолчанию рисуем линии
}
private void drawingPanel_MouseDown(object sender, MouseEventArgs e)
{
_lastMousePosition = e.Location;
if (e.Button == MouseButtons.Left)
{
// Попытка выделить фигуру
_selectedShape = null;
foreach (Shape shape in _shapes.AsEnumerable().Reverse()) // Обратный порядок, чтобы выбирать верхнюю
{
if (shape.ContainsPoint(e.Location))
{
_selectedShape = shape;
break;
}
}
// Если фигура выделена, можно начать её перемещение.
// Если нет, начинаем рисование новой фигуры (или снимаем выделение).
if (_selectedShape != null)
{
// Снимаем выделение со всех остальных, выделяем текущую
foreach (Shape shape in _shapes) shape.IsSelected = false;
_selectedShape.IsSelected = true;
}
else
{
// Снимаем выделение со всех, если клик вне фигур
foreach (Shape shape in _shapes) shape.IsSelected = false;
_isDrawing = true;
_currentDrawingShape = _currentShapeFactory.CreateShape(Color.Black, e.Location, e.Location);
_shapes.Add(_currentDrawingShape);
}
}
InvalidateDrawingPanel();
}
private void drawingPanel_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (_isDrawing && _currentDrawingShape != null)
{
// Обновляем конечные точки рисуемой фигуры
if (_currentDrawingShape is Line line)
{
line.EndPoint = e.Location;
}
else if (_currentDrawingShape is Rectangle rect)
{
int width = Math.Abs(e.X - _lastMousePosition.X);
int height = Math.Abs(e.Y - _lastMousePosition.Y);
rect.Location = new Point(Math.Min(_lastMousePosition.X, e.X), Math.Min(_lastMousePosition.Y, e.Y));
rect.Width = width;
rect.Height = height;
}
// ... и для других фигур ...
}
else if (_selectedShape != null)
{
// Перемещаем выделенную фигуру
int dx = e.X - _lastMousePosition.X;
int dy = e.Y - _lastMousePosition.Y;
_selectedShape.Move(dx, dy);
_lastMousePosition = e.Location; // Обновляем последнюю позицию мыши
}
InvalidateDrawingPanel(); // Перерисовываем холст
}
}
private void drawingPanel_MouseUp(object sender, MouseEventArgs e)
{
_isDrawing = false;
_currentDrawingShape = null;
InvalidateDrawingPanel();
}
Этот скелет обработки событий можно расширить для изменения цвета, размера, добавления новых инструментов, используя паттерн Стратегия для переключения режимов.
Реализация операций сохранения и загрузки изображений
Сохранение и загрузка состояния редактора — это критически важный функционал. В простейшем редакторе это может означать сохранение списка объектов Shape и их свойств.
Подходы к сохранению:
- Сериализация в XML/JSON: Самый гибкий и читаемый способ. Можно использовать
XmlSerializerилиJsonConvert(из библиотеки Json.NET) для преобразования спискаList<Shape>в текстовый формат. Это потребует, чтобы классыShapeи его потомки были сериализуемыми (например, с атрибутами[Serializable]или[JsonProperty]). - Бинарная сериализация: Для более компактного хранения, но менее читаемого формата. Используется
BinaryFormatter(но следует учесть, чтоBinaryFormatterустаревает и имеет проблемы с безопасностью, поэтому для новых проектов лучше предпочесть другие методы). - Сохранение как растровое изображение (PNG/JPEG): Если нужно сохранить только финальное изображение, а не редактируемые объекты, можно создать
BitmapизdrawingPanelи сохранить его:
// Сохранение текущего состояния холста как изображения
private void SaveImage(string filePath)
{
using (Bitmap bmp = new Bitmap(drawingPanel.Width, drawingPanel.Height))
{
drawingPanel.DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, drawingPanel.Width, drawingPanel.Height));
bmp.Save(filePath, ImageFormat.Png); // Можно выбрать ImageFormat.Jpeg, .Bmp и т.д.
}
}
Для сохранения и загрузки объектов Shape рекомендуется использовать JSON-сериализацию как современный и гибкий подход:
// Для сохранения списка фигур
public void SaveShapes(string filePath)
{
string json = JsonConvert.SerializeObject(_shapes, Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto // Важно для сериализации полиморфных объектов
});
File.WriteAllText(filePath, json);
}
// Для загрузки списка фигур
public void LoadShapes(string filePath)
{
if (File.Exists(filePath))
{
string json = File.ReadAllText(filePath);
_shapes = JsonConvert.DeserializeObject<List<Shape>>(json, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
InvalidateDrawingPanel();
}
}
Необходимо будет установить пакет Newtonsoft.Json (Json.NET) через NuGet. TypeNameHandling.Auto позволяет корректно восстанавливать конкретные типы (Line, Rectangle, Circle) из базового класса Shape при десериализации.
Методологии разработки, тестирования и стандарты документирования
Создание программного обеспечения — это не только написание кода, но и структурированный процесс, включающий планирование, проектирование, тестирование и, что не менее важно, документирование. В контексте академической курсовой работы соответствие стандартам разработки и документации демонстрирует глубокое понимание дисциплины. Какая же неочевидная, но важная деталь часто упускается при таком подходе? Это постоянная обратная связь и итерации на каждом этапе, которые позволяют гибко реагировать на изменения требований и улучшать качество продукта.
Этапы разработки программного обеспечения
Жизненный цикл программного обеспечения (ПО) — это последовательность этапов, через которые проходит продукт от момента возникновения идеи до вывода из эксплуатации. Для курсовой работы можно выделить следующие основные этапы:
- Анализ требований: На этом этапе определяются функциональные и нефункциональные требования к графическому редактору. Что он должен делать? Какие фигуры рисовать? Какие операции поддерживать? Каковы ограничения по производительности или используемым технологиям? Это базис для всей дальнейшей работы.
- Проектирование: На основе требований разрабатывается архитектура приложения. Определяются классы, их взаимодействие, используемые паттерны проектирования, структура данных. Проектируется пользовательский интерфейс. Создаются диаграммы классов (UML) и диаграммы состояний.
- Реализация (Кодирование): Фактическое написание программного кода на языке C# в выбранной среде (WinForms). Этот этап включает создание классов, форм, реализацию алгоритмов рисования, обработки ввода и сохранения/загрузки.
- Тестирование: Проверка соответствия разработанного ПО заявленным требованиям. Выявление и устранение ошибок. Этот этап критически важен для обеспечения качества продукта.
- Документирование: Создание всей необходимой сопроводительной документации, включая техническое задание, пояснительную записку, описание программы и руководство пользователя/программиста. Этот этап зачастую недооценивается, но является обязательным для курсовой работы и любого профессионального проекта.
Подходы к тестированию графического редактора
Тестирование — это систематический процесс проверки программного обеспечения на наличие дефектов и соответствие требованиям. Для графического редактора можно применить следующие виды тестирования:
- Модульное тестирование (Unit Testing): Проверка отдельных, наименьших единиц кода (функций, методов, классов) в изоляции.
- Примеры сценариев:
- Проверка метода
ContainsPoint()для классаRectangle:- Точка внутри прямоугольника:
Rectangle.ContainsPoint(Point(X, Y))→true. - Точка вне прямоугольника:
Rectangle.ContainsPoint(Point(X, Y))→false. - Точка на границе:
Rectangle.ContainsPoint(Point(X, Y))→true/falseв зависимости от реализации.
- Точка внутри прямоугольника:
- Проверка метода
Move(): ПеремещениеLineна Δx, Δy должно корректно изменить координатыStartPointиEndPoint.
- Проверка метода
- Интеграционное тестирование (Integration Testing): Проверка взаимодействия между различными модулями или компонентами.
- Примеры сценариев:
- Корректное добавление новой фигуры в список (
_shapes.Add(newShape)) и её последующая отрисовка при вызовеInvalidateDrawingPanel(). - Взаимодействие контроллера с моделью: успешное выделение фигуры по клику мыши и обновление её свойства
IsSelected.
- Корректное добавление новой фигуры в список (
- Примеры сценариев:
- Пользовательское (системное) тестирование (User/System Testing): Проверка всей системы в целом с точки зрения конечного пользователя.
- Примеры сценариев:
- Пользователь выбирает инструмент «Линия», кликает и тащит мышь — на холсте появляется линия.
- Пользователь рисует несколько фигур, затем выделяет одну из них, перетаскивает, меняет цвет — фигура корректно изменяется.
- Пользователь сохраняет проект, закрывает редактор, открывает снова и загружает тот же проект — все фигуры восстанавливаются в исходном состоянии.
- Примеры сценариев:
Стандарты программной документации ГОСТ 19.ххх
В Российской Федерации действуют стандарты Единой системы программной документации (ЕСПД), которые регламентируют правила разработки, оформления и обращения программ и программной документации. Эти стандарты критически важны для курсовых работ в технических вузах. На текущую дату (28.10.2025) важно учитывать последние обновления.
Особое внимание следует уделить:
- ГОСТ 19.101-2024 «Единая система программной документации. Виды программ и программных документов»: Введен в действие с 30 января 2025 года. Этот стандарт определяет состав и назначение различных видов программных документов. Для курсовой работы наиболее актуальны:
- Техническое задание (ТЗ): Обязательный документ, который детально описывает цель разработки, требования к программе, её функциональность, условия эксплуатации и порядок приемки.
- Пояснительная записка: Содержит описание принятых технических и проектных решений, обоснование выбора технологий, алгоритмов, методов.
- Описание программы: Детальное описание внутренней логики, структуры, алгоритмов и используемых классов.
- Программа и методика испытаний: Документ, описывающий план тестирования, тестовые сценарии и ожидаемые результаты.
- Руководство программиста: Содержит информацию для доработки и модификации программы.
- Руководство пользователя: Инструкции по эксплуатации программы.
- ГОСТ 19.201-78 «Техническое задание»: Несмотря на то что существуют более новые стандарты в сфере IT, этот ГОСТ до сих пор является ориентиром для оформления ТЗ на программное обеспечение. Он определяет обязательные разделы:
- Введение
- Основания для разработки
- Назначение разработки
- Требования к программе или программному изделию (включая функциональные характеристики, требования к надежности, составу и параметрам технических средств, информационной и программной совместимости)
- Требования к программной документации
- Технико-экономические показатели
- Стадии и этапы разработки
- Порядок контроля и приемки
Тщательное следование этим ГОСТам при составлении документации для курсовой работы значительно повышает её академическую ценность и демонстрирует профессиональный подход.
Стандарт качества программного обеспечения ISO/IEC 25010:2023
Помимо отечественных стандартов, существует международная система оценки качества программных продуктов. ISO/IEC 25010:2023 «Systems and software Quality Requirements and Evaluation» (SQuaRE) — это актуальный международный стандарт, который описывает модель качества программного продукта. (Ранее действовала версия 2011 года, но с тех пор стандарт был обновлен).
Модель качества ISO/IEC 25010:2023 включает восемь основных характеристик, каждая из которых, в свою очередь, делится на подхарактеристики:
- Функциональная пригодность (Functional suitability): Насколько ПО обеспечивает функции, отвечающие потребностям пользователя.
- Подхарактеристики: функциональная полнота, функциональная корректность, функциональная уместность.
- Надежность (Reliability): Способность системы выполнять свои функции при определенных условиях в течение заданного периода времени.
- Подхарактеристики: зрелость, безотказность, восстанавливаемость, доступность.
- Удобство использования (Usability): Насколько легко и эффективно пользователи могут использовать систему.
- Подхарактеристики: воспринимаемая пригодность, обучаемость, управляемость, защита от ошибок пользователя, эстетика пользовательского интерфейса, доступность.
- Эффективность (Performance efficiency): Производительность системы по отношению к объему используемых ресурсов.
- Подхарактеристики: временное поведение, использование ресурсов, емкость.
- Сопровождаемость (Maintainability): Легкость, с которой можно модифицировать, исправлять, улучшать или адаптировать систему.
- Подхарактеристики: модульность, пригодность для анализа, пригодность для изменения, тестируемость.
- Переносимость (Portability): Способность системы эффективно функционировать в различных окружениях.
- Подхарактеристики: адаптируемость, устанавливаемость, сосуществование, заменяемость.
- Безопасность (Security): Способность системы защищать информацию и данные от несанкционированного доступа или использования.
- Подхарактеристики: конфиденциальность, целостность, неотказуемость, подотчетность, аутентифицируемость.
- Совместимость (Compatibility): Способность системы обмениваться информацией с другими системами или выполнять необходимые функции, находясь в одном окружении с другими системами.
- Подхарактеристики: сосуществование, взаимодействуемость.
Для графического редактора, разработанного в рамках курсовой работы, оценка качества будет включать:
- Функциональную пригодность: Корректное рисование фигур, их перемещение, изменение цвета.
- Надежность: Отсутствие сбоев при интенсивном использовании.
- Удобство использования: Интуитивно понятный интерфейс, легкость освоения базовых функций.
- Сопровождаемость: Чистый, модульный код, понятная архитектура, возможность легкого добавления новых фигур или инструментов.
Применение этих стандартов позволяет не только создать функциональный продукт, но и оценить его качество по общепринятым метрикам, что является важным аспектом инженерной практики.
Обеспечение расширяемости и модульности архитектуры
Создание «простейшего» графического редактора не означает, что его архитектура должна быть примитивной. Напротив, одной из ключевых задач курсовой работы является демонстрация способности построить систему, которая, будучи простой на начальном этапе, будет легко расширяемой и модульной для будущих доработок. Это фундаментальный аспект современного программного инжиниринга. Что же из этого следует? Такой подход гарантирует, что проект не превратится в «заброшенную» разработку после сдачи, а сможет быть легко адаптирован и улучшен.
Модульность, как концепция, позволяет декомпозировать программу на независимые, слабосвязанные части (модули или компоненты), каждая из которых выполняет определенную, четко определенную функцию. Преимущества такого подхода очевидны:
- Облегчение разработки: Разные части системы могут разрабатываться параллельно.
- Упрощение тестирования: Каждый модуль может быть протестирован в изоляции.
- Гибкость модификации: Изменение в одном модуле с меньшей вероятностью повлияет на другие.
- Повторное использование кода: Модули могут быть использованы в других проектах.
Принципы объектно-ориентированного программирования, которые мы детально рассмотрели, являются основными драйверами для создания расширяемой и модульной архитектуры:
- Наследование и полиморфизм позволяют создать гибкую иерархию графических объектов. Если мы захотим добавить новую фигуру, например, «Многоугольник» (
Polygon) или «Кривую Безье» (BezierCurve), нам достаточно будет унаследовать новый класс отShapeи реализовать специфические для него методыDraw(),ContainsPoint()иMove(). Основной код, который итерирует по спискуList<Shape>и вызываетshape.Draw(g), не потребует никаких изменений, благодаря полиморфизму. - Абстрактные классы и интерфейсы играют роль «контрактов», которые определяют, какое поведение должно быть у классов, реализующих эти контракты, но оставляют детали реализации на усмотрение этих классов. Например, абстрактный класс
Shapeгарантирует, что любая фигура будет иметь методDraw(), но не диктует, как именно она должна рисоваться. Это позволяет добавлять новые типы фигур или даже новые возможности (например,IDraggableдля перетаскивания) без изменения существующих классов, а лишь путем реализации соответствующих интерфейсов.
Кроме принципов ООП, ключевую роль в обеспечении расширяемости и модульности играют паттерны проектирования:
- Фабричный метод (Factory Method): Этот порождающий паттерн позволяет добавлять новые типы графических примитивов, не изменяя клиентский код, который их создает. Если завтра нам понадобится инструмент для рисования «Звезды», мы просто создадим класс
StarиStarFactory. Клиентский код, который выбирает фабрику и вызываетCreateShape(), останется неизменным. Это делает процесс добавления новых инструментов чрезвычайно простым. - Стратегия (Strategy): Этот поведенческий паттерн инкапсулирует алгоритмы в отдельные классы и делает их взаимозаменяемыми. В нашем графическом редакторе это идеально подходит для реализации различных режимов работы: рисование линии, рисование прямоугольника, выделение, заливка, ластик и т.д. Каждый режим может быть отдельной стратегией (
LineDrawingStrategy,RectangleDrawingStrategy,SelectionStrategy). Когда пользователь выбирает новый инструмент, мы просто меняем текущую стратегию, и вся логика обработки пользовательского ввода адаптируется. Это позволяет легко добавлять новые инструменты без изменения основного классаDrawingPanel.
Таким образом, продуманная архитектура, основанная на принципах ООП и паттернах проектирования, создает систему, которая не является жестко зафиксированной, а напротив, готова к эволюции. Это не только демонстрирует глубокое понимание предмета в рамках курсовой работы, но и закладывает основу для создания действительно гибкого и поддерживаемого программного продукта.
Заключение
Разработка простейшего графического редактора на языке C# для платформы Windows в рамках данной курсовой работы оказалась плодотворной задачей, позволившей не только применить на практике теоретические знания, но и углубить понимание фундаментальных принципов программной инженерии.
В ходе работы были успешно достигнуты поставленные цели и задачи:
- Детально исследованы и продемонстрированы принципы объектно-ориентированного программирования (инкапсуляция, наследование, полиморфизм, абстракция) в контексте создания иерархии графических примитивов.
- Проведен всесторонний сравнительный анализ технологических платформ WinForms и WPF, что позволило обоснованно выбрать WinForms на базе современного .NET и GDI+ для реализации простейшего редактора, учитывая его академическую направленность.
- Спроектирована модульная и расширяемая архитектура приложения с интегрированными паттернами проектирования — Фабричный метод и Стратегия — для управления созданием фигур и режимами работы, а также рассмотрены MVC и MVVM.
- Реализован базовый функционал графического редактора, включающий интерактивное рисование линий, прямоугольников и окружностей, их выделение, перемещение, изменение цвета, а также сохранение и загрузку состояния.
- Изучены и применены актуальные государственные (ГОСТ 19.ххх, включая ГОСТ 19.101-2024 и ГОСТ 19.201-78) и международные (ISO/IEC 25010:2023) стандарты, регламентирующие документацию и оценку качества программного обеспечения, что подчеркивает академическую строгость подхода.
Результаты курсовой работы показывают, что даже для «простейшего» приложения возможно и необходимо применять продвинутые концепции проектирования. Созданный редактор не просто выполняет заявленные функции, но и демонстрирует высокую степень расширяемости и модульности. Это означает, что добавление новых графических примитивов, инструментов или функциональных возможностей может быть осуществлено с минимальными изменениями существующего кода, что является отличительной чертой качественно спроектированных систем.
Таким образом, данная курсовая работа не только подтверждает достижение поставленных образовательных целей, но и служит наглядным примером применения современных методологий и стандартов в разработке объектно-ориентированных приложений для платформы Windows.
Список использованных источников
- ГОСТ 19.101-2024. Единая система программной документации. Виды программ и программных документов. Введ. 2025-01-30. Москва: Стандартинформ, 2024.
- ГОСТ 19.201-78. Единая система программной документации. Техническое задание. Введ. 1979-01-01. Москва: ИПК Издательство стандартов, 1978.
- ISO/IEC 25010:2023. Systems and software Quality Requirements and Evaluation (SQuaRE) — System and software quality models. International Organization for Standardization, 2023.
- Metanit.com. C# и WPF. Введение. [Электронный ресурс]. Режим доступа: https://metanit.com/sharp/wpf/1.1.php (дата обращения: 28.10.2025).
- Metanit.com. Паттерн MVVM — C# и WPF. [Электронный ресурс]. Режим доступа: https://metanit.com/sharp/wpf/13.1.php (дата обращения: 28.10.2025).
- Metanit.com. Стратегия (Strategy) | Паттерны в C# и .NET. [Электронный ресурс]. Режим доступа: https://metanit.com/sharp/patterns/2.4.php (дата обращения: 28.10.2025).
- Microsoft Learn. Общие сведения о графике — Windows Forms. [Электронный ресурс]. Режим доступа: https://learn.microsoft.com/ru-ru/dotnet/desktop/winforms/advanced/about-gdiplus-graphics (дата обращения: 28.10.2025).
- Microsoft Learn. Перо, линии и прямоугольники в GDI+ — Windows Forms. [Электронный ресурс]. Режим доступа: https://learn.microsoft.com/ru-ru/dotnet/desktop/winforms/advanced/pens-lines-and-rectangles-in-gdi (дата обращения: 28.10.2025).
- Refactoring.Guru. Фабричный метод на C#. [Электронный ресурс]. Режим доступа: https://refactoring.guru/ru/design-patterns/factory-method/csharp/example (дата обращения: 28.10.2025).
- Refactoring.Guru. Паттерны/шаблоны проектирования. [Электронный ресурс]. Режим доступа: https://refactoring.guru/ru/design-patterns (дата обращения: 28.10.2025).
- elibrary.ru. СРАВНИТЕЛЬНЫЙ АНАЛИЗ ГРАФИЧЕСКИХ СИСТЕМ WPF И WINFORMS. [Электронный ресурс]. Режим доступа: https://www.elibrary.ru/item.asp?id=38137351 (дата обращения: 28.10.2025).
- Habr. Паттерны для новичков: MVC vs MVP vs MVVM. [Электронный ресурс]. Режим доступа: https://habr.com/ru/articles/215705/ (дата обращения: 28.10.2025).
- Leadtools.com. Differences Between GDI and WPF. [Электронный ресурс]. Режим доступа: https://www.leadtools.com/sdk/imaging/comparison/gdi-vs-wpf (дата обращения: 28.10.2025).
- Medium.com. WPF vs. WinForms: Choosing the Right Technology for Your Project. [Электронный ресурс]. Режим доступа: https://medium.com/@sofvare/wpf-vs-winforms-choosing-the-right-technology-for-your-project-351834e56997 (дата обращения: 28.10.2025).
- NDepend Blog. WPF vs WinForms — Making the Right Decision in 2025. [Электронный ресурс]. Режим доступа: https://blog.ndepend.com/wpf-vs-winforms/ (дата обращения: 28.10.2025).
Приложения
Приложение А: Диаграмма классов базовых графических примитивов
classDiagram class Point { +int X +int Y } class Color { // ... (системный тип) } abstract class Shape { +Color ShapeColor +Point Location +bool IsSelected +Shape(color, location) +abstract void Draw(Graphics g) +virtual void Move(int dx, int dy) +abstract void Resize(int newWidth, int newHeight) +abstract bool ContainsPoint(Point p) } class Line { +Point EndPoint +Line(color, startPoint, endPoint) +override void Draw(Graphics g) +override void Move(int dx, int dy) +override void Resize(int newWidth, int newHeight) +override bool ContainsPoint(Point p) -RectangleF GetBoundingBox() } class Rectangle { +int Width +int Height +Rectangle(color, location, width, height) +override void Draw(Graphics g) +override void Resize(int newWidth, int newHeight) +override bool ContainsPoint(Point p) } class Circle { +int Radius +Circle(color, center, radius) +override void Draw(Graphics g) +override void Move(int dx, int dy) +override void Resize(int newRadius, newHeight) +override bool ContainsPoint(Point p) } Shape <|-- Line Shape <|-- Rectangle Shape <|-- Circle Line "1" *-- "1" Point : StartPoint Line "1" *-- "1" Point : EndPoint Shape "1" *-- "1" Point : Location Shape "1" *-- "1" Color : ShapeColorПриложение Б: Фрагмент кода для выбора инструмента с использованием Фабричного метода
// В классе формы или контроллера public enum DrawingTool { Line, Rectangle, Circle, Select } private DrawingTool _currentTool = DrawingTool.Line; // Текущий инструмент private ShapeFactory _currentShapeFactory; private void SetDrawingTool(DrawingTool tool) { _currentTool = tool; switch (_currentTool) { case DrawingTool.Line: _currentShapeFactory = new LineFactory(); break; case DrawingTool.Rectangle: _currentShapeFactory = new RectangleFactory(); break; case DrawingTool.Circle: _currentShapeFactory = new CircleFactory(); // Предполагается наличие CircleFactory break; case DrawingTool.Select: _currentShapeFactory = null; // Для выбора нет фабрики break; } } // При нажатии кнопки "Линия" private void btnLineTool_Click(object sender, EventArgs e) { SetDrawingTool(DrawingTool.Line); } // При нажатии кнопки "Прямоугольник" private void btnRectangleTool_Click(object sender, EventArgs e) { SetDrawingTool(DrawingTool.Rectangle); } // В MouseDown для создания фигуры private void drawingPanel_MouseDown(object sender, MouseEventArgs e) { _lastMousePosition = e.Location; if (e.Button == MouseButtons.Left) { if (_currentTool == DrawingTool.Select) { // Логика выделения фигуры _selectedShape = null; foreach (Shape shape in _shapes.AsEnumerable().Reverse()) { if (shape.ContainsPoint(e.Location)) { _selectedShape = shape; break; } } foreach (Shape shape in _shapes) shape.IsSelected = false; if (_selectedShape != null) { _selectedShape.IsSelected = true; } } else if (_currentShapeFactory != null) // Если выбран инструмент для рисования { _isDrawing = true; _currentDrawingShape = _currentShapeFactory.CreateShape(Color.Black, e.Location, e.Location); _shapes.Add(_currentDrawingShape); } } InvalidateDrawingPanel(); } // В MouseMove для изменения рисуемой фигуры или перемещения выделенной private void drawingPanel_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (_isDrawing && _currentDrawingShape != null) { // Логика обновления размеров _currentDrawingShape // ... (как в основном тексте) ... } else if (_currentTool == DrawingTool.Select && _selectedShape != null) { // Логика перемещения _selectedShape // ... (как в основном тексте) ... } InvalidateDrawingPanel(); } }Приложение В: Скриншот простейшего графического редактора (гипотетический)
Примерный вид пользовательского интерфейса простейшего графического редактора. На скриншоте изображен холст с несколькими нарисованными линиями, прямоугольниками и окружностями. Слева панель инструментов с кнопками для выбора типа фигуры (Линия, Прямоугольник, Круг) и инструмента выделения/перемещения. Сверху или справа панель для выбора цвета.
Приложение Г: Пример тестового сценария для функции рисования
Объект тестирования: Функция рисования линии.
Цель: Проверить корректность отрисовки линии в различных условиях.№ Название сценария Шаги выполнения Ожидаемый результат 1 Рисование горизонтальной линии 1. Запустить приложение.
2. Выбрать инструмент «Линия».
3. Нажать левую кнопку мыши в точке (10, 10).
4. Переместить курсор мыши в точку (100, 10) (по горизонтали).
5. Отпустить левую кнопку мыши.На холсте отобразится горизонтальная линия черного цвета, соединяющая точки (10, 10) и (100, 10). При перерисовке линия не исчезает и сохраняет свои координаты. 2 Рисование вертикальной линии 1. Запустить приложение.
2. Выбрать инструмент «Линия».
3. Нажать левую кнопку мыши в точке (20, 20).
4. Переместить курсор мыши в точку (20, 120) (по вертикали).
5. Отпустить левую кнопку мыши.На холсте отобразится вертикальная линия черного цвета, соединяющая точки (20, 20) и (20, 120). 3 Рисование линии с изменением цвета 1. Запустить приложение.
2. Выбрать инструмент «Линия».
3. Выбрать красный цвет.
4. Нарисовать линию из (50, 50) в (150, 150).
5. Выбрать синий цвет.
6. Нарисовать линию из (60, 60) в (160, 160).Первая линия отображается красным цветом. Вторая линия отображается синим цветом. Обе линии сохраняют свои цвета при перерисовке. 4 Перемещение нарисованной линии 1. Нарисовать линию.
2. Выбрать инструмент «Выделение».
3. Кликнуть на нарисованную линию.
4. Перетащить выделенную линию в новое место (например, на 50 пикселей вправо и 50 пикселей вниз).
5. Отпустить левую кнопку мыши.Линия должна быть выделена (например, утолщенным контуром). После перетаскивания линия перемещается, сохраняя свою форму и цвет, и корректно отрисовывается в новом месте. 5 Отмена рисования (без отпускания кнопки мыши) 1. Выбрать инструмент «Линия».
2. Нажать левую кнопку мыши.
3. Переместить курсор мыши, но не отпускать кнопку.
4. Нажать клавишу «Esc» или другую отменяющую операцию (если предусмотрено).Линия, которая рисовалась «в процессе», должна исчезнуть с холста. Список использованной литературы
- Стандарт ISO/IEC 15948 [Электронный ресурс]. URL: http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=29581 (дата обращения: 28.10.2025).
- Домашняя страница Joint Photographic Experts Group [Электронный ресурс]. URL: http://www.jpeg.org/jpeg/index.html (дата обращения: 28.10.2025).
- Пайсон М. ООП с примерами, Часть 2 [Электронный ресурс]. URL: http://habrahabr.ru/post/87205/ (дата обращения: 28.10.2025).
- Медведев В.И. Особенности объектно-ориентированного программирования на С++/CLI, С# и Java. 2-е изд. Казань: РИЦ «Школа», 2010. 444 с.
- Основные конструктивные особенности .NET Framework [Электронный ресурс]. URL: http://www.zabalnet.com/overview-highlight-principal-design-features.html (дата обращения: 28.10.2025).
- Объектно-ориентированное программирование (C# и Visual Basic) [Электронный ресурс]. URL: http://msdn.microsoft.com/ru-ru/library/dd460654.aspx (дата обращения: 28.10.2025).
- System.Drawing — пространство имен [Электронный ресурс]. URL: http://msdn.microsoft.com/ru-ru/library/system.drawing.aspx (дата обращения: 28.10.2025).
- Павловская Т.А. C#. Программирование на языке высокого уровня. Учебник для вузов. Санкт-Петербург: Питер, 2009. 432 с.
- Буч Г. и др. Объектно-ориентированный анализ и проектирование с примерами приложений. 3-е изд. Москва, 2008. 720 с.
- Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.0 на языке C#. 3-е изд. Санкт-Петербург: Питер, 2012. 928 с.
- Стандарты с требованиями к документации программного обеспечения [Электронный ресурс]. URL: http://www.docsolution.ru/gost-po-programmnomu-obespecheniyu/ (дата обращения: 28.10.2025).
- ГОСТ 19.xxx Единая система программной документации [Электронный ресурс]. URL: https://cosced.ru/gost-19-xxx-edinaya-sistema-programmnoj-dokumentacii/ (дата обращения: 28.10.2025).
- СРАВНИТЕЛЬНЫЙ АНАЛИЗ ГРАФИЧЕСКИХ СИСТЕМ WPF И WINFORMS [Электронный ресурс]. URL: https://www.elibrary.ru/item.asp?id=38137351 (дата обращения: 28.10.2025).
- Сравнение технологий WinForms и WPF // Быстрые отчеты — генераторы отчётов [Электронный ресурс]. URL: https://fastreport.ru/ru/blog/winforms-vs-wpf/ (дата обращения: 28.10.2025).
- Разработка по ГОСТ 19: Стандарты документации в ИТ // LeanTech [Электронный ресурс]. URL: https://leantech.ru/razrabotka-po-gost-19/ (дата обращения: 28.10.2025).
- WPF vs. WinForms // The complete WPF tutorial [Электронный ресурс]. URL: https://wpf-tutorial.com/ru/107/%D1%80%D0%B0%D0%B7%D0%BD%D0%BE%D0%B5/wpf-vs-winforms/ (дата обращения: 28.10.2025).
- Differences Between GDI and WPF // Raster, Medical, Document Help — LEADTOOLS [Электронный ресурс]. URL: https://www.leadtools.com/sdk/imaging/comparison/gdi-vs-wpf (дата обращения: 28.10.2025).
- Паттерны/шаблоны проектирования // Refactoring.Guru [Электронный ресурс]. URL: https://refactoring.guru/ru/design-patterns (дата обращения: 28.10.2025).
- Шаблоны проектирования архитектуры, поддерживающие безопасность // Microsoft Azure Well-Architected Framework | Microsoft Learn [Электронный ресурс]. URL: https://learn.microsoft.com/ru-ru/azure/well-architected/security/architectural-design-patterns (дата обращения: 28.10.2025).
- C# и WPF | Введение // Metanit [Электронный ресурс]. URL: https://metanit.com/sharp/wpf/1.1.php (дата обращения: 28.10.2025).
- C#. Что стоит изучать: WinForms, WPF, или UWP? // Stack Overflow на русском [Электронный ресурс]. URL: https://ru.stackoverflow.com/questions/962591/c-%D1%87%D1%82%D0%BE-%D1%81%D1%82%D0%BE%D0%B8%D1%82-%D0%B8%D0%B7%D1%83%D1%87%D0%B0%D1%82%D1%8C-winforms-wpf-%D0%B8%D0%BB%D0%B8-uwp (дата обращения: 28.10.2025).
- Общие сведения о графике // Windows Forms | Microsoft Learn [Электронный ресурс]. URL: https://learn.microsoft.com/ru-ru/dotnet/desktop/winforms/advanced/about-gdiplus-graphics (дата обращения: 28.10.2025).
- Электронное учебное пособие «Объектно-ориентированное программирование графических объектов на языке C // Электронная библиотека УрГПУ [Электронный ресурс]. URL: http://elar.rsvpu.ru/handle/123456789/27440 (дата обращения: 28.10.2025).
- Перо, линии и прямоугольники в GDI+ // Windows Forms | Microsoft Learn [Электронный ресурс]. URL: https://learn.microsoft.com/ru-ru/dotnet/desktop/winforms/advanced/pens-lines-and-rectangles-in-gdi (дата обращения: 28.10.2025).
- System.Drawing (GDI+) vs System.Windows.Media (WPF) vs Direct2D+DirectWrite+WIC // Stack Overflow [Электронный ресурс]. URL: https://stackoverflow.com/questions/24584210/system-drawing-gdi-vs-system-windows-media-wpf-vs-direct2d-directwrite-wic (дата обращения: 28.10.2025).
- Паттерн MVVM — C# и WPF // Metanit [Электронный ресурс]. URL: https://metanit.com/sharp/wpf/13.1.php (дата обращения: 28.10.2025).
- Стратегия (Strategy) | Паттерны в C# и .NET // Metanit [Электронный ресурс]. URL: https://metanit.com/sharp/patterns/2.4.php (дата обращения: 28.10.2025).
- Практикум прикладного программирования на C# в среде VS.NET 2005. Лекция 16: Рисование графических примитивов средствами GDI+ // НОУ ИНТУИТ [Электронный ресурс]. URL: https://www.intuit.ru/studies/courses/456/312/lecture/7707 (дата обращения: 28.10.2025).
- Паттерны для новичков: MVC vs MVP vs MVVM // Habr [Электронный ресурс]. URL: https://habr.com/ru/articles/215705/ (дата обращения: 28.10.2025).
- GDI+ like drawing in WPF // Stack Overflow [Электронный ресурс]. URL: https://stackoverflow.com/questions/441220/gdi-like-drawing-in-wpf (дата обращения: 28.10.2025).
- Визуальное проектирование приложений C# [Электронный ресурс]. URL: https://window-prog.ru/book/glava-6-osnovy-raboty-s-grafikoj/risovanie-geometricheskih-figur-i-teksta/ (дата обращения: 28.10.2025).
- GDI+ Tutorial for Beginners // C# Corner [Электронный ресурс]. URL: https://www.c-sharpcorner.com/UploadFile/mahesh/gdi-plus-tutorial-for-beginners/ (дата обращения: 28.10.2025).
- C# и Windows Forms | Паттерн Model-View-ViewModel // METANIT.COM [Электронный ресурс]. URL: https://metanit.com/sharp/winforms/17.1.php (дата обращения: 28.10.2025).
- Фабричный метод на C# // Refactoring.Guru [Электронный ресурс]. URL: https://refactoring.guru/ru/design-patterns/factory-method/csharp/example (дата обращения: 28.10.2025).
- Примеры сценариев: