Как рисовать в visual studio 2019
БлогNot. Visual Studio, простое рисование на графической канве формы и дисплея
Visual Studio, простое рисование на графической канве формы и дисплея
В блоге уже есть ряд заметок, показывающих работу с графической канвой формы в Visual C++ (раз, два). Цель этого примера - продемонстрировать, как одним и тем же кодом вывести программно созданный рисунок сначала в окно формы, а затем просто на дисплей вне окна. Сделать последнее позволяет метод GetDC из Windows API, получающий контекст графического устройства.
Итак, создадим пустой проект Windows Forms, я делал из сохранённого заранее шаблона в Studio 2015. Дальше процесс расписан по шагам.
1. В классе формы определён флажок, показывающий, нужно ли перерисовывать картинку:
2. Он инициализирован в методе Load формы (так как при загрузке нужно отрисовать в первый раз):
3. Всё рисование делается в методе Paint формы (исключений из этого правила мало):
4. Некоторые события формы должны будут инициализировать принудительную перерисовку, например, когда пользователь закончил изменение размеров окна (событие SizeChanged ):
5. Передав в наш Draw другой графический контекст (например, контекст графического экрана Windows), можно нарисовать ту же графику "в другом месте", например, поверх всех окон или под ними.
Покажем в качестве примера перехват графического контекста основного дисплея (при изменении размеров окна нашей формы картинка будет перерисовываться вне окна формы, начиная с левого верхнего угла экрана). Решение работает только для Windows.
5.1. Заинклудить в самом начале файла формы .h:
5.2. Подключить к проекту стандартную Windows-библиотеку user32 . Для этого перейти к меню Проект, Свойства проекта, открыть слева список Компоновщик, затем Ввод, и прописать в поле "Дополнительные зависимости" значение
5.3. Проверить, что в namespace проекта подключены
5.4. Метод Paint формы изменится, так как перед вызовом Draw он будет получать графический контекст дисплея:
Рисование по-прежнему зависит от положения окна приложения, но можно было вместо this->ClientSize попытаться использовать размеры экрана.
Перед тем, как начать заниматься рисованием линий и фигур, отрисовкой текста или отображением изображений и управления ими с помощью GDI+, необходимо создать объект Graphics. Объект Graphics представляет собой поверхность рисования GDI+ и используется для создания графических изображений.
Существует два этапа работы с графикой:
Использование объекта Graphics для рисования линий и фигур, отрисовки текста или отображения изображений и управления ими.
Создание графического объекта
Графический объект можно создать несколькими способами.
Как создать графический объект
Получите ссылку на графический объект как часть PaintEventArgs события формы или элемента управления Paint. Обычно ссылка на графический объект таким образом берется при создании кода рисования для элемента управления. Аналогичным образом можно также получить графический объект в качестве свойства PrintPageEventArgs при обработке события PrintPage для объекта PrintDocument.
Вызовите метод элемента управления или формы CreateGraphics, чтобы получить ссылку на объект Graphics, представляющий собой область рисования этого элемента управления или формы. Используйте этот метод, если необходимо нарисовать на форме или элементе управления, которые уже существуют.
Создайте объект Graphics из любого объекта, наследуемого от Image. Этот вариант подходит если вы хотите изменить уже существующее изображение.
Необходимые действия будут более подробно описаны в следующих разделах.
PaintEventArgs в обработчике событий Paint
При программировании PaintEventHandler для элементов управления или PrintPage для объекта PrintDocument, графический объект предоставляется в качестве одного из свойств PaintEventArgs или PrintPageEventArgs.
Получение ссылки на графический объект из PaintEventArgs в событии Paint
Назначьте переменную для ссылки на объект Graphics, переданный как часть PaintEventArgs.
Введите код, чтобы нарисовать форму или элемент управления.
В следующем примере показано, как ссылаться на объект Graphics из PaintEventArgs в событии Paint :
Метод CreateGraphics
Также можно воспользоваться методом элемента управления или формы CreateGraphics, чтобы получить ссылку на объект Graphics, представляющий собой область рисования этого элемента управления или формы.
Создание графического объекта с помощью метода CreateGraphics
Вызовите метод CreateGraphics для формы или элемента управления, на которых требуется отрисовка графики.
Создание из объекта изображения
Кроме того, можно создать графический объект из любого объекта, производного от класса Image.
Как создать графический объект на основе изображения
Вызовите метод Graphics.FromImage, указав имя переменной изображения, из которой требуется создать объект Graphics.
В приведенном ниже примере показано использование объекта Bitmap:
Объекты Graphics можно создавать только из неиндексированных файлов формата .bmp, например 16-разрядных, 24-разрядных и 32-разрядных. Каждый пиксель неиндексированных файлов .bmp содержит цвет. В индексированных .bmp файлах же каждый пиксель содержит индекс таблицы цветов.
Рисование и обработка фигур и изображений
Объект Graphics после создания может использоваться для рисования линий и фигур, отрисовки текста или отображения изображений и управления ими. Вот основные объекты, которые используются с объектом Graphics:
Класс Pen — используется для рисования линий, структурирования фигур или отрисовки других геометрических представлений.
Класс Brush — используется для заполнения областей графики, в частности для заполненных фигур, изображений или текста.
Класс Font — предоставляет собой описание фигур, используемых при отрисовке текста.
Структура Color — представляет различные отображаемые цвета.
Использование созданного графического объекта
Обратитесь к соответствующему объекту, указанному выше, чтобы нарисовать необходимые объекты.
В Конструктор XAML фигура — это именно то, что нужно ожидать. Например, прямоугольник, круг или эллипс. Объект контур является более универсальной версией фигуры. Можно, например, изменить эти объекты или объединить их в форме новых фигур.
Для фигур и контуров используется векторная графика, поэтому их легко масштабировать для дисплеев с высоким разрешением.
Рисование фигуры
Фигуры можно найти в окне Ресурсы.
Перетащите любую нужную фигуру в область рисования. Затем используйте маркеры фигуры, чтобы масштабировать, поворачивать, перемещать и наклонять фигуру.
Рисование контура
Контур — это последовательность соединенных линий и кривых. Используйте контур для создания интересных фигур, которые недоступны в окне Ресурсы.
Контур можно нарисовать с помощью линии, пера или карандаша. Эти инструменты доступны на панели Средства.
Рисование прямой линии
Используйте средства Перо или Линия.
Использование средства "Перо"
Щелкните один раз в области рисования, чтобы определить начальную точку, а затем щелкните еще раз для задания конечной точки линии.
Использование средства "Линия"
В области рисования зажмите кнопку мыши в том месте, где должна начинаться линия, затем перетащите и отпустите кнопку мыши там, где линия завершается.
Рисование кривой
Используйте средство Перо.
В области рисования щелкните один раз, чтобы определить начальную точку линии, а затем зажмите и перетащите указатель мыши, чтобы задать нужную кривизну.
Если требуется замкнуть контур, щелкните начальную точку линии.
Изменение формы кривой
Используйте средство Непосредственное выделение.
Щелкните фигуру, а затем потяните за любую точку на фигуре, чтобы изменить форму кривой.
Рисование контура произвольной формы
Используйте средство Карандаш.
Нарисуйте произвольный контур в области рисования, как если бы вы пользовались настоящим карандашом.
Удаление части контура
Используйте средство Непосредственное выделение.
Выберите контур, содержащий сегмент, который требуется удалить, и нажмите кнопку Удалить .
Удаление точки контура
Используйте средство Выделение, чтобы выбрать контур. Затем с помощью средства Перо выделите точку, которую требуется удалить.
Добавление точки контура
Используйте средство Выделение, чтобы выбрать контур. С помощью средства Перо щелкните в любом месте контура, где необходимо добавить точку.
Преобразование фигуры в контур
Чтобы изменить фигуру теми же способами, которые вы использовали для изменения контура, преобразуйте фигуру в контур. Выберите фигуру, а затем щелкните Формат > пути > Преобразование в путь.
Посмотрите короткое видео: , работающих с путями: Преобразование фигуры в контур.
Функция Преобразовать в путь сейчас недоступна для приложений UWP с TargetPlatformVersion версии 10.0.16299.0 и выше.
Объединение контуров
Контуры и фигуры можно объединить в один контур.
Число | Действие |
---|---|
Две фигуры до объединения | |
Объединение | |
Divide | |
Пересечение | |
Исключение перекрытия | |
Subtract |
Посмотрите короткое видео: , работающих с путями: объединение путей.
Создание составного пути
При создании составного контура все пересекающиеся части контуров исключаются из результата, и результирующий контур принимает визуальные свойства нижнего контура.
В любой момент после создания составного пути он может быть разбит на составляющие части.
Посмотрите короткое видео: , работающих с путями: создание составного пути.
Создание контура кадрирования
Контур обрезки — это контур или фигура, применяемая к другому объекту, чтобы скрыть части маскируемого объекта за пределами контура обрезки.
Посмотрите короткое видео: , работающих с путями: создание обтравочного контура.
Запустите Microsoft Visual Studio. Данный урок построен на базе версии 2012 года. Алгоритм работы с графикой аналогичен и для других версий.
Чтобы создать новый проект зайдите в меню "ФАЙЛ" в левом верхнем углу и выберите "Создать" -> "Проект" (или комбинацией клавиш Ctrl + Shift + N)как показано на рисунке.
После создания проекта у вас на экране появится Форма (Form1) и Панель Элементов. Выберите их этой панели объекты:
- Button - кнопка,
- PictureBox - поле для рисования,
и расположите эти объекты на созданной ранее форме.
Выбрав на форме объект PictureBox, на панели "Свойства" вы можете настроить его характеристики. Например: Во вкладке "Макет" -> "Size" вы можете указать точный размер объекта в пикселях.
- Width - ширина по X ;
- Height - высота по Y ;
Выберите на своей форме объект Button1. В окне "Свойства" найдите кнопку "События" , во вкладке "Действие" напротив "Click" выберите название метода, отвечающего за событие при нажатии на кнопку.
В файле Form1.cs будет создан метод, и будет представлять из себя:
Между фигурными скобками "< >" необходимо написать код, который будет выполняться на событие клика по кнопке.
Например, можно нарисовать прямоугольник следующим образом:
и файл Form1.cs будет иметь вид:
Чтобы запустить Проект нужно нажать на кнопку "Запуск" в виде зеленого треугольника на панели действий, или использовать "горячую клавишу" F5.
Для рисования графических примитивов в оконных приложениях используются 4 основных типа объектов:
- точка (Pixel);
- перо (Pen);
- кисть (Brush);
- фон (Background).
Точка
Цвет точки задается с помощью функции
COLORREF SetPixel(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int X, // x-координата точки
_In_ int Y, // y-координата точки
_In_ COLORREF crColor ); // цвет точки
В случае удачного завершения возвращаемое значение функции дублирует цвет точки, в случае ошибки возвращает -1.
Цвет точки представляет собой 32-битное число, заданное в системе RGB:
Можно также воспользоваться функцией
Значения красного, зеленого и синего используются в диапазоне 0…255.
Перо используется для рисования линий и контуров замкнутых фигур. Цвет пера задается функцией
HPEN CreatePen(
_In_ int fnPenStyle, // стиль пера
_In_ int nWidth, // ширина пера (в пикселях)
_In_ COLORREF crColor ); // цвет пера
Стили пера fnPenStyle могут быть заданы согласно таблице
При успешном завершении функция возвращает дескриптор пера, в случае неудачи — константу NULL .
Кисть
Кисть используется для закрашивания замкнутых объектов. Цвет кисти задается с помощью функции
При успешном завершении функция возвращает дескриптор кисти, в случае неудачи — константу NULL .
Эта же функция используется для задания цвета фона .
Можно заранее создать несколько кистей и перьев, а затем выбирать нужные с помощью функции
HGDIOBJ SelectObject(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ HGDIOBJ hgdiobj ); // дескриптор объекта
Рисование графических примитивов
Перемещение в указанную точку осуществляется функцией:
BOOL MoveToEx(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int X, // координата x точки
_In_ int Y, // координата y точки
_Out_ LP POINT lpPoint ); // указатель на структуру POINT
Координаты точки x и у определяются в пикселях относительно левого верхнего угла.
В случае успешного выполнения возвращает ненулевое значение.
Структура POINT имеет вид
Рисование отрезков осуществляется функцией:
BOOL LineTo(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int nXEnd, // координата x конечной точки
_In_ int nYEnd ); // координата y конечной точки
В случае успешного выполнения возвращает ненулевое значение.
Рисование прямоугольника осуществляется функцией:
BOOL Rectangle(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int nLeftRect, // x-координата верхнего левого угла
_In_ int nTopRect, // y-координата верхнего левого угла
_In_ int nRightRect, // x-координата нижнего правого угла
_In_ int nBottomRect); // координата нижнего правого угла
Рисование прямоугольника начинается из точки, в которую осуществлено перемещение с помощью функции MoveTo() .
В случае успешного выполнения возвращает ненулевое значение.
Рисование эллипса осуществляется функцией:
BOOL Ellipse(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int nLeftRect, // x-координата верхнего левого угла
_In_ int nTopRect, // y-координата верхнего левого угла
_In_ int nRightRect, // x-координата нижнего правого угла
_In_ int nBottomRect); // координата нижнего правого угла
В случае успешного выполнения возвращает ненулевое значение.
Рисование дуги осуществляется функцией:
BOOL ArcTo(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int nLeftRect, // x-координата верхнего левого угла
_In_ int nTopRect, // y-координата верхнего левого угла
_In_ int nRightRect, // x-координата нижнего правого угла
_In_ int nBottomRect, // y-координата нижнего правого угла
_In_ int nXRadial1, // x- координата конца первого радиуса
_In_ int nYRadial1, // y- координата конца первого радиуса
_In_ int nXRadial2, // x- координата конца второго радиуса
_In_ int nYRadial2 ); // y- координата конца второго радиуса
В случае успешного выполнения возвращает ненулевое значение.
Вывод текста в окно
Для вывода текста в поле окна используется функция
BOOL TextOut(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int nXStart, // x-координата начала вывода текста
_In_ int nYStart, // y-координата начала вывода текста
_In_ LPCTSTR lpString, // указатель на строку текста
_In_ int cchString ); // количество символов для вывода
В случае успешного выполнения возвращает ненулевое значение.
Задать цвет фона под буквами можно с помощью функции
COLORREF SetBkColor(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ COLORREF crColor ); // цвет
Задать цвет букв можно с помощью функции
COLORREF SetЕTextColor(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ COLORREF crColor ); // цвет
В случае неудачного завершения эти функции возвращают константу CLR_INVALID=0xFFFF .
Использование графических функций
При обработке вызова BeginPaint() , Windows обновляет фон рабочей области с помощью кисти, заданной в поле hbrBackground структуры WNDCLASS , описанной здесь. Вызов BeginPaint() делает всю рабочую область действительной (не требующей перерисовки) и возвращает описатель контекста устройства. Контекст устройства описывает физическое устройство вывода информации (например, экран) и его драйвер. Описатель контекста устройства необходим для вывода в рабочую область окна текста и графики.
- hwnd – дескриптор окна;
- lpPaint – указатель на структуру PAINTSTRUCT .
Структура PAINTSTRUCT имеет вид
typedef struct tag PAINTSTRUCT <
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32]; > PAINTSTRUCT , * P PAINTSTRUCT ;
- hdc – дескриптор контекста устройства.
- fErase – ненулевое значение стирает фон.
- rcPaint – структура RECT , определяющая верхний левый и нижний правый углы рабочей области.
Функция EndPaint() освобождает описатель контекста устройства, после чего его значение нельзя использовать. Возвращает всегда ненулевое значение.
Получение дескриптора контекста устройства осуществляется вызовом функции:
hWnd – дескриптор окна, для которого используется контекст устройства.
Возвращаемое значение – дескриптор контекста устройства.
освобождает контекст устройства hDC для данного окна hWnd , после чего значение контекста устройства нельзя использовать. Возвращает всегда ненулевое значение.
Здравствуйте, Елена, спасибо за Ваш сайт, много интересного. По поводу графики отмечу, что было бы хорошо, если бы здесь было бы упоминание про двойную буферизацию (это помогает избавиться от эффектов мерцания, если такие наблюдаются при рисовании). Вот часть кода из моей программы.
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
switch (message)
//.
case WM_PAINT :
PaintAll(hwnd);
return 0;
case WM_ERASEBKGND:
return 0;
//.
>
return DefWindowProc (hwnd, message, wparam, lparam);
>
namespace e
extern HWND hpicturebox; // это окно где что-то рисуется
>
void PaintAll( HWND hwnd)
HDC hdc, hcmpdc;
HBITMAP hbmp;
HBRUSH hbrush;
HPEN hpen;
PAINTSTRUCT ps;
RECT rect;
BeginPaint(hwnd, &ps); // здесь hwnd окна на котором расположен hpicturebox
EndPaint(hwnd, &ps);
GetClientRect(e::hpicturebox, &rect);
hdc = GetDC(e::hpicturebox);
hcmpdc = CreateCompatibleDC(hdc);
hbmp = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
hbrush = CreateSolidBrush(RGB(255, 255, 255));
hpen = CreatePen(PS_INSIDEFRAME, 1, RGB(255, 255, 255));
BeginPaint(e::hpicturebox, &ps);
SelectObject(hcmpdc, hbmp);
SelectObject(hcmpdc, hbrush);
SelectObject(hcmpdc, hpen);
Rectangle(hcmpdc, rect.left, rect.top, rect.right, rect.bottom);
//
PaintPicturebox(hcmpdc); // //
SetStretchBltMode(hdc, COLORONCOLOR);
BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, hcmpdc, 0, 0, SRCCOPY);
EndPaint(e::hpicturebox, &ps);
ReleaseDC(e::hpicturebox, hdc);
DeleteDC(hcmpdc);
DeleteObject(hbmp);
DeleteObject(hbrush);
DeleteObject(hpen);
>
Читайте также: