Как нарисовать точку в c windows forms

Обновлено: 06.07.2024

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

Содержание

Поиск на других ресурсах:

Условие задачи

Задана формула функции двух переменных z = sin(x) + cos(y) . Разработать приложение, которое рисует график этой функции в отдельной форме.

Дополнительно реализовать поворот графика влево, вправо, вверх, вниз. Также нужно выводить оси OX , OY , OZ .

Математическая постановка задачи

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

График функции двух переменных z(x,y) строится в параллелепипеде с размерами (xx1, xx2) , (yy1, yy2) , (zz1, zz2) .

Для использования поворота системы в 3-мерном пространстве возникает понятие точки ( x0 , y0 , z0), относительно которой происходит поворот системы координат.

Также возникает понятие углов:

    (альфа) – поворот системы относительно оси OZ ; (бета) – поворот системы относительно оси OX .

Сдвиг в точку ( x0 , y0 , z0 ) с учетом поворота на углы и описывается известными соотношениями

Преобразования координат 3D Формулы

После перемножения матриц получаем формулу для вычисления:

02_02_00_013_formula_02

По этой формуле будет происходить преобразование системы координат и масштабирование (рисунок 1).

Рисунок. Сдвиг и поворот системы координат

Рис. 1. Сдвиг и поворот системы координат

Необходимо определиться, в какой плоскости монитора будут лежать оси координат OX , OY , OZ . Принимаем, что в плоскости монитора лежат оси OX и OY . А ось OZ перпендикулярна экрану.

Координаты расчетной точки (x, y) прижимаются к точке (0, 0) по формулам:

где A , a – коэффициенты перспективы, которые подбираются экспериментально в зависимости от функции.

Выполнение

1. Создание проекта как Windows Forms Application

2. Создание формы Form1 .

Создать форму по образцу, как показано на рисунке 2.

Настроить следующие свойства компонент и формы:

3. Создание формы Form2 .

Создать новую форму. Подробный процесс создания новой формы описывается здесь .

Разместить на форме четыре компонента типа Button. Автоматически создается четыре объекта с именами button1, button2, button3, button4.

Настроить свойства компонент и формы следующим образом:

Приблизительный вид формы Form2 изображен на рисунке 3.

4. Ввод внутренних переменных в форму Form2 .

Все внутренние переменные, использующиеся для организации вывода графика, размещаются в классе формы Form2. Поэтому, сначала надо активизировать модуль « Form2.pas ».

В модуль формы Form2 вводятся следующие внутренние переменные с классом видимости private:

  • xx1, xx2, yy1, yy2 – соответствуют координатам точек, которые отображаются на экране монитора;
  • массивы xx и yy предназначены для вывода плоскости из 4-х точек. Область определения функции z = f(x, y) разбивается на прямоугольники, на любом из которых функция экстраполируется ребрами четырехугольника.

В разделе public вводятся:

  • переменные X_min , Y_min , X_max , Y_max вещественного типа, которые представляют реальные координаты параллелепипеда, в котором выводится график функции. Эти переменные заполняются из основной формы Form1 экспериментальным путем:
  • переменные alfa, beta вещественного типа, которые отображают углы наблюдения за графиком функции. Заполняются из главной формы Form1;
  • переменные x0, y0, z0 вещественного типа. Отображают величины из главной формулы вычисления (см. математическую постановку задачи);
  • переменная A вещественного типа. Представляет коэффициент перспективы и подбирается экспериментально;
  • переменная f_show логического типа используется для указания того, что нужно перерисовать график, в случае изменения положения углов alfa и beta.

После введения переменных в текст программы, фрагмент класса формы Form2 имеет вид:

Переменные, имеющие идентификатор доступа public, заполняются из формы Form1 .

5. Программирование внутренних методов в форме Form2 .

В текст класса Form2 вводятся три дополнительных метода:

  • функция преобразования системы координат и масштабирования Zoom_XY() ;
  • функция func() для которой выводится график;
  • функция рисования графика Show_Graphic().

Листинг метода преобразования системы координат следующий:

Листинг метода func() следующий.

В этом методе вместо строки

можно сделать вставку собственной функции.

Непосредственный вывод графика функции реализован в методе Show_Graphic() . Листинг метода Show_Graphic() следующий.

Объясним некоторые фрагменты кода в методе Show_Graphic().

Область определения функции z = f(x,y) разбивается на прямоугольники, на любом из которых функция экстраполируется с ребрами четырехугольника. Построение четырехугольников на экране реализуется с помощью метода DrawLine().

После очистки канвы происходит рисование осей координат и методом DrawLine() выводятся фрагменты поверхности.

При рисовании поверхности, из метода Show_Graphic() вызывается метод Zoom_XY(), что осуществляет преобразование и масштабирование из реальных координат в экранные координаты.

6. Программирование события Paint формы Form2.

Обработчик события Form2_Paint() получает два параметра. Первый параметр типа System.Object , второй параметр типа PaintEventArgs .

Параметр типа PaintEventArgs содержит объект Graphics, необходимый для рисования на поверхности формы.

Листинг обработчика события Form2_Paint() следующий.

7. Программирование обработчиков событий клика на кнопках button1, button2, button3, button4.

Поворот графика происходит в момент, когда пользователь делает клик на одной из кнопок, размещенных на форме Form2 (элементы управления button1, button2, button3, button4).

Отображение графика зависит от внутренних переменных alfa и beta. Переменная alfa содержит угол поворота относительно оси OZ . Переменная beta содержит значение угла поворота вокруг оси OX .

Поэтому, в обработчиках событий происходит изменение значений alfa и beta на некоторую величину. По желанию, можно установить собственную величину изменения alfa и beta.

Листинг обработчиков событий приведен ниже.

В вышеприведенных обработчиках событий, событие Paint генерируется явно с помощью унаследованного метода Invalidate(). Этот метод делает перерисовывание всей клиентской области программным путем.

Метод Invalidate() имеет несколько перегруженных вариантов. Например, если нужно обновить заданный прямоугольник, то нужно создать такой код:

8. Программирование обработчиков событий MouseDown, MouseMove и MouseUp.

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

Если нажать клавишу мыши и удерживать ее нажатой над формой Form2, а потом отпустить, то генерируются такие события (рисунок 4):

  • MouseDown – генерируется, если пользователь делает клик мышкой на форме Form2;
  • MouseMove – генерируется, если пользователь перемещает мышку над формой Form2 (независимо, нажата ли одна из кнопок мышки);
  • MouseUp – генерируется, если пользователь отпускает кнопку мышки после нажатия.

9. Листинг модуля « Form2.cs ».

Ниже приведен полный текст файла ” Form2.cs ”, который соответствует форме Form2.

10. Программирование события клика на кнопке button1 формы Form1 (вызов формы рисования графика функции).

При клике на кнопке button1 из формы Form1 может выводиться график функции.

Обработчик события клика на кнопке Button1 имеет вид.

11. Запуск программы.

После запуска программы на выполнение, форма графика функции изображена на рисунке 5.

Для рисования графических примитивов в оконных приложениях используются 4 основных типа объектов:

  • точка (Pixel);
  • перо (Pen);
  • кисть (Brush);
  • фон (Background).

Точка

Цвет точки задается с помощью функции

COLORREF SetPixel(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int X, // x-координата точки
_In_ int Y, // y-координата точки
_In_ COLORREF crColor ); // цвет точки

В случае удачного завершения возвращаемое значение функции дублирует цвет точки, в случае ошибки возвращает -1.

RGB

Цвет точки представляет собой 32-битное число, заданное в системе RGB:

Можно также воспользоваться функцией

RGB(
_ Red As Integer, // красный
_ Green As Integer, // зеленый
_ Blue As Integer); // синий

Значения красного, зеленого и синего используются в диапазоне 0…255.

Перо используется для рисования линий и контуров замкнутых фигур. Цвет пера задается функцией

HPEN CreatePen(
_In_ int fnPenStyle, // стиль пера
_In_ int nWidth, // ширина пера (в пикселях)
_In_ COLORREF crColor ); // цвет пера

Стили пера fnPenStyle могут быть заданы согласно таблице

Кисть

Кисть используется для закрашивания замкнутых объектов. Цвет кисти задается с помощью функции

HBRUSH CreateSolidBrush(
_In_ COLORREF crColor ); // цвет кисти

Можно заранее создать несколько кистей и перьев, а затем выбирать нужные с помощью функции

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 имеет вид

typedef struct tag POINT <
LONG x;
LONG y; > POINT , *P 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 .

Использование графических функций

HDC BeginPaint(
_In_ HWND hwnd,
_Out_ L P PAINTSTRUCT lpPaint );

При обработке вызова 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 , определяющая верхний левый и нижний правый углы рабочей области.

typedef struct _ RECT <
LONG left; LONG top;
LONG right; LONG bottom; > RECT , * P RECT ;
BOOL EndPaint(
_In_ HWND hWnd,
_In_ const PAINTSTRUCT *lpPaint );

Функция EndPaint() освобождает описатель контекста устройства, после чего его значение нельзя использовать. Возвращает всегда ненулевое значение.

Получение дескриптора контекста устройства осуществляется вызовом функции:

hWnd – дескриптор окна, для которого используется контекст устройства.
Возвращаемое значение – дескриптор контекста устройства.

освобождает контекст устройства hDC для данного окна hWnd , после чего значение контекста устройства нельзя использовать. Возвращает всегда ненулевое значение.

Прошу прощения. Может я что-то не увидел, но какую библиотеку надо подключить? Здравствуйте, Елена, спасибо за Ваш сайт, много интересного. По поводу графики отмечу, что было бы хорошо, если бы здесь было бы упоминание про двойную буферизацию (это помогает избавиться от эффектов мерцания, если такие наблюдаются при рисовании). Вот часть кода из моей программы. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

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; // это окно где что-то рисуется
>

БлогNot. Visual C++: рисуем мышью на форме

Visual C++: рисуем мышью на форме

Предыдущая заметка по теме была вот здесь, а дальше легко найти по цепочке :) Тем не менее, простого примера на рисование мышкой "как в Paint" что-то не видно, попробуем сделать его прямо сейчас.

1. Рисовать будем непосредственно на канве формы, хотя вообще-то лучше на PictureBox , растянутом на всю форму. Тогда просто получите MyGraphics от этого PictureBox . В классе формы приложения Windows Forms пропишем нужные данные:

На событие загрузки формы (Load) проинициализируем данные:

По событию MouseDown формы (нажатие кнопки мыши) будем разрешать рисование:

а по событию MouseUp (отпускание кнопки мыши) - запрещать:

По событию. "движение мыши" формы (MouseMove) будем рисовать, если включён флажок isPaint и текущие координаты мыши отличаются от последних координат, сохранённых в переменной p . Также запомним новые координаты:

Вместо точки мы здесь выводим эллипс 2x2 пиксела. Работать с массивами отдельных пикселов можно, например, через System::Windows::Media::Imaging::WriteableBitmap.

Очищать рисунок можно по любому удобному событию или выбору кнопки (пункта меню). Используем для этого двойной щелчок (MouseDoubleClick) по форме:

2. Увы, при быстром движении мыши обработчик события MouseMove не будет успевать рисовать маленькие эллипсы и линия получится разрывной. Проще всего решить проблему, соединяя текущую точку p и точку, полученную из текущего положения мыши, линией.

Вот как изменится весь написанный нами код:

3. Наконец, существует удобный способ рисования, связанный с классом System::Drawing::Drawing2D::GraphicsPath.

Ниже прилагается полный листинг для вставки в приложение Windows Forms. Его внимательный анализ поможет вам освоить и этот способ. Кроме того, здесь MouseDown различает кнопки мыши, MouseUp определяет число кликов, а MouseMove можно заставить рисовать "непрерывно", раскомментарив одну строчку.

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

Пространство имен System.Drawing (Рисование) обеспечивает доступ к функциональным возможностям графического интерфейса GDI+ , используя около 50 (!) классов, в том числе класс Graphics. Чуть позже мы будем использовать дополнительные пространства имен System.Drawing.Drawing2D, System.Drawing.Imaging, System.Drawing.Printing, System.Drawing.Text, расширяющие функциональные возможности библиотеки System.Drawing.

Класс Graphics предоставляет методы рисования на устройстве отображения (другие термины — графический контекст, «холст»). Определимся сразу, на чем мы хотим рисовать. Далее в примерах он обозначается как объект g.

Способы задания «холста»

3. В принципе, иногда (если все графические операции выполняются внутри одной функции) эти четыре строки могут быть заменены одной строкой:
Graphics g = Graphics.FromImage(new Bitmap(pictureBox1.Width, pictureBox1.Height));
После этого можно задать фон холста белым:
g.Clear(Color.White);

4. Еще один пример задания «холста» на форме через дескриптор окна:
Graphics g = Graphics.FromHwnd(this.Handle);
Далее в примерах конкретизируются эти способы.

Объекты других классов из библиотеки System.Drawing

