Как проще всего добавить на форму WindowsForms круг, цвет которого можно программно менять?
Нужно добавить на форму круг, цвет которого можно переключать программно (зелёный, желтый, красный). Можно сделать три pictureBox’а и из них каждый раз оставлять один видимый, но таких кружков требуется три штуки. Такое решение звучит как-то угловато. Может есть более элегантное?
Отслеживать
задан 11 авг 2015 в 11:53
InfernumDeus InfernumDeus
643 2 2 золотых знака 11 11 серебряных знаков 25 25 бронзовых знаков
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
Удобнее всего сделать повторно используемый пользовательский контрол:
using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; public sealed class CircleControl : Control < public CircleControl() < Height = Width = 100; SetStyle(ControlStyles.ResizeRedraw | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); >protected override void OnPaint(PaintEventArgs e) < base.OnPaint(e); var grfx = e.Graphics; grfx.SmoothingMode = SmoothingMode.AntiAlias; grfx.DrawEllipse(new Pen(Color), 0, 0, Width-1, Height-1); //grfx.FillEllipse(new SolidBrush(color), 0, 0, Width - 1, Height - 1); // рисует закрашенный круг >private Color color = Color.Black; public Color Color < get < return color; >set < color = value; Invalidate(); >> >
Через свойство Color можно задавать цвет окружности. При смене цвета окружность будет перерисована.
Вы можете рисовать в методе OnPaint разными способами: DrawEllipse — окружность. FillEllipse — закрашенный круг.
Добавить контрол на форму можно через дизайнер или в конструкторе:
var сircleControl = new CircleControl(); сircleControl.Color = Color.Red; // меняем цвет окружности Controls.Add(сircleControl);
Обновление
По умолчанию форма контрола будет прямоугольная и при размещении над другими контролами будут видны края. Чтобы избежать этого эффекта нужно добавить следующий код:
protected override void OnResize(EventArgs e)
Как нарисовать закрашенный круг на GLSL #version 120
Может у кого-нибудь есть вершинный и фрагментные шейдеры, которые рисуют закрашенный круг в (x, y) с радиусом r ?
В инете есть туториалы, но они для более новых шейдеров и конкретно для glsl #120 я не нашел 🙁
Буду очень признателен, если у кого-нить что-нибудь завалялось.
Заранее спасибо!

Glaciuse
03.10.15 20:40:03 MSK
Что конкретно не получается с glsl 120?
andreyu ★★★★★
( 05.10.15 09:43:16 MSK )

sadlinuxoid
anonymous
( 05.10.15 09:45:05 MSK )

Логика там одна и та же должна быть. Рисуется quad на экране. В шейдеры передаются радиус и координаты центра. Далее во фрагментном шейдере определяется дистанция от текущего пикселя до центра окружности и если она больше радиуса, то делается discard, иначе пишется цвет в gl_FragColor.
Amp ★★★
( 05.10.15 11:47:19 MSK )
Ответ на: комментарий от Amp 05.10.15 11:47:19 MSK

Все, спасибо! Все получилось и как причешу код, выложу сюда для тех, кому понадобиться в будущем.
Всем спасибо!
Glaciuse
( 05.10.15 19:34:04 MSK ) автор топика
нарисовать закрашенный круг на GLSL

Eddy_Em
anonymous
( 05.10.15 19:39:32 MSK )
Ответ на: комментарий от Amp 05.10.15 11:47:19 MSK

#pragma once #include #include #include #include #include #include using std::vector; using std::string; using std::cout; using std::endl; static const char* vertex_shared_src = "\n" "attribute vec2 tex_coords;\n" "varying vec2 _disc_tex_coords;\n" "void main()\n" "\n"; static const char* fragment_shader_src = "\n" "uniform vec4 disc_color;\n" "varying vec2 _disc_tex_coords;\n" "float disc_radius = 1.0f;\n" "\n" "void main()\n" "\n"; class Cell < public: Cell() < load_shaders(); _disc_color = glGetUniformLocation(_program, "disc_color"); >; void draw() < glClearColor(0.2, 0.2, 0.2, 1.0); glUseProgram(_program); glUniform4f(_disc_color, 0.2f, 0.9f, 0.4f, 1.0f); glBindVertexArray(_vao); glDrawArrays(GL_QUADS, 0, 4 * (GLsizei)_cells.size()); glUseProgram(0); >void add_cell(unsigned int x, unsigned int y, unsigned int r) < _CellData cd; cd.x1 = x - r; cd.y1 = y - r; cd.tex_x1 = -1.0f; cd.tex_y1 = -1.0f; cd.x2 = x - r; cd.y2 = y + r; cd.tex_x2 = -1.0f; cd.tex_y2 = 1.0f; cd.x3 = x + r; cd.y3 = y + r; cd.tex_x3 = 1.0f; cd.tex_y3 = 1.0f; cd.x4 = x + r; cd.y4 = y - r; cd.tex_x4 = 1.0f; cd.tex_y4 = -1.0f; _cells.push_back(cd); _bind_buffers(); >private: struct _CellData < GLfloat x1, y1, tex_x1, tex_y1; GLfloat x2, y2, tex_x2, tex_y2; GLfloat x3, y3, tex_x3, tex_y3; GLfloat x4, y4, tex_x4, tex_y4; >; vector _cells; GLuint _program; GLint _disc_color; GLuint _vbo, _vao; void _bind_buffers() < GLchar* pointer = 0; glGenBuffers(1, &_vbo); glGenVertexArrays(1, &_vao); glBindBuffer(GL_ARRAY_BUFFER, _vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(_CellData) * _cells.size() * sizeof(GLfloat), &_cells[0], GL_STATIC_DRAW); glBindVertexArray(_vao); glBindBuffer(GL_ARRAY_BUFFER, _vbo); // 0 - вершины glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, pointer); // 16 - размер одной записи x + y + tex_x1 + tex_y1 // 1 - кординаты текстуры glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 16, pointer + 8); // Включаем массив атрибутов для вершин и координат текстур glEnableVertexAttribArray(0); glEnableVertexAttribArrayARB(1); >void load_shaders() < auto vertex_shader_object = glCreateShader(GL_VERTEX_SHADER); auto fragment_shader_object = glCreateShader(GL_FRAGMENT_SHADER); glShaderSourceARB(vertex_shader_object, 1, &vertex_shared_src, NULL); glShaderSourceARB(fragment_shader_object, 1, &fragment_shader_src, NULL); glCompileShader(vertex_shader_object); _check_shader_compilation(vertex_shader_object, "vertex"); glCompileShader(fragment_shader_object); _check_shader_compilation(fragment_shader_object, "fragment"); _program = glCreateProgram(); glAttachShader(_program, vertex_shader_object); glAttachShader(_program, fragment_shader_object); glBindAttribLocation(_program, 0, "gl_Vertex"); glBindAttribLocation(_program, 1, "tex_coords"); glLinkProgram(_program); _check_program_link(_program); _get_active_vertex_shader_inputs(_program); >void _check_shader_compilation(GLuint shader_object, string shader_name) < GLint compiled, blen, slen; glGetObjectParameterivARB(shader_object, GL_COMPILE_STATUS, &compiled); if(!compiled) < cout 1) < GLchar* compiler_log = new GLchar[blen]; glGetInfoLogARB(shader_object, blen, &slen, compiler_log); cout exit(1); > > void _check_program_link(GLuint program) < GLint linked; GLint blen, slen; glGetProgramiv(program, GL_LINK_STATUS, &linked); if(!linked) < cout 1) < GLchar* link_log = new GLchar[blen]; glGetInfoLogARB(program, blen, &slen, link_log); cout > > void _get_active_vertex_shader_inputs(GLuint program) < char* name; GLint active_attribs, max_length; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active_attribs); glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_length); name = new char[max_length + 1]; for(unsigned int i = 0 ; i < active_attribs ; i++) < GLint size; GLenum type; glGetActiveAttrib(program, i, max_length + 1, NULL, &size, &type, name); cout delete [] name; > >;
Glaciuse
( 05.10.15 21:16:05 MSK ) автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.
Похожие темы
- Форум Описание алгоритма генерации 2d теней на GLSL (2018)
- Форум fabric.js Нарисовать сектор круга (2021)
- Форум Как нарисовать круг на полях? (2009)
- Форум glsl (2008)
- Форум Как нарисовать круг в Haskell на Gtk ? (2022)
- Форум поддержка glsl 4 (2014)
- Форум GLSL игра без текстур (2018)
- Новости Finnix 120 (2020)
- Форум Замыкая круг (2023)
- Форум Круг замкнулся (2016)
КАК рисовать в Win32 API?
Обществом преподавателей информатики замечено, что очень многие, при изучении нового языка программирования, прежде всего интересуются его графическими возможностями. Видимо, ещё с детства в нас не остыл интерес к красивым разноцветным кружочкам и овалам. Как вы и думали, API даёт в этом плане огромнейшую свободу, ибо всё, что знает Windows о рисовании, она знает от API.
Разноцветные геометрические фигуры, которые можно заливать любым цветом, эллипсы, окружности, прямоугольники, линии. Во введении я уже говорил про кисти и перья. Эта важнейшие особенности API дают нам возможность заливать фигуры не только сплошным покровом, а линии делать пунктирными и штрих-пунктирными.
С текстом мы вроде как разобрались, теперь переходим к нашим любимым графическим примитивам. Так как в этой главе мы будем изучать почти все графические функции, предлагаю сделать заготовочку, в которую можно примерять новые изученные функции.
КАК и где вставлять графические функции?
Сам текст программы ничем не отличается от предыдущих. Рассмотрим лишь сообщение WM_PAINT. Я покажу куда рисовать.
case WM_PAINT :
hdc=BeginPaint(hWnd, &ps);
//здесь можно вставить какие-нибудь функции рисования
.
//обновляем окно
ValidateRect(hWnd, NULL);
//заканчиваем рисовать
EndPaint(hWnd, &ps);
break;
Графические функции GDI:
1. Вывод точки. SetPixel устанавливает заданный цвет в точке с указанными координатами:
COLORREF SetPixel(HDC hDC, int x, int y, COLORREF crColor);
Пример:
SetPixel(hDC, 10,10, RGB(0,0,0));
Функция GetPixel соответственно возвращает цвет в заданных координатах.
COLORREF Getpixel(hDC, int x, int y);
2. Рисование линий.
BOOL LineTo(hDC, int x, int y);
Функция рисует линию от текущей позиции до места, указанного в аргументах. Чтобы изменить тип линии (толщину, стиль)- меняется тип пера. Но об этом позже.
Так как в отличие от многих других подходов, в GDI нет функции рисования линии от одного указанного места до другого, её можно создать самому. Она будет соединять линией точки с координатами: x1,y1 и x2,y2.
BOOL Line(HDC hdc, int x1, int y1, int x2, int y2)
MoveToEx(hdc, x1, y1, NULL); //сделать текущими координаты x1, y1
return LineTo(hdc, x2, y2);
>
3. Дуга
BOOL Arc(hDC, int left, int top, int right, int bottom, int x1, int y1, int x2, int y2);
Первые четыре аргумента — левый верхний и правый нижний углы прямоугольника, в который вписан эллипс. Остальные значения — координаты точек, от которых будут проведены прямые к центру эллипса. В местах пересечения первой и второй прямой с радиусом эллипса, начинается и кончается дуга.
4. Прямоугольник. По умолчанию прозрачный, а вообще, тип его заливки определяется текущей кистью. По умолчанию она тоже прозрачная.
BOOL Rectangle(hDC, int left, int top, int right, int bottom); //аргументы — это коордианты левого верхнего и правого нижнего углов
5. Закруглённый прямоугольник. Его можно использовать, как импровизированную кнопку, если не лень возиться.
BOOL RoundRect(hDC, int left, int top, int right, int bottom, int width, int height);
Первые пять параметров совпадают с параметрами предыдущей фукнции. Далее width и height задают ширину и высоту эллипса, дуги которого ограничивают прямоугольник.
6. Кисти. Самое время познакомиться с кистями, так как фигуры, которые пойдут дальше выглядят лучше закрашенными. Мы уже немного затронули эту тему во вводной части. Теперь рассмотрим как задать свой стиль кисти. Как и setfillstyle() в DOS, кисть закрашивает какую-то область в какой-то цвет. В зависимости от кисти, она может делать это в полосочку, в клеточку, по диагонали.
Есть два способа объявить кисть. Первый — задать сплошную заливку, второй — указать стиль. Для этого существуют соответственно функции: CreateSoldBrush() и CreateHatchBrush().
Пример:
HBRUSH hBrush; //создаём объект-кисть
CreateSolidBrush(RGB(255,0,67)); //задаём сплошную кисть, закрашенную цветом RGB
SelectObject(hdc, hBrush); //делаем кисть активной
А вот как объявить не сплошную кисть:
CreateHatchBrush(int fnStyle, RGB(r,g,b));
Аргумент fnStyle принимает ряд константных значений:
HS_DIAGONAL — штрихует по диагонали
HS_CROSS — клеточка
HS_DIAGCROSS — диагональная сетка
HS_FDIAGONAL — по диагонали в другую сторону
HS_HORIZONTAL — горизонтальная «тельняшка»
HS_VERTICAL — вертикальный «забор»
HBRUSH hBrush1;
CreateHatchBrush(int fnStyle, RGB(r,g,b));
SelectObject(hdc, hBrush1); //делаем кисть активной
Вот махонький пример сообщения WM_PAINT с использованием кистей.
//сообщение рисования
case WM_PAINT :
//начинаем рисовать
hdc=BeginPaint(hWnd, &ps);
HBRUSH hBrush;
hBrush=CreateHatchBrush(HS_FDIAGONAL, RGB(255,0,0));
SelectObject(hdc,hBrush);
Ellipse(hdc, 100,100,200,300); //эллипс будет заштрихован
//обновляем окно
ValidateRect(hWnd, NULL);
//заканчиваем рисовать
EndPaint(hWnd, &ps);
break;
7. Перья. Они задают стиль линий, как и setlinestyle в DOS. Линия может быть жирной и тонкой, прерывистой и штрих-пунктирной. Всё предусмотрено. Это очень удобно для создания графиков функций, когда на график накладывается сетка, рисуются оси и выводится сама функция. Вы можете сказать, что это касается только математиков! Но почти любая фирма, что бы она не производила, иногда проводит презентации. На графике можно показать рост внешнего капитала, объём продаж и многое другое.
HPEN hPen; //Объявляется кисть
CreatePen(fnPenStyle, int width, RGB(r,g,b)); //Создаётся объект
SelectObject(hdc, hPen); //Объект делается текущим
fnStyle может принимать следующие значения:
PS_SOLD — сплошная
PS_DASH — состоящая из точек
PS_DOT — состоящая из тире
PS_DASHDOT — «точка-тире»
PS_DASHDOTDOT — «тире-точка-точка-тире»
PS_NULL — невидимая
PS_INSIDEFRAME — обводка замкнутых фигур
И пример будет такой:
//сообщение рисования
case WM_PAINT :
//начинаем рисовать
hdc=BeginPaint(hWnd, &ps);
HPEN hPen1, hPen2, hPen3; //объявляем сразу три объекта-пера
hPen1=CreatePen(PS_DASHDOT, 1, RGB(0,0,255)); //создаём всё три
hPen2=CreatePen(PS_DASH, 1, RGB(255,0,255));
hPen3=CreatePen(PS_DOT, 1, RGB(0,128,256));
SelectObject(hdc, hPen1); //но в одним момент времени может быть только 1
Rectangle(hdc, 10,10,100,100); //рисуем фигуру соответствующим пером
SelectObject(hdc, hPen2); //меняем перо
Ellipse(hdc, 100,100,200,300); //рисуем другим пером
SelectObject(hdc, hPen3);
LineTo(hdc, 200,100);
//обновляем окно
ValidateRect(hWnd, NULL);
//заканчиваем рисовать
EndPaint(hWnd, &ps);
break;
Важно понять, что можно создавать хоть 10 перьев с помощью CreatePen, но применить в данный момент времени можно только 1 из них. Для этого и нужен SelectObject, чтобы окно поняло какую кисть в настоящий момент мы достаём из этюдника GDI.
6. Закрашенный прямоугольник
int FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr);
lprc — закрашиваемый прямоугольник типа RECT.
hbr — кисть
Вот пример-фрагмент WM_PAINT:
RECT r; //объявляем экзмепляр структуры RECT — координаты прямоугольника.
r.left=100; //левый верхний угол
r.top=100;
r.right=200; //правый нижний
r.right=300;
А вот и первый пример программы подоспел! Нарисуем что-то очень красивое — то, что мы уже умеем.
В этом примере мы освежим методы работы со шрифтами, поменяв стандартный системный шрифт на свой, затем нарисуем прямоугольник, заполненный красным цветом, зелёный эллипс и прямоугольник с закруглёнными краями жёлтого цвета. Естественно, что для того, чтобы их заполнить нам понадобятся кисти, а для синей рамки на жёлтом прямоугольнике понадобятся перья. Всё, что есть в этой программе вы уже умеете. Мы просто закрепляем теорию на практике.
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
char szProgName[]=»Имя программы»;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
HWND hWnd;
MSG lpMsg;
WNDCLASS w;
w.lpszClassName=szProgName; //имя программы — объявлено выше
w.hInstance=hInstance; //идентификатор текущего приложения
w.lpfnWndProc=WndProc; //указатель на функцию окна
w.hCursor=LoadCursor(NULL, IDC_ARROW); //загружаем курсор
w.hIcon=0;
w.lpszMenuName=0;
w.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //цвет фона окна
w.style=CS_HREDRAW|CS_VREDRAW;
w.cbClsExtra=0;
w.cbWndExtra=0;
//Если не удалось зарегистрировать класс окна — выходим
if(!RegisterClass(&w))
return 0;
//Создадим окно в памяти, заполнив аргументы CreateWindow
hWnd=CreateWindow(szProgName, //Имя программы
«Грфические возможности Win32 API», //Заголовок окна
WS_OVERLAPPEDWINDOW, //Стиль окна — перекрывающееся
100, //положение окна на экране по х
100, //положение по у
500, //ширина
400, //высота
(HWND)NULL, //идентификатор родительского окна
(HMENU)NULL, //идентификатор меню
(HINSTANCE)hInstance, //идентификатор экземпляра программы
(HINSTANCE)NULL); //отсутствие дополнительных параметров
//Выводим окно из памяти на экран
ShowWindow(hWnd, nCmdShow);
//Обновим содержимое окна
UpdateWindow(hWnd);
//Цикл обработки сообщений
//Функция окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT messg,
WPARAM wParam, LPARAM lParam)
HDC hdc; //создаём контекст устройства
PAINTSTRUCT ps; //создаём экземпляр структуры графического вывода
LOGFONT lf;
HFONT hFont;
RECT r;
HBRUSH hBrush;
HPEN hPen;
//Цикл обработки сообщений
switch(messg)
//сообщение рисования
case WM_PAINT :
hdc=BeginPaint(hWnd, &ps);
//Создаём свой шрифт
strcpy(lf.lfFaceName,»Times New Roman»); //копируем в строку название шрифта
lf.lfHeight=20;
lf.lfItalic=1;
lf.lfStrikeOut=0;
lf.lfUnderline=0;
lf.lfWidth=10;
lf.lfWeight=40;
lf.lfCharSet=DEFAULT_CHARSET; //значение по умолчанию
lf.lfPitchAndFamily=DEFAULT_PITCH; //значения по умолчанию
lf.lfEscapement=0;
hFont = CreateFontIndirect(&lf);
SelectObject(hdc, hFont);
SetTextColor(hdc, RGB(0,0,255));
TextOut(hdc, 80,40, «Красота спасёт мир!!», 20);
//рисуем зелёный эллипс
hBrush=CreateSolidBrush(RGB(10,200,100));
SelectObject(hdc, hBrush);
Ellipse(hdc, 20,100,200,200);
//рисуем закруглённый прямоугольник
hBrush=CreateSolidBrush(RGB(250,200,100));
SelectObject(hdc, hBrush);
hPen=CreatePen(2,2,RGB(0,0,255));
SelectObject(hdc, hPen);
RoundRect(hdc, 20, 250, 250, 350, 15, 15);
ValidateRect(hWnd, NULL);
EndPaint(hWnd, &ps);
break;
//сообщение выхода — разрушение окна
case WM_DESTROY:
PostQuitMessage(0); //Посылаем сообщение выхода с кодом 0 — нормальное завершение
DeleteObject(hPen);
DeleteObject(hBrush);
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam)); //освобождаем очередь приложения от нераспознаных
>
return 0;
>
Правда, красиво? Наконец-то из этой API нам удалось выжать что-то стоящее. Продолжаем обзор.
7. Прямоугольная рамка — как видите, существует немало функций для работы с прямоугольниками:
int FrameRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr);
Применение аналогично предыдущей.
8. Инверсия значения цветов точек в заданной области
BOOL InvertRect(HDC hDC, CONST RECT *lprc);
9. Эллипс
BOOL Ellipse(HDC hdc, int x1, int y1, int x2, int y2);
координаты — это прямоугольник, в который вписывается эллипс
10. Хорда (сегмент эллипса) — параметры аналогичны Arc
BOOL Chord(HDC hDC, int left, int top, int right, int bottom, int x1, int y1, int x2, int y2); Функция соединяет хордой точки начала и конца дуги эллипса и закрашивает выделенный сегмент текущей кистью.
11. Сектор эллипса — аналог pieslice в DOS.
BOOL Pie(HDC hDC, int left, int top, int right, int bottom, int x1, int y1, int x2, int y2);
12. Многоугольник . Есть много функций рисования мноугольников. Мы рассмотрим две. Рисования от вершины к вершине и рисования отрезками:
PolyDraw оперирует вершинами:
POINT poly[8];
BYTE polytype[8];
poly[0].x=375; //координаты первой вершины
poly[0].y=375;
. //и так заполняем координаты всех восьми вершин
poly[7].x=400; //координаты восьмой вершины
poly[7].y =400;
. //другой массив содержит режим рисования
PolyDraw(hdc, poly, polytype, 8); //рисование многоугольника
Функция Polyline рисует набором отрезков:
POINT poly[4];
poly[0].x =10;
poly[0].y =30;
poly[1].x =30;
poly[1].y =30;
poly[2].x =30;
poly[2].y =60;
Polyline(hdc, poly , 4);
КАК вывести график функции?
Всё это были фрагменты графических функций. Теперь рассмотрим настоящий полноценный пример. Это будет простейший график функции.

