Rectangle c windows forms

Пройдите тест, узнайте какой профессии подходите

Работать самостоятельно и не зависеть от других

Работать в команде и рассчитывать на помощь коллег

Организовывать и контролировать процесс работы

Введение в рисование на форме в Windows Forms

Рисование на форме в Windows Forms предоставляет разработчикам мощный инструмент для создания графических элементов, таких как линии, прямоугольники, эллипсы и изображения, прямо на поверхности формы. Это может быть полезно для создания пользовательских интерфейсов, визуализации данных или просто для добавления декоративных элементов в ваше приложение. В этой статье мы рассмотрим основные принципы рисования на форме в Windows Forms с использованием языка программирования C#. Мы подробно разберем, как использовать класс Graphics для рисования различных примитивов и изображений, а также рассмотрим некоторые полезные советы и трюки, которые помогут вам в работе.

Кинга Идем в IT: пошаговый план для смены профессии

Создание проекта Windows Forms в Visual Studio

Для начала работы нам потребуется создать проект Windows Forms в Visual Studio. Следуйте этим шагам:

  1. Откройте Visual Studio и выберите Создать новый проект.
  2. В списке шаблонов выберите Приложение Windows Forms (.NET Framework).
  3. Укажите имя проекта и выберите расположение для его сохранения.
  4. Нажмите Создать.

После создания проекта у вас будет форма, на которой мы будем рисовать. Важно отметить, что Visual Studio предоставляет множество инструментов для упрощения разработки приложений Windows Forms, таких как дизайнер форм, который позволяет визуально добавлять и настраивать элементы управления.

Основы работы с классом Graphics

Для рисования на форме в Windows Forms используется класс Graphics. Этот класс предоставляет методы для рисования различных графических примитивов и изображений. Чтобы начать рисование, нам нужно получить объект Graphics, связанный с формой. Это можно сделать в обработчике события Paint формы. Событие Paint вызывается каждый раз, когда форма перерисовывается, что делает его идеальным местом для выполнения всех операций рисования.

Пример кода для получения объекта Graphics и рисования на форме:

Объект Graphics предоставляет множество методов для рисования различных графических примитивов, таких как линии, прямоугольники, эллипсы и изображения. Важно понимать, что все операции рисования должны выполняться в контексте события Paint, чтобы гарантировать правильное отображение графики на форме.

Примеры рисования примитивов

Линии

Для рисования линий используется метод DrawLine. Этот метод принимает объект Pen, который определяет цвет и толщину линии, а также координаты начальной и конечной точек линии. Пример кода:

Прямоугольники

Для рисования прямоугольников используется метод DrawRectangle. Этот метод также принимает объект Pen, а также координаты верхнего левого угла и размеры прямоугольника. Пример кода:

Эллипсы

Для рисования эллипсов используется метод DrawEllipse. Этот метод принимает объект Pen, а также координаты верхнего левого угла и размеры прямоугольника, в который вписан эллипс. Пример кода:

Использование метода DrawImage для работы с изображениями

Метод DrawImage позволяет рисовать изображения на форме. Для этого сначала нужно загрузить изображение в объект Image, а затем использовать метод DrawImage для его отображения. Метод DrawImage предоставляет множество перегрузок, которые позволяют рисовать изображения с различными параметрами, такими как масштабирование и обрезка.

Пример кода для загрузки и отображения изображения:

Также можно масштабировать изображение при рисовании. Это может быть полезно, если вам нужно изменить размер изображения для его отображения на форме:

Дополнительные советы и трюки

Использование буферизации для улучшения производительности

При рисовании сложных графических элементов на форме может возникнуть проблема мерцания. Это происходит из-за того, что форма перерисовывается слишком часто. Чтобы избежать этого, можно использовать двойную буферизацию. Двойная буферизация позволяет сначала рисовать все элементы на скрытой поверхности, а затем отображать их на форме одним кадром, что значительно уменьшает мерцание.

Для включения двойной буферизации можно установить свойство DoubleBuffered формы в true:

Обработка событий мыши для интерактивного рисования

Вы можете сделать ваше приложение более интерактивным, обрабатывая события мыши для рисования на форме. Например, вы можете рисовать линии или другие примитивы в ответ на движение мыши или нажатие кнопок мыши. Для этого нужно подписаться на соответствующие события формы, такие как MouseDown, MouseMove и MouseUp.

Пример кода для рисования линии при перемещении мыши:

Теперь вы знаете основные методы рисования на форме в Windows Forms. Используя эти знания, вы можете создавать разнообразные графические элементы в своих приложениях. Удачи в ваших начинаниях! 😉

Читайте также

Изображение к статье создано при помощи нейросети Kandinsky

Доброго времени суток, друзья.

В сегодняшней статье мы разберём с вами некоторые возможности GDI+ и научимся рисовать различные простые графические фигуры и примитивы на форме в приложении Windows Forms.

Описание того, что такое GDI+, можно найти по следующей ссылке на официальном сайте: https://learn.microsoft.com/ru-ru/dotnet/desktop/winforms/advanced/about-gdi-managed-code?view=netframeworkdesktop-4.8

Отмечу лишь кратко, что аббревиатура GDI обозначает Graphics Device Interface (т.е. интерфейс графического устройства), и по сути это часть операционной системы Windows, которая предоставляет возможность для создания векторных изображений и рисования. Также стоит упомянуть, что GDI+ является частью .NET Framework.

Итак, в рамках этой статьи мы рассмотрим возможности рисования при помощи средств GDI+ следующих фигур:

  • Прямоугольник (Rectangle) — нарисуем контур прямоугольника и закрашенный прямоугольник на форме
  • Эллипс (Ellipse) — нарисуем контур эллипса и закрашенный эллипс на форме
  • Полигон (Polygon) — нарисуем контур полигона и закрашенный полигон на форме
  • Дуга (Arc) — нарисуем на форме небольшой отрезок дуги. Дугой называется часть окружности или эллипса, заключённая между двумя заданными точками, принадлежащими этой окружности/эллипсу.
  • Сектор (Pie) — нарисуем на форме сектор и закрашенный сектор. Сектор похож на дугу, но отличается от неё тем, что две крайние точки дуги соединены радиальными линиями с центром окружности/эллипса.
  • Линии (Line) — нарисуем на форме 3 различных линии, каждая из которых будет иметь свой стиль штриха.
  • Фундаментальный сплайн (Curve) — мы нарисуем на форме несколько фундаментальных сплайнов. Три из них будут открытыми, и два из них будут закрытыми. О том, какие есть различия между открытыми и закрытыми фундаментальными сплайнами, мы посмотрим далее по тексту статьи.
  • Графический путь (GraphicsPath) — нарисуем на форме графический путь, состоящий из нескольких линий и дуги
  • Текст — выведем на форме текст, содержащийся в тестовой строковой переменной

Давайте сразу посмотрим на тот результат, который мы получим в конце статьи. Итак, у нас будет простое приложение для Windows Forms, с единственной главной формой, отображающейся при старте приложения. И на форме будут нарисованы перечисленные выше фигуры следующим образом:

 

В конце статьи вы сможете найти ссылку на архив с готовым примером проекта для среды Microsoft Visual Studio, который будет разобран в статье. А сейчас мы приступим к созданию приложения и по пути разберём нюансы при рисовании каждой из упомянутых фигур.

Создание нового проекта в среде Microsoft Visual Studio

Откройте среду разработки Microsoft Visual Studio и создайте новый проект с типом Приложение Windows Forms (.NET Framework), как показано ниже: 

 

В качестве имени нового проекта задайте GDIPaintingExample и выберите местоположение, куда будут сохранены файлы нового проекта (здесь я обычно оставляю все настройки по умолчанию и рекомендую сделать то же самое, просто запомните каталог, указанный в поле «Расположение», чтобы затем открывать его в Проводнике).

Переименование главной формы приложения

После создания проекта будет создана главная форма по умолчанию с именем Form1 и соответствующий ей файл, содержащий код для класса формы, с именем Form1.cs.

Выберем в окне «Обозреватель решений» эту форму и в окне «Свойства» изменим название класса для формы на FrmGDIPaintingExample.cs.

В диалоговом окне, запрашивающем подтверждение переименования класса формы и связанных с ней файлов, соглашаемся. В результате этих действий в окне «Обозреватель решений» форма и зависящие от неё файлы будут переименованы.

Теперь установим главной форме некоторые значения свойств.

Установка свойств для главной формы приложения

В окне «Свойства» для главной формы установим следующие значения свойств:

  • Text — [Allineed.Ru] Пример рисования различных фигур при помощи GDI+
  • Size — 816; 489
  • StartPosition — CenterScreen

Все остальные свойства главной формы нашего приложения оставим с их значениями по умолчанию.

Теперь перейдем непосредственно к основной части — рисованию фигур на форме.

Обработка события Paint для главной формы

Основная работа по отрисовке всех фигур в нашем примере будет происходить при помощи обработки события Paint для главной формы нашего приложения. Это по сути главное и ключевое событие, которое вызывается при перерисовке элемента управления (формы). Для его обработки нам необходимо в окне «Свойства» найти иконку молнии и перейти к доступным событиям формы, после чего найти в списке событий событие Paint и дважды кликнуть напротив него левой кнопкой мыши.

В результате в коде главной формы будет создан пустой обработчик для этого события:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {

        }

Всю работу по рисованию фигур на главной форме мы будем производить из этого обработчика. Но поскольку мы напишем не один десяток строк кода, чтобы этот метод не «разросся», мы будем выделять логику по отрисовке каждой фигуры в отдельные методы, которые напишем с вами самостоятельно.

Первое, с чего мы начнём, — это добавим в код метода-обработчика для события Paint следующие две строки кода:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

        }

В первой добавленной строке кода мы записываем в переменную класса Graphics, которую назвали g, ссылку на экземпляр класса Graphics, который по умолчанию передаётся во втором параметре события Paint — у нас это параметр с именем e класса PaintEventArgs.

Этот экземпляр класса Graphics (как и сам класс Graphics) является, я бы сказал, основополагающим во всём процессе рисования различных фигур при помощи GDI+, поэтому мы непременно должны получить его для дальнейшей работы по рисованию чего бы то ни было на нашей главной форме. Класс Graphics, как мы увидим далее, предоставляет множество полезных методов для рисования самых разных фигур, и некоторые из этих методов мы как раз разберём в данной статье.

Вторая строка кода задаёт специальный режим сглаживания (smoothing mode) для экземпляра класса Graphics, который мы только что с вами получили. Этот режим сглаживания, как нетрудно догадаться, влияет на то, каким образом будут сглаживаться углы и сгибы фигур при их отрисовке. Если его не выставить, то по умолчанию некоторые линии, углы или сгибы фигур могут казаться немного «рубленными». Режим сглаживания управляется через свойство SmoothingMode класса Graphics, и в нашем случае мы его выставляем в значение HighQuality, что в дословном переводе означает «высокое качество». Вы можете заметить, что есть и другие значения в перечислении SmoothingMode, например AntiAlias, но, согласно официальной документации на это перечисление (см. ссылку https://learn.microsoft.com/ru-ru/dotnet/api/system.drawing.drawing2d.smoothingmode?view=dotnet-plat-ext-8.0) значения HighQuality и AntiAlias эквивалентны и по сути устанавливают сглаживание. Остальные значения для данного перечисления отключают сглаживание при отрисовке.

Более подробно про режим сглаживания и специфику его работы можно также прочитать на этой странице: https://learn.microsoft.com/ru-ru/dotnet/api/system.drawing.graphics.smoothingmode?view=dotnet-plat-ext-8.0

Далее мы перейдем к написанию кода для рисования фигур, но прежде я бы хотел сказать пару слов о специфике той системы координат, которая используется в GDI+.

Система координат

Из курса средней школы мы знаем привычную систему координат, которая выглядит так:

 

Т.е. в этой системе координат ось X идёт от начальной точки O(0; 0) вправо, а ось Y идёт от начальной точки вверх. Некоторая точка P с произвольными координатами (x0; y0) при этом лежит правее-выше начала системы координат.

В цифровом же мире компьютеров и программ (и, в частности, в GDI+) обычно принята несколько иная система координат, в которой ось Y идёт от начальной точки с координатами (0; 0) — вниз, и некоторая точка P(x0; y0) будет находиться правее-ниже начала системы координат:

Именно в контексте работы с GDI+ и в нашем примере получается, что начало системы координат находится в левом-верхнем углу формы приложения. И если не задано какое-то иное смещение системы координат (что, в целом, также можно осуществить, если есть в этом необходимость), то точка на «плоскости» главной формы с координатами (0; 0) находится в левом-верхнем углу формы. Точка (10; 0) находится на отдалении 10 пикселей по оси X (т.е. вправо) от начала координат и при этом на одном и том же уровне с начальной точкой, т.к. её координата Y равна нулю.

GDI+ поддерживает понятие разных типов систем координат и, как я сказал ранее, возможности перемещения системы координат в другую точку. Если интересны нюансы типов систем координат и возможности их смещения, то более подробно предлагаю ознакомиться читателю с данной темой, прочитав документацию по ссылке: https://learn.microsoft.com/ru-ru/dotnet/desktop/winforms/advanced/types-of-coordinate-systems?view=netframeworkdesktop-4.8

В контексте же этой статьи мы не будем делать смещения стандартной системы координат и примем за точку отсчёта левый верхний угол формы (по умолчанию), а также тот факт, что ось Y пролегает от точки отсчёта вниз (в левый нижний угол формы).

Теперь, когда мы поняли специфику системы координат в GDI+ и направления оси Y в ней, мы готовы к тому, чтобы начать отрисовку фигур на главной форме, для чего напишем соответствующий код на C#.

Рисуем на форме контур эллипса и закрашенный эллипс

Откроем код нашей главной формы и создадим в ней следующий метод:

        /// <summary>
        /// Отрисовка эллипсов (Ellipse). Один эллипс рисуется в виде контура через вызов метода DrawEllipse
        /// класса Graphics, второй эллипс - заполненный, рисуется через вызов метода FillEllipse
        /// класса Graphics.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawEllipse(Graphics g) {
            g.DrawEllipse(Pens.Red, new Rectangle(new Point(10, 10), new Size(100, 50)));
            g.FillEllipse(Brushes.Red, new Rectangle(new Point(10, 70), new Size(100, 50)));
        }

Как видим, он состоит всего из двух строк кода, в первой из которых мы вызываем метод DrawEllipse, а во второй — FillEllipse. Оба метода доступны в классе Graphics, который мы обсудили ранее, а входным параметром g у этого метода как раз выступает экземпляр класса Graphics. Разберём оба этих метода, у них есть некоторые отличия:

  • DrawEllipse — нарисует контур эллипса, без его «заливки» в цвет.
  • FillEllipse — нарисует эллипс с заливкой

Ввиду этой специфики, первый из методов принимает в первом своём параметре экземпляр класса Pen («ручка»), а второй — экземпляр класса Brush («кисть»). В GDI+, можно считать за правило, экземпляры класса Pen обычно используются для рисования линий и контуров, где не присутствует заливка, а экземпляры класса Brush, наоборот, в тех случаях, когда нужна и важна заливка некоторой области или фигуры. В качестве второго параметра для каждого из методов мы передаём новый экземпляр класса Rectangle («прямоугольник»). Этот прямоугольник является описанным прямоугольником вокруг рисуемого эллипса. Т.е. фактически, для рисования эллипса мы задаём координаты и размеры описанного вокруг него прямоугольника. При создании экземпляра класса Rectangle первым аргументом передаётся экземпляр той точки (экземпляр класса Point), которая будет являться верхним-левым углом описанного вокруг эллипса прямоугольника. В нашем случае это точки с координатами (10; 10) и (10; 70). А вторым параметром мы передаём экземпляр класса Size, который задаёт двумя параметрами ширину и высоту этого прямоугольника. По координатам точек можно видеть, что закрашенный эллипс мы рисуем чуть ниже первого эллипса в виде обычного контура: его координата Y равна 70, а у первого — 10. Координата X у обоих эллипсов одинаковая и равна 10, и это значит, что они имеют одинаковый отступ слева от левого края главной формы. Как видите, всё довольно просто. Ну и заметьте также, что в методы DrawEllipse и FillEllipse мы передаём экземпляры класса Size с одними и теми же значениями ширины (100) и высоты (50) для обоих эллипсов, т.е. эллипсы будут у нас одинаковые по размерам.

Стоит также отметить, что экземпляры «ручек» и «кистей» для рисования контуров или закрашенных фигур можно как создавать вручную, так и пользоваться доступными через стандартные классы Pens и Brushes. В них есть множество экземпляров с различными цветами для рисования. В данном случае мы не создавали экземпляр ручки и кисти вручную (т.е. через оператор new), но далее в примерах мы это сделаем, поскольку ручное создание экземпляров ручек/кистей даёт некоторую большую гибкость, например по части стиля штриха рисуемых линий.

Сам по себе метод, созданный нами, не сильно полезен, пока никто его не вызывает, поэтому давайте теперь добавим его вызов в код метода-обработчика события Paint, который мы подготовили с вами ранее:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
        }

Обратите внимание, что мы передаём в наш новый метод уже имеющийся экземпляр класса Graphics — переменную с именем g. Это значит, что наш новый метод DrawEllipse(Graphics g) получит готовый экземпляр класса Graphics и будет использовать его для рисования эллипсов.

На этом этапе мы готовы запустить наше приложение и уже увидеть первый результат! Можем это сделать, нажав клавишу F5 или кнопку «Пуск» в среде разработки.

Результат после запуска нашей программы должен получиться такой:

 

Поздравляю! Вот мы и нарисовали наши самые первые фигуры на форме при помощи средств GDI+! Это уже неплохой результат, но впереди мы познакомимся ещё и с другими интересными возможностями.

Рисуем на форме контур прямоугольника и закрашенный прямоугольник

Аналогично тому, как мы поступили с эллипсами, давайте посмотрим, как нарисовать прямоугольники на главной форме нашего приложения.

Для этого в код главной формы добавим следующий новый метод DrawRectangles:

        private void DrawRectangles(Graphics g) {
            Pen greenDottedPen = new Pen(Brushes.Green, 2f);
            greenDottedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;

            g.DrawRectangle(greenDottedPen, new Rectangle(new Point(120, 10), new Size(100, 50)));

            greenDottedPen.Dispose();

            g.FillRectangle(Brushes.Green, new Rectangle(new Point(120, 70), new Size(100, 50)));
        }

В этом методе точно так же мы определили входным параметром с именем g экземпляр класса Graphics, который будет использоваться для рисования прямоугольников.

Далее мы создаём новый экземпляр класса Pen, передавая ему в первом аргументе конструктора зелёную кисть (Brushes.Green), а во втором — толщину рисуемой линии контура прямоугольника, равную 2f. 2f — это число типа float, поскольку второй параметр конструктора для класса Pen ожидает именно тип данных float. 2f эквивалентно записи 2.0f, т.е. по сути это толщина линии равная 2. При желании вы можете поэкспериментировать и передать что-то вида 2.5f и так далее.

Дальше мы задаём свойство DashStyle для нашего экземпляра «ручки», равным System.Drawing.Drawing2D.DashStyle.Dot. Это означает, что ручка будет рисовать пунктирными линиями (т.е. основанными на близко расположенных друг к другу точках), а весь контур нашего прямоугольника также будет пунктирным.

Далее идёт вызов метода DrawRectangle, который доступен в классе Graphics. Он, по аналогии с тем, как мы рисовали эллипсы, рисует контур прямоугольника, без заливки. Первым параметром передаём нашу «ручку», а вторым — экземпляр класса Rectangle, который и задаёт местоположение прямоугольника и его размеры.

Дальше идёт очень важная строка кода, которая позволяет высвободить ресурсы, занимаемые вручную созданным объектом Pen: greenDottedPen.Dispose()

Обращаю внимание, что в случаях, когда кисти/ручки создаются вручную — через оператор new — их нужно обязательно освобождать, когда они выполнили свою функцию для отрисовки и становятся «не нужны». Этот момент позволит экономить ресурсы компьютера, на котором выполняется приложение и своевременно освобождать память, занимаемую объектами Pen и Brush.

В конце метода идёт отрисовка заполненного прямоугольника при помощи вызова метода FillRectangle. Заметьте, что как и в случае с эллипсами «Fill-методы» принимают первым параметром экземпляр «кисти» (Brush), а «Draw-методы» принимают экземпляр «ручки» (Pen). Такова их специфика, и она прослеживается и при других Draw/Fill методах.

Снова добавим вызов нашего нового метода DrawRectangles к обработчику события Paint — сразу после вызова DrawEllipse(g):

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
        }

Снова запустим наше приложение и увидим следующий результат:

 

Как видите, теперь на форме отобразились два прямоугольника, как мы и хотели. Также обратим внимание на то, что в отличие от контура эллипса контур прямоугольника — пунктирный и толщина линии равна 2. Это результат того, что мы вручную сконфигурировали экземпляр класса Pen на свой вкус.

Рисуем на форме контур полигона и закрашенный полигон

Прежде, чем мы начнём отрисовку полигонов на нашей форме, давайте поймем, что в принципе представляет собой полигон, и какова его специфика. Полигон (или, по сути, знакомый нам многоугольник) в GDI+ — это набор точек с определёнными координатами, где последовательные пары точек соединяются линиями, образуя контур полигона:

 

Например, в этом полигоне у нас 7 точек P1, P2, P3, …, P7, где координаты первой точки — (x1; y1), координаты второй — (x2; y2) и так далее. Последовательные пары точек P1-P2, P2-P3, P3-P4, P4-P5, P6-P7 соединяются линиями, образуя контур полигона. Закрашенный полигон — это когда внутренняя область полигона, определённого точками будет закрашена определённой «кистью» (Brush). Чтобы задать полигон нам нужно передать методам GDI+, доступным в классе Graphics, массив точек нашего полигона. И в случае, если мы рисуем лишь контур, передать дополнительно экземпляр «ручки» (Pen), которой необходимо отрисовать контур нашего полигона, а в случае закрашенного полигона — экземпляр «кисти» (Brush).

Создадим в коде главной формы следующий метод DrawPolygons:

        /// <summary>
        /// Отрисовка полигонов (Polygon). Один полигон рисуется в виде контура через вызов метода DrawPolygon 
        /// класса Graphics, второй полигон - заполненный, рисуется через вызов метода FillPolygon
        /// класса Graphics.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawPolygons(Graphics g) {
            Pen blueDashedPen = new Pen(Brushes.Blue, 1.5f);
            blueDashedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

            g.DrawPolygon(blueDashedPen, new Point[] {
                new Point(230, 10),
                new Point(370, 30),
                new Point(310, 50),
                new Point(240, 50)
            });

            blueDashedPen.Dispose();

            g.FillPolygon(Brushes.Blue, new Point[] {
                new Point(230, 70),
                new Point(370, 90),
                new Point(310, 110),
                new Point(240, 110)
            });
        }

В первых двух строках метода мы вручную создаём экземпляр «ручки» (Pen) с именем переменной blueDashedPen, и наша «ручка» строится на базе синей кисти (Brushes.Blue) и имеет ширину 1.5 пикселя. Мы также устанавливаем ей стиль штриха (свойство DashStyle), равный System.Drawing.Drawing2D.DashStyle.Dash. Это значит, что контур нашего полигона будет рисоваться не сплошной синей линией, а синей штриховой линией с шириной 1.5 пикселя.

Далее мы вызываем метод DrawPolygon у экземпляра g класса Graphics, в который передаём этот экземпляр «ручки», а также, вторым аргументом вызова, передаём массив точек, состоящий из 4-х элементов. Каждый элемент массива — это экземпляр класса Point, который задаёт очередную вершину полигона. 

Также обратите внимание, что сразу после вызова метода мы освобождаем ресурсы, занимаемые вручную созданным экземпляром Pen, вызывая blueDashedPen.Dispose()

Далее мы рисуем закрашенный полигон при помощи вызова метода FillPolygon у экземпляра g класса Graphics, также состоящий из 4-х точек, у которого координата X для всех точек — идентична координате X у предыдущего полигона, а координату Y мы смещаем на +60 пикселей, т.е. 2-й закрашенный полигон будет нарисован чуть ниже первого. Также замечаем, что для «Fill-метода» в первом аргументе вызова метода идёт экземпляр «кисти», (а не «ручки», как обычно у «Draw-методов»), и в данном случае мы не создаём «кисть» вручную, а переиспользуем доступный экземпляр синей кисти — Brushes.Blue.

Теперь можем добавить вызов нашего нового метода DrawPolygons в обработчик события Paint, после двух ранее добавленных вызовов для отрисовки эллипсов и прямоугольников: 

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
            DrawPolygons(g);
        }

Запустим снова программу, нажав F5 или кнопку «Пуск» на панели инструментов среды разработки, мы должны увидеть следующий результат:

Как видим, оба наших полигона (многоугольника) были успешно отрисованы.

Рисуем на форме дугу

Дуга (Arc) представляет собой часть эллипса (или окружности), которая соединяет две точки этого эллипса (или окружности). Рассмотрим, к примеру, вариант, когда дуга рисуется по эллипсу (пример рисования дуги по окружности будет у нас как раз в коде, и там всё аналогично — просто в случае окружности вокруг неё описан квадрат, с одинаковыми сторонами, а не прямоугольник, как в случае эллипса). Для рисования дуги в GDI+ нужны будут два очень важных параметра (в аргументах вызова метода DrawArc, при помощи которого рисуется дуга, они передаются последними, как мы увидим чуть далее по коду):

  • startAngle (тип данных float) — угол, в градусах, который измеряется по часовой стрелке, начиная от оси X и заканчивая начальной точкой дуги.
  • sweepAngle (тип данных float) — угол, в градусах, который измеряется по часовой стрелке, начиная от значения параметра startAngle и заканчивая конечной точкой дуги.

На рисунке ниже проиллюстрирован эллипс и две точки, принадлежащие этому эллипсу и представляющие собой начальную точку дуги и конечную точку дуги.

Начальная точку дуги мы получаем, двигаясь по часовой стрелке от отметки «0 градусов» на указанное нами количество градусов — в данном примере 180 градусов (жёлтая нижняя пунктирная стрелка показывает направление этого движения). Т.е. параметр startAngle в этом примере равен 180.

Конечную точку дуги мы получим, продолжая двигаться по часовой стрелке на заданное нами количество градусов (жёлтая пунктирная стрелка сверху показывает направление этого движения). В данном примере мы продолжим двигаться на 90 градусов по часовой стрелке от начальной точки и получим конечную точку дуги. Таким образом, параметр sweepAngle в нашем случае равен 90, и он определяет расположение конечной точки нашей дуги.

 

В нашем примере в метод DrawArc, предоставляемый нам средствами GDI+, мы передадим одинаковые значения ширины и высоты для описанного вокруг эллипса прямоугольника (Rectangle), а это значит, что мы будем рисовать дугу не по эллипсу, а по окружности. Но, как я уже упомянул выше, с точки зрения механики вычисления начальной/конечной точек дуги отличий при этом особо никаких нет.

Итак, напишем в коде нашей главной формы следующий короткий метод DrawArc (одноимённый с тем, как он называется в классе Graphics), который принимает на вход параметр g класса Graphics (по аналогии со всеми рассмотренными нами выше методами для отрисовки эллипсов, прямоугольников и полигонов):

        /// <summary>
        /// Метод рисует дугу (Arc), которая обрамлена в прямоугольник с координатами верхнего-левого угла
        /// (380; 10) и размерами ширины и высоты, равными 50 пикселей.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawArc(Graphics g) {
            g.DrawArc(Pens.Orange, new Rectangle(new Point(380, 10), new Size(50, 50)), 180, 90);            
        }

Первым аргументом при вызове метода GDI+ мы передаём экземпляр «ручки» (Pen) оранжевого цвета (Pens.Orange), вторым аргументом — экземпляр прямоугольника, описанного вокруг эллипса, третьим и четвёртым параметром — значения для startAngle и sweepAngle, которые мы рассмотрели выше. Поскольку при создании экземпляра прямоугольника мы передали new Size(50, 50), то это означает, что ширина и высота прямоугольника равны 50 пикселям, т.е. это, фактически, квадрат. А вписанный в этот квадрат эллипс является, фактически, окружностью в нашем примере.

Добавим теперь вызов нашего метода в обработчик события Paint — после вызова DrawPolygons(g):

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
            DrawPolygons(g);
            DrawArc(g);
        }

Теперь запустим нашу программу и видим следующий результат:

 

Заметим справа от синего контура полигона оранжевую дугу, которую мы только что нарисовали.

Рисуем на форме два сектора (Pies)

Сектор (Pie) — это фигура очень схожая с дугой, разница лишь в том, что в случае сектора начальная и конечная точка дуги соединяются линиями (называемыми радиальными) с центром эллипса, из которого получена сама дуга.

Если рассмотреть предыдущую иллюстрацию и соединить начальную и конечную точки дуги с центром эллипса, то мы получим сектор:

Давайте напишем метод DrawPies в коде главной формы, который нарисует контур сектора и закрашенный сектор. Контур сектора получается при помощи вызова метода DrawPie класса Graphics, а закрашенный сектор получаем при помощи вызова метода FillPie, который также есть в классе Graphics:

        /// <summary>
        /// Отрисовка секторов (Pie). Один сектор рисуется в виде контура через вызов метода DrawPie
        /// класса Graphics, второй сектор - заполненный, рисуется через вызов метода FillPie
        /// класса Graphics.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawPies(Graphics g) {
            g.DrawPie(Pens.Magenta, new Rectangle(new Point(440, 10), new Size(100, 50)), 180, 90);
            g.FillPie(Brushes.Magenta, new Rectangle(new Point(440, 70), new Size(100, 50)), 180, 90);
        }

Снова обратим внимание, что в метод DrawPie первым параметром передаётся готовый экземпляр «ручки» (Pens.Magenta), а в случае метода FillPie первый параметр — готовый экземпляр кисти (Brushes.Magenta). Вторым параметром у обоих методов идёт передача экземпляра прямоугольника, который описан вокруг эллипса, из которого будет выделен сектор. Последними параметрами передаются startAngle и sweepAngle — как и у метода DrawArc, что мы уже разобрали выше.

Добавим теперь вызов нашего метода DrawPies в метод-обработчик для события Paint:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
            DrawPolygons(g);
            DrawArc(g);
            DrawPies(g);
        }

Теперь запустим снова приложение, чтобы увидеть результат. Как видим, после дуги отрисовались два сектора — один незаполненный, второй — заполненный:

 

Рисуем на форме несколько линий (Lines)

Линия — это, пожалуй, одна из самых простых фигур, которые можно рисовать при помощи средств GDI+. Для её отрисовки нужен экземпляр «ручки» (Pen), а также указание двух точек (экземпляры класса Point), которые являются концами линии.

Добавим в код главной формы следующие методы: главный метод DrawLines для рисования трёх разных линий и три отдельных метода на каждый из типов линий — DrawSolidCrimsonLine, DrawDashedCrimsonLine и DrawDashedDotCrimsonLine:

        /// <summary>
        /// Отрисовка линий (Line). Рисуется 3 разных линии с различным стилем штриха.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawLines(Graphics g) {
            DrawSolidCrimsonLine(g);
            DrawDashedCrimsonLine(g);
            DrawDashedDotCrimsonLine(g);
        }

        /// <summary>
        /// Отрисовка обычной линии (без заданного стиля штриха).
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawSolidCrimsonLine(Graphics g) {
            g.DrawLine(Pens.Crimson, new Point(550, 10), new Point(650, 50));
        }

        /// <summary>
        /// Отрисовка линии со стилем штриха - "штриховая" (Dash).
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawDashedCrimsonLine(Graphics g) {
            Pen dashedCrimsonPen = new Pen(Brushes.Crimson, 2);
            dashedCrimsonPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

            g.DrawLine(dashedCrimsonPen, new Point(550, 20), new Point(650, 60));

            dashedCrimsonPen.Dispose();
        }

        /// <summary>
        /// Отрисовка линии со стилем штриха - "штрихпунктирная" (DashDot).
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawDashedDotCrimsonLine(Graphics g) {
            Pen dashedDotCrimsonPen = new Pen(Brushes.Crimson, 3);
            dashedDotCrimsonPen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;

            g.DrawLine(dashedDotCrimsonPen, new Point(550, 30), new Point(650, 70));

            dashedDotCrimsonPen.Dispose();
        }

Как видим, главный метод DrawLines вызывает три других метода. Каждый из методов определяет экземпляр «ручки» (Pen) на основе малинового цвета кисти  (Brushes.Crimson). Обратите внимание, что в методе DrawSolidCrimsonLine, который рисует обычную сплошную линию по двум точкам не требуется ничего лишнего — достаточно вызвать метод DrawLine у экземпляра g класса Graphics и передать ему две точки. Это самый простой способ рисования линии, без дополнительных параметров стиля штриха у линии.

В двух других методах — DrawDashedCrimsonLine и DrawDashedDotCrimsonLine мы создаём экземпляры «ручки» вручную через оператор new, а также дополнительно устанавливаем значения для свойства DashStyle у экземпляра «ручки». В первом случае линия у нас будет пунктирной ( что достигается указанием значения стиля штриха DashStyle равным System.Drawing.Drawing2D.DashStyle.Dash), во втором случае — штрихпунктирной (значение System.Drawing.Drawing2D.DashStyle.DashDot).

Как всегда, не забываем освободить ресурсы, занимаемые экземплярами вручную созданных «ручек» при помощи вызова метода Dispose(), в момент, когда «ручки» выполнили свою задачу и более не нужны.

Теперь добавим вызов главного метода DrawLines в метод-обработчик для события Paint:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
            DrawPolygons(g);
            DrawArc(g);
            DrawPies(g);
            DrawLines(g);
        }

Запускаем наше приложение, чтобы увидеть отрисованные на главной форме линии:

 

Рисуем на форме строку с текстом

Давайте теперь научимся рисовать строку с текстом при помощи средств, предоставляемых GDI+. Для отрисовки строки с текстом используется метод DrawString, доступный в классе Graphics. Ему необходимо передать непосредственно строку с текстом, экземпляр шрифта, который необходимо использовать для вывода строки, экземпляр «кисти» (Brush), а также координаты левого-верхнего угла прямоугольника, который описан вокруг строки текста с учётом её размеров.

Создадим в коде главной формы метод DrawTestString и напишем следующий код:

        /// <summary>
        /// Отрисовка тестовой строки внизу формы.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawTestString(Graphics g) {
            Font font = new Font("Arial", 14);
            string testString = "Пример рисования фигур средствами GDI+";
            SizeF sizeOfTestString = g.MeasureString(testString, font);

            g.DrawString(testString, font, Brushes.Purple, new PointF(Width / 2 - sizeOfTestString.Width / 2, Height - Height / 4));
        }

Мы задали переменную font, создав экземпляр шрифта и указав его параметры, далее мы определили переменную testString с тестовой строкой для вывода на форме. Также мы используем метод GDI+ MeasureString, который очень полезен, когда требуется измерить строку, т.е. понять её высоту и ширину при отрисовке. Метод требует двух параметров — сама строка и экземпляр шрифта для отрисовки и возвращает результат с типом данных SizeF. В нашем случае мы записали размер измеренной строки в переменную sizeOfTestString, она пригодится нам в следующей строке для вывода строки на экран.

Ключевой метод для вывода строки — это DrawString, в который мы передаём все необходимые параметры: сама строка (testString), экземпляр шрифта (font), экземпляр «кисти» — в нашем случае это фиолетовая готовая кисть (Brushes.Purple), далее — экземпляр точки типа PointF (его отличие от типа Point в том, что координаты x и y задаются как значения типа float, а не int).

Мы выводим нашу строку по центру относительно горизонтали и примерно на 1/4 высоты главной формы, ближе к нижнему краю формы.

Осталось добавить наш новый метод опять к обработчику события Paint:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
            DrawPolygons(g);
            DrawArc(g);
            DrawPies(g);
            DrawLines(g);
            DrawTestString(g);
        }

Теперь запустим приложение для проверки результата. Наша строка отобразилась на главной форме:

 

Рисуем на форме фундаментальные сплайны (Curves)

Фундаментальный сплайн (Curve) — это последовательность отдельных кривых, которые при объединении образуют более крупную кривую. Более подробное объяснение специфики фундаментальных сплайнов можно найти по следующей ссылке: https://learn.microsoft.com/ru-ru/dotnet/desktop/winforms/advanced/cardinal-splines-in-gdi?view=netframeworkdesktop-4.8

Ключевой, на мой взгляд, момент для понимания и рисования фундаментальных сплайнов — это то, что они строятся на основании переданного массива точек, а также для их отрисовки важен параметр натяжения (tension) между точками. Натяжение, равное 0, превратит сплайн по сути в последовательность прямых, соединяющих все точки. Это объясняется тем, что значение 0 представляет собой как бы «бесконечно сильное физическое натяжение», и это натяжение превращает кривые, соединяющие точки, в прямые. Если же мы будем увеличивать значение натяжения, к примеру, укажем его равным 1, то натяжение между точками будет «слабее», т.е. мы будем получать более плавные изгибы вокруг каждой точки.

Также фундаментальные сплайны в GDI+ можно рисовать открытыми и закрытыми. В открытом фундаментальном сплайне крайние его точки не соединены вместе. Закрытый же сплайн, как и следует из его названия, «закрывает» кривую, т.е. соединяет крайние её точки, образуя закрытый контур кривой.

Лучше всего это понять на практике, поэтому давайте создадим в коде главной формы метод DrawCurves для отрисовки нескольких фундаментальных сплайнов с разными значениями параметра натяжения.

        /// <summary>
        /// Метод рисует несколько фундаментальных сплайнов (Curve) на форме.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawCurves(Graphics g) {
            g.DrawCurve(Pens.LimeGreen, new Point[] {
                new Point(10, 150),
                new Point(30, 190),
                new Point(80, 240),
                new Point(10, 300),
            }, 1);

            g.DrawCurve(Pens.LimeGreen, new Point[] {
                new Point(40, 150),
                new Point(60, 190),
                new Point(110, 240),
                new Point(40, 300),
            }, 2);

            g.DrawCurve(Pens.LimeGreen, new Point[] {
                new Point(70, 150),
                new Point(90, 190),
                new Point(140, 240),
                new Point(70, 300),
            }, 3);

            g.DrawClosedCurve(Pens.LimeGreen, new Point[] {
                new Point(180, 210),
                new Point(200, 220),
                new Point(240, 240),
                new Point(180, 300),
            }, 3, System.Drawing.Drawing2D.FillMode.Alternate);

            g.DrawClosedCurve(Pens.LimeGreen, new Point[] {
                new Point(330, 210),
                new Point(350, 220),
                new Point(400, 240),
                new Point(330, 300),
            }, 3, System.Drawing.Drawing2D.FillMode.Alternate);

        }

Теперь добавим вызов этого метода в метод-обработчик для события Paint главной формы:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
            DrawPolygons(g);
            DrawArc(g);
            DrawPies(g);
            DrawLines(g);
            DrawTestString(g);
            DrawCurves(g);
        }

Запустим нашу программу и увидим следующий результат:

 

Мы нарисовали 3 открытых фундаментальных сплайна (три зелёных кривых слева) с разным параметром натяжения, который меняли от 1 до 3. Видно, что степень «натяжения» между точками фундаментальных сплайнов изменяется при их отрисовке: кривые выглядят по-разному. Далее идёт отрисовка двух других фундаментальных сплайнов, которые являются уже закрытыми. Закрытые сплайны в методе мы нарисовали при помощи вызова метода DrawClosedCurve, доступном в классе Graphics. Открытые сплайны — при помощи метода DrawCurve. Оба метода принимают первым параметром экземпляр «ручки» (Pen) для рисования, далее — массив точек, входящих в фундаментальный сплайн, и третий параметр — это tension, т.е. натяжение, которое мы обсудили. Метод DrawClosedCurve также требует передачи 4-го параметра FillMode, определяющего способ заполнения кривой. Этот параметр является обязательным, однако он не обрабатывается.

Рисуем на форме графический путь (Path)

В GDI+ помимо рассмотренных нами выше фигур ещё есть и интересная возможность объединения различных фигур в графический путь (GraphicsPath). Фактически, мы можем добавить различные фигуры (линии, прямоугольники, дуги и т.д.) в единый путь, который соединит эти фигуры в единое целое. Графический путь представляется классом GraphicsPath, и у него есть различные методы по добавлению в путь фигур. Затем полученный графический путь мы можем передать в метод DrawPath класса Graphics, а также передать в его первом аргументе экземпляр «ручки» (Pen), которой следует нарисовать полученный путь. 

Создадим в коде главной формы метод DrawPath и, как обычно, зададим в качестве его входного параметра переменную g класса Graphics:

        /// <summary>
        /// Метод создаёт экземпляр класса GraphicsPath и добавляет в него различные графические объекты
        /// (4 линии и одну дугу) с последующей их отрисовкой через вызов метода DrawPath класса Graphics.
        /// </summary>
        /// <param name="g">экземпляр класса Graphics, через который производить отрисовку объектов</param>
        private void DrawPath(Graphics g) {
            GraphicsPath path = new GraphicsPath();
            path.AddLine(new Point(450, 230), new Point(450, 210));
            path.AddLine(new Point(450, 210), new Point(550, 210));
            path.AddArc(new Rectangle(550, 110, 100, 100), 180, 180);
            path.AddLine(new Point(650, 210), new Point(750, 210));
            path.AddLine(new Point(750, 210), new Point(750, 230));
            path.CloseFigure();
            
            Pen penForPath = new Pen(Brushes.BurlyWood, 2);
            penForPath.DashStyle = DashStyle.Dash;

            g.DrawPath(penForPath, path);

            penForPath.Dispose();
        }

Как видим, мы сначала создаём новый экземпляр класса GraphicsPath и присваиваем его переменной path. Дальше мы добавляем в наш путь 2 линии (AddLine), 1 дугу (AddArc) и две другие линии, после чего вызываем метод CloseFigure, которая позволяет закрыть текущую полученную фигуру. Мы также создаём вручную экземпляр «ручки» и записываем его в переменную penForGraph, а затем устанавливаем ему стиль штриха.

Наконец, мы вызываем метод DrawPath у экземпляра класса Graphics для отрисовки графического пути, после чего очищаем ресурсы, занятие экземпляром «ручки», поскольку он более нам не нужен.

Опять добавим вызов нашего нового метода в метод-обработчик события Paint:

        private void FrmGDIPaintingExample_Paint(object sender, PaintEventArgs e) {
            Graphics g = e.Graphics;

            // Режим сглаживания выставляем в значение HighQuality (высокое качество)
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            DrawEllipse(g);
            DrawRectangles(g);
            DrawPolygons(g);
            DrawArc(g);
            DrawPies(g);
            DrawLines(g);
            DrawTestString(g);
            DrawCurves(g);
            DrawPath(g);
        }