Класс Pen (перо) используется для рисования линий и кривых, а классы, производные от класса Brush (кисть) используются для закраски замкнутых контуров (см. ниже).

Класс GraphicsPath позволяет задавать последовательность соединенных линий и кривых, класс Region описывает внутреннюю часть графической формы, состоящей из многоугольников и контуров.

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

Класс Graphics

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

Имя метода Описание Число перегрузок
Clear(Color) Очищает всю поверхность рисования и выполняет заливку поверхности указанным цветом фона. 1
CopyFromScreen(Point, Point, Size) Выполняет передачу данных о цвете, соответствующих прямоугольной области пикселей, блоками битов с экрана на поверхность рисования объекта Graphics. 4
Dispose() Освобождает все ресурсы, используемые данным объектом Graphics. 1
DrawArc(Pen, Rectangle, Single, Single) Рисует дугу, которая является частью эллипса, заданного структурой Rectangle. 4
DrawBezier(Pen, Point, Point, Point, Point) Рисует кривую Безье, определяемую четырьмя структурами Point. 3
DrawBeziers(Pen, Point[]) Рисует несколько (N) кривых Безье, определяемых массивом из (3N+1) структур Point. 2
DrawCloseCurve(Pen, Point[ ]) Рисует замкнутый фундаментальный сплайн 4
DrawEllipse(Pen, Rectangle) Рисует эллипс 4
DrawIcon(Icon, Rectangle) Рисует значок 2
DrawImage(Image image, int x, int y) Рисует заданное изображение image, используя его фактический размер в месте с координатами (x,y) 30
DrawLine(Pen, Point, Point) Проводит линию, соединяющую две структуры Point. 4
DrawLines(Pen, Point[ ]) Рисует набор сегментов линий, которые соединяют массив структур Point. 2
DrawPath(Pen, gp) Рисует пером Pen объект GraphicsPath gp. 1
DrawPie(Pen, Rectangle, Single, Single) Рисует сектор, который определяется эллипсом, заданным структурой Rectangle и двумя радиалtьными линиями. 4
DrawPolygon(Pen, Point[]) Рисует многоугольник, определяемый массивом структур Point. 2
DrawRectangle(Pen, Rectangle) Рисует прямоугольник, определяемый структурой Rectangle. 3
DrawRectangles(Pen, Rectangle[]) Рисует набор прямоугольников, определяемых структурами Rectangle. 2
DrawString(String, Font, Brush, PointF) Создает указываемую текстовую строку в заданном месте с помощью определяемых объектов Brush и Font. 6
Equals(Object) Определяет, равен ли заданный объект текущему объекту. (Унаследовано от Object.) 1
ExcludeClip(Rectangle) Обновляет вырезанную область данного объекта Graphics, чтобы исключить из нее часть, определяемую структурой Rectangle. 1
ExcludeClip(Region) Обновляет вырезанную область данного объекта Graphics, чтобы исключить из нее часть, определяемую структурой Region. 1
FillClosedCurve(Brush, Point[]) Заполняет внутреннюю часть замкнутой фундаментальной кривой, определяемой массивом структур Point. 6
FillEllipse(Brush, Rectangle) Заполняет внутреннюю часть эллипса, определяемого ограничивающим прямоугольником, который задан структурой Rectangle. 4
FillPath(Brush, GraphicsPath) Заполняет внутреннюю часть объекта GraphicsPath. 1
FillPie(Brush, Rectangle, Single, Single) Заполняет внутреннюю часть сектора, определяемого эллипсом, который задан структурой RectangleF, и двумя радиальными линиями. 3
FillPolygon(Brush, Point[]) Заполняет внутреннюю часть многоугольника, определяемого массивом точек, заданных структурами Point. 4
FillRectangle(Brush, Rectangle) Заполняет внутреннюю часть прямоугольника, определяемого структурой Rectangle. 4
FillRegion(Brush, Region) Заполняет внутреннюю часть объекта Region. 1
Flush() Вызывает принудительное выполнение всех отложенных графических операций и немедленно возвращается, не дожидаясь их окончания. 2
IntersectClip(Region) Обновляет вырезанную область данного объекта, включая в нее пересечение текущей вырезанной области и указанной структуры 3
ResetClip() Сбрасывает выделенную область g, делая ее бесконечной 1

Подробнее еще о двух классах.

Класс Pen

Класс Brush

Для первоначального привыкания к стилю ООП в графике рассмотрим первый пример рисования.

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