#define pi 3.14
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//Процедура рисования линии
BOOL Line(HDC hdc, int x1, int y1, int x2, int y2);
char szProgName[]=»Имя программы»;
int i, xView, yView;
double y;
char Buf[2];
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
HWND hWnd;
MSG lpMsg;
WNDCLASS w;
w.lpszClassName=szProgName;
w.hInstance=hInstance;
w.lpfnWndProc=WndProc;
w.hCursor=LoadCursor(NULL, IDC_ARROW);
w.hIcon=0;
w.lpszMenuName=0;
w.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
w.style=CS_HREDRAW|CS_VREDRAW;
w.cbClsExtra=0;
w.cbWndExtra=0;
//Если не удалось зарегистрировать класс окна — выходим
if(!RegisterClass(&w))
return 0;
//Создадим окно в памяти, заполнив аргументы CreateWindow
hWnd=CreateWindow(szProgName,
«График функции»,
WS_OVERLAPPEDWINDOW,
100,
100,
500,
400,
(HWND)NULL,
(HMENU)NULL,
(HINSTANCE)hInstance,
(HINSTANCE)NULL);
//Выводим окно из памяти на экран
ShowWindow(hWnd, nCmdShow);
//Обновим содержимое окна
UpdateWindow(hWnd);
//Цикл обработки сообщений
while(GetMessage(&lpMsg, NULL, 0, 0)) < //Получаем сообщение из очереди
TranslateMessage(&lpMsg); //Преобразует сообщения клавиш в символы
DispatchMessage(&lpMsg); //Передаёт сообщение соответствующей функции окна
>
return(lpMsg.wParam);
>
//Функция окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT messg,
WPARAM wParam, LPARAM lParam)
HDC hdc; //создаём контекст устройства
PAINTSTRUCT ps; //создаём экземпляр структуры графического вывода
HPEN hPen; //создаём перо
//Цикл обработки сообщений
switch(messg)
case WM_SIZE:
xView=LOWORD(lParam);
yView=HIWORD(lParam);
//сообщение рисования
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
SetMapMode(hdc, MM_ISOTROPIC); //логические единицы отображаем, как физические
SetWindowExtEx(hdc, 500,500, NULL); //Длина осей
SetViewportExtEx(hdc, xView, -yView, NULL); //Определяем облась вывода
SetViewportOrgEx(hdc, xView/6, yView/2, NULL); //Начало координат
//Рисуем оси координат
Line(hdc,0, 220,0,-220);//ось У
Line(hdc, -100,0,500,0);//ось Х
MoveToEx(hdc, 0,0,NULL); //перемещаемся в начало координат
//Создание красного пера
hPen=CreatePen(1,4,RGB(255,25,0));
SelectObject(hdc, hPen);
//синусоида
for(i=0; i y=180.0*(exp(-i*0.01))*sin(pi*i*(200.0/400.0)/180.0);
LineTo(hdc, i, (int)y);
>
//Делаем перо снова чёрным
hPen=CreatePen(1,1,RGB(0,0,0));
SelectObject(hdc, hPen);
//Наносим деления
for(i=-100; i Line(hdc, i, 3,i,-3);
Line(hdc, -3, i,3,i);
itoa(i, Buf, 10);
TextOut(hdc, i-5, -5, Buf , strlen(Buf));
TextOut(hdc, -5, i, Buf , strlen(Buf));
>
ValidateRect(hWnd, NULL); //Обновляем экран
EndPaint(hWnd, &ps);
break;
//сообщение выхода — разрушение окна
case WM_DESTROY:
DeleteObject(hPen); //не забываем уничтожать перья
PostQuitMessage(0); //Посылаем сообщение выхода с кодом 0 — нормальное завершение
break;
default:
return(DefWindowProc(hWnd, messg, wParam, lParam)); //освобождаем очередь приложения от нераспознаных
>
return 0;
>
//Функция рисования линии
BOOL Line(HDC hdc, int x1, int y1, int x2, int y2)
MoveToEx(hdc, x1, y1, NULL); //сделать текущими координаты x1, y1
return LineTo(hdc, x2, y2); //нарисовать линию
>
Поскольку в данной программе большое внимание уделяется всяким украшательствам: делениям и надписям, обращу ваше внимание на главное — создавать графики совсем не сложно. И вот как это делается:
Мы знаем, что отсчёт координат задаётся от левого верхнего угла вниз и вправо. Как известно, значения на графике изменяются вверх и вправо. Вряд ли мы сможем объяснить пользователю, почему график «растёт вниз». На счастье, в Windows предусмотрена функция, преобразует координаты в нужном нам направлении.
Первым делом, мы узнаём размер окна. Для этого используется сообщение WM_SIZE. Параметр lParam содержит по этому сообщению размеры экрана. Переменные xView и yView будут содержать эти значения:
case WM_SIZE:
xView=LOWORD(lParam);
yView=HIWORD(lParam);
break;
Затем определим область вывода. Мы хотим, чтобы при увеличении координаты по у график рос вверх, а не вниз.
SetViewportExtEx(hdc, xView, -yView, NULL);
Обратите внимание: yView указан со знаком —. Значит все координаты по у будут расти в обратную сторону — вверх.
Центр графика обычно где-нибудь посередине экрана. Координаты же увеличиваются из левого верхнего угла. Перенесём центр графика:
SetViewportOrgEx(hdc, xView/6, yView/2, NULL);
В точке, равной 1/6 максимального значения по х и 1/2 значения по этого значения по у будет центр.
Можно также задать длину осей — 500 и 500. Для этого применяется следующая функция:
SetWindowExtEx(hdc, 500,500, NULL);
Как вы уже знаете, окно имеет логические координаты и физические. Для того, чтобы логические координаты совпадали с физическими, а также, чтобы единица отложенная по х была равно единице отложенной по у, задаётся режим MM_ISOTROPIC. Его задаёт функция:
SetMapMode(hdc, MM_ISOTROPIC);
Вот, как будет выглядеть эта конструкция вцелом:
SetMapMode(hdc, MM_ISOTROPIC); //логические единицы отображаем, как физические
SetWindowExtEx(hdc, 500,500, NULL); //Длина осей
SetViewportExtEx(hdc, xView, -yView, NULL); //Определяем облась вывода
SetViewportOrgEx(hdc, xView/6, yView/2, NULL); //Начало координат
Дальше надо нарисовать оси. К нашей радости, точка 0, 0 сместилась на середину экрана, в левую его часть. Исходя из этого, рисуем оси, применяя самописную функцию Line:
Line(hdc,0, 220,0,-220);//ось У
Line(hdc, -100,0,500,0);//ось Х
MoveToEx(hdc, 0,0,NULL);
В выводе графика нет ничего примечательного. Переменная i меняется от 0 до 450. Подставляя i в формулу, мы получаем зависимость y от i. Рисуем линию до этой точки. Небольшие отрезки сольются в непрерывную линию.
Иногда, требуется хранить значения физических величин несколько дней. Тогда график выполняется с длиннющей горизонтальной полосой прокрутки. При желании, можно вернуться и посмотреть были ли изменения, и если да, то какие.
Другой выход из положения — вести историю, записывая её в файл, а на экран выводя только показания последних пяти минут.
Задания:
1. Добавьте в приложения с графиком стрелочки и подписи к осям.
2. Нарисуйте снеговика известными средствами GDI. Напомню, что снеговик состоит из трёх непрозрачных эллипсов грязно-белого цвета, на груди у него должны быть пуговки, в руке — метла, а на голове — ведро.
3. Нарисуйте красивый паровозик, клубы из трубы которого будут выводиться в цикле в виде синих эллипсов
4. Нарисуйте кораблик с жёлтой палубой и красными бортами, используя Polyline или Polydraw. Кораблик покоится на синих волнах, которые нарисованы дугами разной толщины. Попробуйте вывести дуги в цикле.
5. Нарисуйте с помощью одних только линий домик с забором
Как нарисовать круг (PhotoShop)
Нарисовать круг в фотошопе можно по-разному. Можно нарисовать круг с рамкой, можно закрашенный круг. Для начала выбираем инструмент эллипс (Ellipse Tool) .
Ellipse Tool (Инструмент Эллипс)
- Выбираем фигуры — горячая клавиша U , или сразу правой кнопкой мыши кликаем по иконке и выбираем Ellipse Tool (Инструмент Эллипс) ;
- Выбираем Ellipse Tool (Инструмент Эллипс) .
Закрашенный круг
- Устанавливаем Fill Pixels (Закрашивать пиксели);
- Выбираем цвет заливки;
- Рисуем круг с зажатой клавишей Шифт (Shift)
Круг с рамкой
Круг следует рисовать на новом пустом слое, без какой-либо заливки. Создать новый слой можно одновременным нажатием клавиш Alt + Ctrl + Shift + N .
- Устанавливаем Paths (по-русски пути);
- Рисуем круг с зажатым шифтом;
Преобразуем векторный круг в выделение (Select), нажатием клавиш Ctrl + Enter .
Закрашиваем выделение (в данном случае белым цветом).
Alt + ← BackSpace — первый выбранный цвет.
Ctrl + ← BackSpace — второй выбранный цвет.
Нажимаем правой кнопкой мыши по слою с кругом и выбираем Blending Options (Параметры наложения) .
В появившемся окне устанавливаем толщину рамки в пикселях и цвет рамки. Можно поэкспериментировать с другими опциями.
В результате получаем круг с красной рамкой толщиной в 2 пикселя.
✖ ❤ Мне помогла статья 3 оценки
34647 просмотров нет комментариев Артём Фёдоров 08 июня 2011
Категории
Читайте также
- Как нарисовать параллелограмм (PhotoShop)
- Как нарисовать квадрат (PhotoShop)
- Как нарисовать треугольник (PhotoShop)
- Текст по кругу (PhotoShop)
- Как нарисовать линию (PhotoShop)
- Удалить прыщик (PhotoShop)
- PhotoShop — как обрезать изображение
- Как создать новый слой (PhotoShop)