Снова запустим наше приложение и посмотрим на получившийся результат:

Мы можем заметить, что справа от фундаментальных сплайнов была нарисована замкнутая фигура, которая объединяет в себе 4 линии, одну дугу и представляет скомпонованный нами графический путь.

Стоит сказать, что возможности GDI+ на этом не ограничиваются, и в нём есть другие интересные методы в классе Graphics, которые позволяют рисовать на форме иконки (DrawIcon) изображения (DrawImage), кривую Безье (DrawBezier), последовательность из нескольких линий (DrawLines), а также набор прямоугольников (DrawRectangles). Думаю, что имея ту основу, что мы разобрали с вами в текущей статье, можно будет без особого труда разобраться с тем, как работают и эти интересные методы, но я оставлю это за рамками текущей статьи.

Если вам понравилась статья и вы бы хотели увидеть продолжение (разбор методов DrawIcon, DrawImage и т. д.) — поставьте лайки или напишите комментарии, так я пойму ваш интерес к теме GDI+ и его возможностей.

Ну а пока всё, спасибо за внимание и успехов в работе с GDI+. Внизу вы найдете ссылку на полностью готовый архив с примером, что мы вместе с вами разобрали в рамках статьи. Можете сверить код примера с тем, что получилось у вас.

Ссылка на готовый пример: https://allineed.ru/our-products/download/4-allineed-ru-examples/29-csharp-gdiplus-example

Sign in to your MUO account

Computer sitting on table open to an image inside a software

Windows Forms is a framework that lets you build desktop applications. You can click and drag components like buttons onto a visual user interface. It also helps you manually create various shapes within your code.

This article will show you how to add lines, shapes, and images to your application. This tutorial uses the Visual Studio 2019 Community Edition to show examples.

What Are the Built-In Classes Used for Drawing Graphics?

Windows Forms uses the C# programming language. Its built-in classes and methods allow you to draw various shapes onto a Windows Form canvas. These include the Graphics, Pen, Color, and Brush classes.

Class

Description

Graphics

The Graphics class allows you to draw shapes and lines onto the canvas. It includes methods such as:

  • DrawLine(Pen, Point1, Point2)
  • DrawRectangle(x, y, width, height)
  • DrawPolygon(Pen, PointF[])

Pen

The Pen class allows you to specify the properties of a ‘pen’ tip which you can use to draw your shapes. You can specify properties such as color, thickness, or dash style. Methods include:

  • SetLineCap(LineCap, LineCap, DashCap)

Color

A color object made up of R (red), G (green), and B (blue) values. You will need a color object for many of the built-in methods that create shapes.

SolidBrush, HatchBrush, TextureBrush

These brush classes derive from the «Brush» interface. These classes allow you to color in blank spaces on the canvas. You can also choose to fill the spaces using different patterns or textures. You can specify properties such as the color.

Rectangle, Line, Polygon, Ellipse

You can create objects based on these shapes, and use them when calling methods such as DrawRectangle(). Instead of passing the x, y, width, and height as arguments, you can choose to pass an existing Rectangle object instead.

To view the source code for a running example of the above tutorial, visit the GitHub repository. You can try out the following examples once you’ve created a Winforms application.

How to Add a Paint on Form Load Event Handler

First, add an event handler to draw shapes when the canvas loads.

  1. Add a Paint function for the form.

            private void Form1_Paint(object sender, PaintEventArgs e)
    {
        // Code goes here
    }
  2. Go into the Design View Tab.
  3. In the Properties window, select the lightning icon to open the «Events» tab.
  4. In «Paint», under «Appearance», select the Form1_Paint function. This will execute the function when you run the application.

    Winforms showing how to add a paint event

How to Draw Lines Onto a Windows Form Canvas

You can use a Color, Pen, and the DrawLine() method to draw lines on a canvas.

  1. Inside the Form1_Paint() function, create a Color object with the color you want the line to be. Then, create a Pen object to draw the line with.

            Color black = Color.FromArgb(255, 0, 0, 0);
    Pen blackPen = new Pen(black);
  2. The DrawLine() method from the Graphics class will draw a line using the pen. This will start drawing a line from an x, y position to another x, y position.

            e.Graphics.DrawLine(blackPen, 300, 200, 800, 200);
  3. You can modify the properties for the pen object to change its width, dash style, and start or end cap.

            blackPen.Width = 20;
    blackPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
    blackPen.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
    e.Graphics.DrawLine(blackPen, 300, 200, 800, 200);
  4. Press the green play button at the top of Visual Studio to see the changes.

    Visual Studio App running with a line

How to Draw Shapes Such as Rectangles and Circles

You can use the shapes classes for different shapes, or draw shapes manually onto the canvas.

  1. Create a Color and Pen object as shown in the previous steps. Then, use the DrawRectangle() method to create the rectangle. The arguments are the x and y coordinates for the top-left of the rectangle, along with its width and height.

            Color red = Color.FromArgb(255, 255, 0, 0);
    Pen redPen = new Pen(red);
    redPen.Width = 5;
    e.Graphics.DrawRectangle(redPen, 100, 100, 500, 200);
  2. You can also create a rectangle using the Rectangle Class. First, create a Rectangle object. The arguments are also the x and y coordinates for the top-left corner, width, and height.

            Rectangle rectangle = new Rectangle(100, 350, 500, 200);
  3. Use the DrawRectangle() function to draw the rectangle. Instead of passing the x, y, width, and height like before, you can use the Rectangle object instead.

            e.Graphics.DrawRectangle(redPen, rectangle);
  4. Press the green play button at the top of Visual Studio to see the changes.

    Visual Studio application running to show rectangles

  5. Go back to the code to draw other shapes. Use the DrawEllipse() function to draw a circle.

            Color green = Color.FromArgb(255, 0, 255, 0);
    Pen greenPen = new Pen(green);
    greenPen.Width = 5;
    e.Graphics.DrawEllipse(greenPen, 400, 150, 400, 400);

    When you draw a circle, the x and y coordinates (x=400, y=150) refer to the top-left corner of the circle, not the center of the circle.

    Close up example of circle on canvas and where X,Y starts

  6. To draw other shapes such as triangles or hexagons, use the DrawPolygon() method. Here you can specify a list of coordinates to represent the points of the shape.

            Color blue = Color.FromArgb(255, 0, 0, 255);
    Pen bluePen = new Pen(blue);
    bluePen.Width = 5;

    PointF[] coordinatesForTriangle = new PointF[] {
        new PointF(400, 150),
        new PointF(300, 300),
        new PointF(500, 300)
    };

    e.Graphics.DrawPolygon(bluePen, coordinatesForTriangle);

    The DrawPolygon() method will draw lines between the points specified.

    Visual Studio app running to show triangle on canvas

    ​​​​​​

How to Use the Brush Class to Fill In Shapes With Color

You can use the FillRectangle(), FillEllipses() or FillTriangle() methods to create shapes with a solid color.

  1. First, create a brush object.

            Color purple = Color.FromArgb(255, 128, 0, 0);
    SolidBrush solidBrush = new SolidBrush(purple);
  2. Use the FillRectangle(), FillEllipses() or FillTriangle() methods. They work the same way as the draw functions above, except instead of a Pen, they use a Brush object.

            e.Graphics.FillRectangle(solidBrush, 50, 50, 200, 250);
    e.Graphics.FillEllipse(solidBrush, 300, 50, 200, 200);
    e.Graphics.FillPolygon(solidBrush, new PointF[] { new PointF(700, 150), new PointF(600, 300), new PointF(800, 300) });
    Visual Studio app running to show filled shapes on canvas

  3. You can also input a shape object directly instead of providing coordinates.

            Rectangle rectangle = new Rectangle(100, 350, 500, 200);
    e.Graphics.FillRectangle(solidBrush, rectangle);
  4. Use the HatchBrush to fill the shape using a different fill style, such as a horizontal or vertical pattern.

            Color blue = Color.FromArgb(255, 0, 0, 255);
    Color green = Color.FromArgb(255, 0, 255, 0);
    HatchBrush hatchBrush = new HatchBrush(HatchStyle.Horizontal, green, blue);
    e.Graphics.FillRectangle(hatchBrush, 50, 50, 200, 250);
    Visual Studio app open to show rectangle with horizontal pattern design fill

  5. You can use the TextureBrush to fill a shape using an image. Here, create a bitmap by pointing to an image file. Instead of creating a brush using a color, create it using the image.

            Bitmap image = (Bitmap)Image.FromFile(@"C:\Users\Sharl\Desktop\flag.bmp", true);
    TextureBrush textureBrush = new TextureBrush(image);
    e.Graphics.FillRectangle(textureBrush, 100, 100, 500, 400);
    Visual Studio app open to show shape filled using an image

How to Render Images Onto the Form

To render an image, create a PictureBox control object and add it to the form.

  1. Create a PictureBox control object using an image file.

            PictureBox picture = new PictureBox();
    picture.ImageLocation = @"C:\Users\Sharl\Desktop\flagLarge.bmp";
  2. Set the size of the image and add it onto the form so it renders.

            picture.SizeMode = PictureBoxSizeMode.AutoSize;
    this.Controls.Add(picture);
  3. Press the green start button at the top to view the image.

    Winforms App open to show image rendered on form

Adding More Shapes to Your Windows Form

You should now understand how to add lines, shapes, and images to your Windows form. You can combine shapes to create new shapes. You can also play around with the built-in functions to create more complex shapes.

В этом примере рисование заполненного прямоугольника в форме.

Пример

System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics;
formGraphics = this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, 200, 300));
myBrush.Dispose();
formGraphics.Dispose();

Компиляция кода

Этот метод нельзя вызывать Load обработчик событий. Если скрыта другой формой или изменении размера формы, рисунок перерисовываться не будет. Чтобы сделать автоматическую перерисовку, нужно переопределить OnPaint метод.

Отказоустойчивость

Следует всегда вызывать Dispose на любые объекты, которые потребляют системные ресурсы, такие как Brush и Graphics объектов.

См. также

  • FillRectangle
  • OnPaint
  • Приступая к программированию графики
  • Объекты Graphics и Drawing в Windows Forms
  • Рисование линий и фигур с помощью пера
  • Кисти и закрашенные фигуры в GDI+

Basic overview of drawing in C#

How to use the Graphics class to draw to the screen in C#

The Graphics class is one of the fundamental classes used in programming with Windows Forms and GDI+. Through the Graphics class, you gain access to information about the display resolution and device capabilities. In this article, you’ll learn about the Paint event and how it supplies you regarding an adequately initialized Graphics object. This article also covers the most common operations performed using the Graphics object.

The first thing we will do is open Visual Studio and click “Create a new project” to get started. We are going to create a new Windows Form in C#. You could choose any project name you would like and its destined location on your desktop/pc. 

A blank project will be generated to serve as your canvas. You could change the width and height based on your preference. The next thing we need to handle is the paint event for the form. When the form is drawing itself, it will call this paint event, and then inside of that, we will get a handle to the graphics object. Afterward, we could paint the form ourselves. It is a step-by-step process that we need to accomplish. 

Declare a new graphics object with this syntax above. With this step, we could make new shapes like rectangles. 

How to draw a rectangle

To draw rectangles and squares in C#, the GraphicsObject provides the DrawRectangle() method. There are two ways to use the DrawRectangle() method. We will begin by drawing a rectangle without a pre-created Rectangle object.

  • The first step is to create a new brush. The syntax above is the code that you can use to alter the color and name of the brush.
  • It also needs the coordinates of the rectangle you want to create. To do that, you can encode the x, y coordinates like in the syntax attached. 

  • Since we’ve used 100×100 as the coordinates, it came out as square, but you could change the coordinates to generate your desired shape.

For the second method

  • To draw a rectangle, you will draw four lines. We will make a drawing pin and set that equal a new pen in this method. You could also set the color for your rectangle. The syntax above is the example that will generate your rectangle. 

How to draw a circle

Ellipses and circles are drawn in C# using the DrawEllipse() method of the GraphicsObject class. 

We made a drawing scene representing the “sun,” a circle in one of our examples. 

  • You could declare a “new brush” to create the round object. The syntax above shows the various brushes for different objects: the ground and the sun in the said scene.
  • An ellipse will be generated using the declared sun brush and filled with this syntax in the next step.

How to draw a line

Lines are drawn in C# using the DrawLine() method of the Graphics Object. This method takes a pre-instantiated Pen object and two sets of x and y coordinates (the start and endpoints of the line) as arguments.

A “ground” was made to complete the drawing scene in the example. A straight line represents it. 

Coordinates were also filled up to determine the width, height, and length to set up the ground.

The next step in this project is to try drawing a person! A stickman person, to be exact. It will be composed of a circle for its head, a line for its limbs and body.

  • We added another drawing pen to change its color, white. 

In the syntax above, we tried to make a whole component to make a stickman. With various lines and objects, it resulted in the image below. 

The background is also changed to the color blue! And there you go, a scene with a stickman was made using simple objects and lines. 

How to draw an image

To draw an image, it will require creating a bitmap from the file. To do this, the syntax below will help to run the image.  We will use the image above as the background for our generated image.

The syntax above draws the image, but the problem is that our form and image aren’t the exact sizes.  We could stretch the image to fit the form by doing a new rectangle.

The image will be stretched to fit the form better with this code. 

We will also try to attach some images to the scene. We will do next to draw an image bitmap from the file again. 

The attached image is quite big, so you could opt for a smaller size of the image you want. 

This is the revised image of the cat once you’ve scaled it correctly. 

Here is the complete syntax for the background and the cat. Make sure to layer your drawings correctly to make them appear in the correct order. After the cat image, we will draw the bird. 

Here is the image after the code for the bird image is generated and run. 

To add an extra effect, we will add a line object in the scene. 

The last thing that we will add to this project is text. To include text in your image, follow this syntax below. Make sure to set a font style first!

The text is added and repeated three times. The project is done!

This article shows how various graphical objects can be drawn within a drawing programmatically using C#. It may be quite challenging, but first but with troubleshooting, patience, and creativity, you could also finish a project in no time!

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Планировщик заданий windows 10 спящий режим
  • New task manager windows 11
  • Калибровка тачпада на ноутбуке windows 11
  • Горячие клавиши windows презентация
  • Как перенести папку пользователи с диска с на диск д в windows 10