153 / 136 / 45 Регистрация: 15.02.2010 Сообщений: 748 |
|
1 |
|
Графика в консоли16.12.2012, 09:09. Показов 77936. Ответов 36
Существует ли возможность реализовать графику в консольных приложениях С++ с использованием стандартных библиотек. (без создния собственных библиотек, классов и прочее)?
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
16.12.2012, 09:09 |
Ответы с готовыми решениями: Графика в консоли Графика в консоли Построение графика функции в консоли Графика в консоли 36 |
CEO SOVAZ Corp. 386 / 232 / 51 Регистрация: 17.12.2011 Сообщений: 822 Записей в блоге: 1 |
|
16.12.2012, 09:53 |
2 |
В консоли вроде нельзя. В Qt SDK есть встроенная библиотека QPainter. Там и рисуй (только не в консоли)
0 |
Croessmah Don’t worry, be happy 17781 / 10545 / 2035 Регистрация: 27.09.2012 Сообщений: 26,514 Записей в блоге: 1 |
||||
16.12.2012, 10:27 |
3 |
|||
Сообщение было отмечено как решение Решение
8 |
153 / 136 / 45 Регистрация: 15.02.2010 Сообщений: 748 |
|
16.12.2012, 11:11 [ТС] |
4 |
Спасибо, Croessmah.
0 |
Don’t worry, be happy 17781 / 10545 / 2035 Регистрация: 27.09.2012 Сообщений: 26,514 Записей в блоге: 1 |
|
16.12.2012, 11:26 |
5 |
«создание рисунков циклическим повторением графических примитивов» покажите им квадрат или треугольник(ковер, салфетку) Серпинского. Их можно достаточно ясно описать без использования программирования вовсе
0 |
153 / 136 / 45 Регистрация: 15.02.2010 Сообщений: 748 |
|
16.12.2012, 11:32 [ТС] |
6 |
можно достаточно ясно описать без использования программирования вовсе Ну, смысл как раз в программировании и заключается. Циклы + графика: интересней для изучения, чем на одних вычислениях циклы «оттачивать»…
1 |
3645 / 1377 / 243 Регистрация: 16.04.2009 Сообщений: 4,526 |
|
16.12.2012, 12:39 |
7 |
LVV, я бы OpenGL юзал.
3 |
424 / 389 / 113 Регистрация: 21.09.2012 Сообщений: 913 |
|
16.12.2012, 12:54 |
8 |
Croessmah, А можно сделать так чтобы линия не пропадала когда консоль сворачиваешь? Чтобы перерисовка была
0 |
3645 / 1377 / 243 Регистрация: 16.04.2009 Сообщений: 4,526 |
|
16.12.2012, 13:13 |
9 |
v.a.l.i.d, В обработчике событий добавить в WM_PAINT перерисовку.
0 |
424 / 389 / 113 Регистрация: 21.09.2012 Сообщений: 913 |
|
16.12.2012, 14:23 |
10 |
В обработчике событий добавить в WM_PAINT перерисовку. А как это сделать?
0 |
daslex 1369 / 592 / 199 Регистрация: 02.08.2011 Сообщений: 2,882 |
||||||||
16.12.2012, 19:08 |
11 |
|||||||
Иногда нужно
иначе может возникнуть ошибка error C3861: ‘GetConsoleWindow’: identifier not found
0 |
Don’t worry, be happy 17781 / 10545 / 2035 Регистрация: 27.09.2012 Сообщений: 26,514 Записей в блоге: 1 |
|
16.12.2012, 20:10 |
12 |
Иногда нужно Специально для Вас: MSDN. Изменение WINVER и _WIN32_WINNT
1 |
1369 / 592 / 199 Регистрация: 02.08.2011 Сообщений: 2,882 |
|
16.12.2012, 20:42 |
13 |
Специально для Вас Не по теме: ну не только для меня. будут люди, которые с этим столкнутся еще.
0 |
skynet120 0 / 0 / 0 Регистрация: 22.01.2013 Сообщений: 76 |
||||
01.09.2013, 15:14 |
14 |
|||
кто может рассказать как оно работает, буду очень благодарен
0 |
Croessmah Don’t worry, be happy 17781 / 10545 / 2035 Регистрация: 27.09.2012 Сообщений: 26,514 Записей в блоге: 1 |
||||
01.09.2013, 15:18 |
15 |
|||
Если просто
2 |
0 / 0 / 0 Регистрация: 22.01.2013 Сообщений: 76 |
|
01.09.2013, 15:27 |
16 |
можно ли где почитать про это все интересует:
0 |
Don’t worry, be happy 17781 / 10545 / 2035 Регистрация: 27.09.2012 Сообщений: 26,514 Записей в блоге: 1 |
|
01.09.2013, 15:31 |
17 |
можно ли где почитать про это все MSDN, книги и статьи по WinAPI Добавлено через 1 минуту
какие параметры за что отвечают Смотря параметры чего.
как нарисовать горизонтальную линию координаты поменять
можно ли менять толщину линии создать перо с нужной толщиной
1 |
Модератор 8759 / 6549 / 887 Регистрация: 14.02.2011 Сообщений: 22,971 |
|
01.09.2013, 15:32 |
18 |
Существует ли возможность реализовать графику в консольных приложениях С++ в общих случаях нельзя
#include <windows.h> и если развернуть на весь экран ctrl+Enter то не во всех виндах работать будет
0 |
0 / 0 / 0 Регистрация: 22.01.2013 Сообщений: 76 |
|
01.09.2013, 16:11 |
19 |
создать перо с нужной толщиной можете подсказать как это сделать
MSDN, книги и статьи по WinAPI можете кинуть ссылку на страницу MSDN где описываться тот код что Вы привели
0 |
567 / 198 / 70 Регистрация: 25.05.2012 Сообщений: 816 |
|
01.09.2013, 18:27 |
20 |
v.a.l.i.d, В обработчике событий добавить в WM_PAINT перерисовку. Для консоли этого сделать не получится.
0 |
IT_Exp Эксперт 87844 / 49110 / 22898 Регистрация: 17.06.2006 Сообщений: 92,604 |
01.09.2013, 18:27 |
20 |
I have drawn the straight line using windows.h in code::blocks. I can’t explain it in details, but I can provide you a code and procedure to compile it in code::blocks.
- go to setting menu and select compiler and debugger.
- Click on linker tab and add a link library libgdi32.a which is at C:Program FilesCodeBlocksMinGWlib directory.
Now compile this program
#include <windows.h>
#include <cmath>
#define ROUND(a) ((int) (a + 0.5))
/* set window handle */
static HWND sHwnd;
static COLORREF redColor=RGB(255,0,0);
static COLORREF blueColor=RGB(0,0,255);
static COLORREF greenColor=RGB(0,255,0);
void SetWindowHandle(HWND hwnd){
sHwnd=hwnd;
}
/* SetPixel */
void setPixel(int x,int y,COLORREF& color=redColor){
if(sHwnd==NULL){
MessageBox(NULL,"sHwnd was not initialized !","Error",MB_OK|MB_ICONERROR);
exit(0);
}
HDC hdc=GetDC(sHwnd);
SetPixel(hdc,x,y,color);
ReleaseDC(sHwnd,hdc);
return;
// NEVERREACH //
}
void drawLineDDA(int xa, int ya, int xb, int yb){
int dx = xb - xa, dy = yb - ya, steps, k;
float xIncrement, yIncrement, x = xa, y = ya;
if(abs(dx) > abs(dy)) steps = abs(dx);
else steps = abs(dy);
xIncrement = dx / (float) steps;
yIncrement = dy / (float) steps;
setPixel(ROUND(x), ROUND(y));
for(int k = 0; k < steps; k++){
x += xIncrement;
y += yIncrement;
setPixel(x, y);
}
}
/* Window Procedure WndProc */
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
switch(message){
case WM_PAINT:
SetWindowHandle(hwnd);
drawLineDDA(10, 20, 250, 300);
break;
case WM_CLOSE: // FAIL THROUGH to call DefWindowProc
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break; // FAIL to call DefWindowProc //
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow){
static TCHAR szAppName[] = TEXT("Straight Line");
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW|CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
// Register the window //
if(!RegisterClass(&wndclass)){
MessageBox(NULL,"Registering the class failled","Error",MB_OK|MB_ICONERROR);
exit(0);
}
// CreateWindow //
HWND hwnd=CreateWindow(szAppName,"DDA - Programming Techniques",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if(!hwnd){
MessageBox(NULL,"Window Creation Failed!","Error",MB_OK);
exit(0);
}
// ShowWindow and UpdateWindow //
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
// Message Loop //
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* return no error to the operating system */
return 0;
}
In this program I have used DDA line drawing algorithm. Pixel drawing tasks is done by setPixel(ROUND(x), ROUND(y)) function.
This is windows programing which you can learn details here
Для рисования графических примитивов в оконных приложениях используются 4 основных типа объектов:
- точка (Pixel);
- перо (Pen);
- кисть (Brush);
- фон (Background).
Точка
Цвет точки задается с помощью функции
COLORREF SetPixel(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int X, // x-координата точки
_In_ int Y, // y-координата точки
_In_ COLORREF crColor ); // цвет точки
В случае удачного завершения возвращаемое значение функции дублирует цвет точки, в случае ошибки возвращает -1.
Цвет точки представляет собой 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 могут быть заданы согласно таблице
При успешном завершении функция возвращает дескриптор пера, в случае неудачи — константу NULL.
Кисть
Кисть используется для закрашивания замкнутых объектов. Цвет кисти задается с помощью функции
HBRUSH CreateSolidBrush(
_In_ COLORREF crColor ); // цвет кисти
При успешном завершении функция возвращает дескриптор кисти, в случае неудачи — константу NULL.
Эта же функция используется для задания цвета фона.
Можно заранее создать несколько кистей и перьев, а затем выбирать нужные с помощью функции
HGDIOBJ SelectObject(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ HGDIOBJ hgdiobj ); // дескриптор объекта
Рисование графических примитивов
Перемещение в указанную точку осуществляется функцией:
BOOL MoveToEx(
_In_ HDC hdc, // дескриптор контекста устройства
_In_ int X, // координата x точки
_In_ int Y, // координата y точки
_Out_ LPPOINT lpPoint ); // указатель на структуру POINT
Координаты точки x и у определяются в пикселях относительно левого верхнего угла.
В случае успешного выполнения возвращает ненулевое значение.
Структура POINT имеет вид
typedef struct tagPOINT {
LONG x;
LONG y; } POINT, *PPOINT;
Рисование отрезков осуществляется функцией:
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.
Использование графических функций
Для перерисовки окна, в котором будут отображаться графические объекты, будем использовать обработку сообщения WM_PAINT.
Обработка сообщения WM_PAINT почти всегда начинается с вызова функции:
HDC BeginPaint(
_In_ HWND hwnd,
_Out_ LPPAINTSTRUCT lpPaint );
При обработке вызова BeginPaint(), Windows обновляет фон рабочей области с помощью кисти, заданной в поле hbrBackground структуры WNDCLASS, описанной здесь. Вызов BeginPaint() делает всю рабочую область действительной (не требующей перерисовки) и возвращает описатель контекста устройства. Контекст устройства описывает физическое устройство вывода информации (например, экран) и его драйвер. Описатель контекста устройства необходим для вывода в рабочую область окна текста и графики.
Аргументы функции:
- hwnd – дескриптор окна;
- lpPaint – указатель на структуру PAINTSTRUCT.
Структура PAINTSTRUCT имеет вид
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32]; } PAINTSTRUCT, *PPAINTSTRUCT;
Члены структуры:
- hdc – дескриптор контекста устройства.
- fErase – ненулевое значение стирает фон.
- rcPaint – структура RECT, определяющая верхний левый и нижний правый углы рабочей области.
typedef struct _RECT {
LONG left; LONG top;
LONG right; LONG bottom; } RECT, *PRECT; - fRestore, fIncUpdate, rgbReserved – зарезервировано, используется системой.
Обработка сообщения WM_PAINT почти всегда заканчивается вызовом функции:
BOOL EndPaint(
_In_ HWND hWnd,
_In_ const PAINTSTRUCT *lpPaint );
Функция EndPaint() освобождает описатель контекста устройства, после чего его значение нельзя использовать. Возвращает всегда ненулевое значение.
Получение дескриптора контекста устройства осуществляется вызовом функции:
HDC GetDC(_In_ HWND hWnd);
hWnd – дескриптор окна, для которого используется контекст устройства.
Возвращаемое значение – дескриптор контекста устройства.
Функция
int ReleaseDC(
_In_ HWND hWnd,
_In_ HDC hDC );
освобождает контекст устройства hDC для данного окна hWnd, после чего значение контекста устройства нельзя использовать. Возвращает всегда ненулевое значение.
Пример График функции y=sin(x).
Назад: Создание Windows-приложений
I have drawn the straight line using windows.h in code::blocks. I can’t explain it in details, but I can provide you a code and procedure to compile it in code::blocks.
- go to setting menu and select compiler and debugger.
- Click on linker tab and add a link library libgdi32.a which is at C:Program FilesCodeBlocksMinGWlib directory.
Now compile this program
#include <windows.h>
#include <cmath>
#define ROUND(a) ((int) (a + 0.5))
/* set window handle */
static HWND sHwnd;
static COLORREF redColor=RGB(255,0,0);
static COLORREF blueColor=RGB(0,0,255);
static COLORREF greenColor=RGB(0,255,0);
void SetWindowHandle(HWND hwnd){
sHwnd=hwnd;
}
/* SetPixel */
void setPixel(int x,int y,COLORREF& color=redColor){
if(sHwnd==NULL){
MessageBox(NULL,"sHwnd was not initialized !","Error",MB_OK|MB_ICONERROR);
exit(0);
}
HDC hdc=GetDC(sHwnd);
SetPixel(hdc,x,y,color);
ReleaseDC(sHwnd,hdc);
return;
// NEVERREACH //
}
void drawLineDDA(int xa, int ya, int xb, int yb){
int dx = xb - xa, dy = yb - ya, steps, k;
float xIncrement, yIncrement, x = xa, y = ya;
if(abs(dx) > abs(dy)) steps = abs(dx);
else steps = abs(dy);
xIncrement = dx / (float) steps;
yIncrement = dy / (float) steps;
setPixel(ROUND(x), ROUND(y));
for(int k = 0; k < steps; k++){
x += xIncrement;
y += yIncrement;
setPixel(x, y);
}
}
/* Window Procedure WndProc */
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
switch(message){
case WM_PAINT:
SetWindowHandle(hwnd);
drawLineDDA(10, 20, 250, 300);
break;
case WM_CLOSE: // FAIL THROUGH to call DefWindowProc
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break; // FAIL to call DefWindowProc //
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow){
static TCHAR szAppName[] = TEXT("Straight Line");
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW|CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
// Register the window //
if(!RegisterClass(&wndclass)){
MessageBox(NULL,"Registering the class failled","Error",MB_OK|MB_ICONERROR);
exit(0);
}
// CreateWindow //
HWND hwnd=CreateWindow(szAppName,"DDA - Programming Techniques",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if(!hwnd){
MessageBox(NULL,"Window Creation Failed!","Error",MB_OK);
exit(0);
}
// ShowWindow and UpdateWindow //
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
// Message Loop //
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* return no error to the operating system */
return 0;
}
In this program I have used DDA line drawing algorithm. Pixel drawing tasks is done by setPixel(ROUND(x), ROUND(y)) function.
This is windows programing which you can learn details here
I have drawn the straight line using windows.h in code::blocks. I can’t explain it in details, but I can provide you a code and procedure to compile it in code::blocks.
- go to setting menu and select compiler and debugger.
- Click on linker tab and add a link library libgdi32.a which is at C:Program FilesCodeBlocksMinGWlib directory.
Now compile this program
#include <windows.h>
#include <cmath>
#define ROUND(a) ((int) (a + 0.5))
/* set window handle */
static HWND sHwnd;
static COLORREF redColor=RGB(255,0,0);
static COLORREF blueColor=RGB(0,0,255);
static COLORREF greenColor=RGB(0,255,0);
void SetWindowHandle(HWND hwnd){
sHwnd=hwnd;
}
/* SetPixel */
void setPixel(int x,int y,COLORREF& color=redColor){
if(sHwnd==NULL){
MessageBox(NULL,"sHwnd was not initialized !","Error",MB_OK|MB_ICONERROR);
exit(0);
}
HDC hdc=GetDC(sHwnd);
SetPixel(hdc,x,y,color);
ReleaseDC(sHwnd,hdc);
return;
// NEVERREACH //
}
void drawLineDDA(int xa, int ya, int xb, int yb){
int dx = xb - xa, dy = yb - ya, steps, k;
float xIncrement, yIncrement, x = xa, y = ya;
if(abs(dx) > abs(dy)) steps = abs(dx);
else steps = abs(dy);
xIncrement = dx / (float) steps;
yIncrement = dy / (float) steps;
setPixel(ROUND(x), ROUND(y));
for(int k = 0; k < steps; k++){
x += xIncrement;
y += yIncrement;
setPixel(x, y);
}
}
/* Window Procedure WndProc */
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
switch(message){
case WM_PAINT:
SetWindowHandle(hwnd);
drawLineDDA(10, 20, 250, 300);
break;
case WM_CLOSE: // FAIL THROUGH to call DefWindowProc
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break; // FAIL to call DefWindowProc //
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow){
static TCHAR szAppName[] = TEXT("Straight Line");
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW|CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
// Register the window //
if(!RegisterClass(&wndclass)){
MessageBox(NULL,"Registering the class failled","Error",MB_OK|MB_ICONERROR);
exit(0);
}
// CreateWindow //
HWND hwnd=CreateWindow(szAppName,"DDA - Programming Techniques",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if(!hwnd){
MessageBox(NULL,"Window Creation Failed!","Error",MB_OK);
exit(0);
}
// ShowWindow and UpdateWindow //
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
// Message Loop //
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* return no error to the operating system */
return 0;
}
In this program I have used DDA line drawing algorithm. Pixel drawing tasks is done by setPixel(ROUND(x), ROUND(y)) function.
This is windows programing which you can learn details here
-
iamlamer
New Member
- Публикаций:
-
0
- Регистрация:
- 20 июн 2005
- Сообщения:
- 273
- Адрес:
- Russia
В http://www.firststeps.ru/mfc/winapi/r.php?6 написано, что сабж возможен, а нифига не рисует.
-
// Ищем консольное окошко с именем GRAFCON
-
if (v.dwPlatformId==VER_PLATFORM_WIN32_NT)
-
hwnd=FindWindow(«ConsoleWindowClass»,»C:grafcon.exe»);
-
hwnd=FindWindow(«tty»,»GRAFCON»);
-
if (!hwnd) printf(«nWindow not found %u», GetLastError());
-
// По хэндлу получаем контекст
-
if (!hdc) printf(«nGet context error %u», GetLastError());
-
// Рисуем серенький квадратик
-
cr1=SetPixel(hdc, x, y, RGB(128, 128, 128) );
-
cr2=SetPixel(hdc, 150-x, y, RGB(128, 128, 128) );
-
if ((cr1==-1)||(cr2==-1)) { printf(«nSetPixel error %u», GetLastError()); goto ex; }
В Win98 выдает странную ошибку «SetPixel error 0» и вообще ничего не рисует.
В Win2K не находит окошка, а квадратик все-таки рисует, но на раб. столе.Ни се во ни па ни маю.
Где я накосячил?
Или пните туда, где эта тема обсуждалась (что-то на васме не нашел). -
redsh
New Member
- Публикаций:
-
0
- Регистрация:
- 19 июл 2007
- Сообщения:
- 20
Консоль поддерживается на уровне ядра и не имеет отношения к GDI, поэтому рисовать в ней не получится (также, как создавать контроллы).
-
Консоль ядром не поддерживается! Консоль — обычное окно с обычными свойствами, просто принадлежит csrss.
GetWindowDC используй, когда-то давно я это пробовал. -
roman_pro
New Member
- Публикаций:
-
0
- Регистрация:
- 9 фев 2007
- Сообщения:
- 291
Ничего сложного, вот код, всё работает:
-
TCHAR Str[]=_T(«TestString»);
-
TCHAR UniqueTitle[]=_T(«some_unique_value»);
-
TCHAR OldTitle[MAX_PATH]={0};
-
GetConsoleTitle(OldTitle, MAX_PATH);
-
SetConsoleTitle(UniqueTitle);
-
HWND hConsWnd=FindWindow(NULL, UniqueTitle);
-
SetConsoleTitle(OldTitle);
-
SetTextColor(hDC, RGB(255,0,0));
-
TextOut(hDC, 0, 0, Str, lstrlen(Str));
-
MoveToEx(hDC, 0,0, NULL);
-
ReleaseDC(hConsWnd, hDC);
-
MessageBox(0,_T(«End»),0,0);
-
iamlamer
New Member
- Публикаций:
-
0
- Регистрация:
- 20 июн 2005
- Сообщения:
- 273
- Адрес:
- Russia
Ура! Спасибо roman_pro !
Вот такой вариант частично заработал:
-
// Принудительно называем окно консоли «grafcon»
-
SetConsoleTitle(«grafcon»);
-
// Ищем консольное окошко с именем grafcon
-
v.dwOSVersionInfoSize = sizeof(v);
-
if (v.dwPlatformId==VER_PLATFORM_WIN32_NT)
-
hwnd=FindWindow(«ConsoleWindowClass»,»grafcon»);
-
hwnd=FindWindow(«tty»,»grafcon»);
-
// По хэндлу получаем контекст
-
// Рисуем серенький кводратег
-
cr1=SetPixel(hdc, x, y, RGB(128, 128, 128) );
-
cr2=SetPixel(hdc, x, y, RGB(128, 128, 128) );
-
if ((cr1==-1)||(cr2==-1)) { printf(«nSetPixel error %u», GetLastError()); goto ex; }
Но только в Windows 2K и Windows XP, а в Windows 98 по прежнему ничего не получаеццо. А мне, хоть застрелись, надо, чтобы рисовалось везде.
Вот здесь http://www.firststeps.ru/mfc/winapi/r.php?6 же явно Маздай 98. Чего там автор с пером мутил? Это очепятка что ли, должно было быть CreatePen?
-
iamlamer
New Member
- Публикаций:
-
0
- Регистрация:
- 20 июн 2005
- Сообщения:
- 273
- Адрес:
- Russia
Урррра!!! Все заработало!!! Оказываеццо, Windows NT, 2000, XP пофигу, а Windows 95, 98, ME надо именно GetWindowDC, а не GetDC !!!
Вот финальный, работающий везде вариант:
-
// Рисование в окне консоли
-
// Принудительно называем окно консоли «grafcon»
-
SetConsoleTitle(«grafcon»);
-
// Ищем консольное окошко с именем grafcon
-
v.dwOSVersionInfoSize = sizeof(v);
-
if (v.dwPlatformId==VER_PLATFORM_WIN32_NT)
-
hwnd=FindWindow(«ConsoleWindowClass»,»grafcon»);
-
hwnd=FindWindow(«tty»,»grafcon»);
-
// По хэндлу получаем контекст
-
for (x=50;x<100;x++) for (y=50;y<100;y++) SetPixel(hdc, x, y, RGB(128, 128, 128) );
Время прочтения
2 мин
Просмотры 37K
В последнее время Хабр просто пестрит «30-строчными постами»:
— Гоночка на JavaScript (30 строк кода)
— Крошечный арканоид на JavaScript (30 строк кода)
— Крошечный Excel на чистом JavaScript (30 строк кода)
— Крошечная змейка на JavaScript (30 строк кода)
— Tetris на javascript (в 30+ строк)
Одержимый желанием следовать моде, я тоже решил что-нибудь написать. Но так как с JS у меня отношения сложные, я решил писать на C++ с использованием API, которое так любезно предоставила мне ОС Windows (в народе именуемом WinAPI).
Итак, ближе к
телу
делу:
C++ код (31 строка):
#include <Windows.h>
#include <vector>
#include "resource.h"
BOOL CALLBACK PaintProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
POINT t; static std::vector<POINT> pos; HDC hdc; static bool status; PAINTSTRUCT pt;
switch(uMsg) {
case WM_INITDIALOG: status = false;
return TRUE;
break;
case WM_PAINT: hdc = BeginPaint(hwnd, &pt);
(!pos.size()) ? NULL : MoveToEx(hdc, pos[0].x, pos[0].y, NULL);
for(size_t i=0;i<pos.size();++i)
(pos[i].x==-1 && i<pos.size()-1) ? MoveToEx(hdc, pos[i+1].x, pos[i+1].y, NULL) : LineTo(hdc, pos[i].x, pos[i].y);
EndPaint(hwnd, &pt);
break;
case WM_LBUTTONDOWN: status = true;
break;
case WM_LBUTTONUP: status = false;
t.x=-1; pos.push_back(t);
break;
case WM_MOUSEMOVE: GetCursorPos(&t);
ScreenToClient (hwnd, &t);
(status) ? pos.push_back(t) : NULL;
(status) ? InvalidateRect(hwnd, NULL, true) : NULL;
break;
case WM_CLOSE: EndDialog(hwnd, 0);
break; }
return FALSE; }
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
{ DialogBox(hInst, MAKEINTRESOURCE(IDD_PAINT), NULL, PaintProc);
return 0; }
Так как меряемся
пиписьками
основным кодом, не учитывая «верстку», описание диалога, как ресурса, не учитываю, но желающим воспроизвести данный пример необходимо создать диалог с ID — IDD_PAINT.
Собственно, то, ради чего всё начиналось:
Особенности
— 31 строка C++
говно
кода
— Использованные библиотеки: STL
Недостатки
— Мерцание экрана при непосредственном рисовании (двойная буферизация была опущена в силу экономии строк).
— В реальной задаче написания программы (аля Paint) использование контейнера vector, возможно, не самый лучший вариант, но все же.
Итог
Согласен, немного неправильно укладывать объявление переменных в одну строку. Но думаю, что на общее впечатление от кода это не повлияет.
Всем спасибо за внимание. +1 к общему количеству «ненормальных».
case MNUCLEAR: |
|
Clear(); |
|
curspos = { 0, 1 }; |
// после очистки курсор |
//в левый верхний угол консоли |
break;
case MNUEXIT: int resp;
cout << «Вы уверены, что хотите выйти
из программы? (y/n)?»;
resp = getchar();
if (resp == ‘y’ || resp == ‘Y’)
{ gotoxy(0, 0); cls(1); exit(0); } getCursorPosition(); // запомнить положение курсора,
// если отменили выход
break;
}
fflush(stdin); //очистить буфер клавиатуры gotoxy(menu[sel].x, menu[sel].y); // курсор в
// текущий пункт меню
showCursor(false);
break;
case 120: // выход по клавише x case 88: // выход по клавише X case 27: // выход по клавише ESC
gotoxy(0, 0); cls(1);
exit(0); //завершение программы
}
}
}
}
//Текстовый курсор в точку x,y void gotoxy(int x, int y)
{
COORD cursorPos = { x, y }; SetConsoleCursorPosition(hStdOut, cursorPos); //SetConsoleCursorPosition(hStdOut, {x,y});
}
//запись текущего положения текстового курсора в глобальную
//переменную curspos
void getCursorPosition(void)
{
GetConsoleScreenBufferInfo(hStdOut, &csbInfo);
curspos = csbInfo.dwCursorPosition;// положение курсора
}
//очистка тестовой области консоли. Если it==0, то очистка со
//строки следующей за строкой меню, иначе очистка с левого
//верхнего угла консоли
31
void cls(int it)
{
int i;
string s(80, ‘ ‘);
SetConsoleTextAttribute(hStdOut, woкkWindowAttributes); if (it == 0) gotoxy(0, consolRect.Top + 1);
else gotoxy(0, consolRect.Top);
for (i = consolRect.Top; i<curspos.Y+1; i++) // очистка от
// первой строки до строки с курсором cout << s.c_str(); // залить фон строки меню
gotoxy(0, 0);
}
//выделить пункт меню с номером sel void itemMenu(int sel, bool activate)
{
WORD itemAttributes;
if (activate) itemAttributes = activeItemAttributes; else itemAttributes = inactiveItemAttributes; gotoxy(menu[sel].x, menu[sel].y); SetConsoleTextAttribute(hStdOut, itemAttributes); cout << menu[sel].str;
}
//скрыть/показать текстовый курсор в консоли
void showCursor(bool visible)
{
CONSOLE_CURSOR_INFO ccInfo; ccInfo.bVisible = visible; ccInfo.dwSize = 20; SetConsoleCursorInfo(hStdOut, &ccInfo);
}
Большую часть кода этого модуля составляет определение функции DrawMenu(). В ней «спрятана» вся функциональность меню. Функция рисует/печатает меню в верхней строке консольного окна, а затем запускает бесконечный цикл обработки событий нажатий клавиш. Комментарии в коде поясняют основные команды. Затем в модуле определяются некоторые вспомогательные функции.
Функция gotoxy(int x,int y) устанавливает курсор в заданную позицию.
Функция getCursorPosition(void) сохраняет текущее положение курсора в глобальную переменную curspos.
Функция cls(int it) выполняют очистку консоли (всей или без строки меню).
Функция itemMenu(int sel,bool activate) выделяет или снимает выделение пункта меню.
Функция showCursor(bool visible) делает невидимым или показывает текстовый курсор.
32
Замечание. Нашему меню далеко до функциональности, которую вы наблюдаете в меню программ Windows. Однако оно дает представление о том, как можно создать меню в текстовом режиме консоли. Вы можете использовать нашу программу как шаблон для ваших консольных программ. Все, что вам надо изменить находится в цикле обработки событий нажатий клавиш функции DrawMenu(), а также небольшом фрагменте кода, который еще раз приведен ниже.
// Изменяемые элементы меню
enum menuitems { MNUFILE, MNUDO, MNUCLEAR, MNUEXIT }; extern const int numMenu = 4; //количество пунктов меню
ITEM menu[numMenu] = { |
//положение (x,y), заголовок, |
|
// указатель на функцию |
||
{ 1, 0, » Файл |
«, File }, |
{11, 0, » Действие «, Do },
{21, 0, » Очистить «, Clear },
{ 31, 0, » Выход |
«, Exit } |
}; |
Изменения в программе, которые должен выполнить пользователь состоят в следующем:
изменить количество пунктов меню, задав значение константы numMenu;
Определить функции, которые будут вызываться при выборах пунктов меню (у нас функции File, Do, Clear, Exit определены в модуле menudemo.cpp) ;
добавить описание функций меню в модуль menudemo.h;
изменить количество пунктов и их заголовки в массиве menu[]; при
этом длины строк заголовков (в нашем примере » Файл «, » Действие «, » Очистить «, » Выход «) должна быть подобрана в соответствии с их первой координатой в этом массиве; у нас длина строк заголовков меню равна 10 символам);
изменить/добавить имена констант в перечислении menuitems; элементов в перечислении должно быть столько, сколько элементов меню;
в функции DrawMenu() в цикл обработки нажатий клавиш в раздел case KEY_ENTER внутри тела оператора switch(sel) нужно добавить код обработки выбора соответствующих пунктов меню. Например, если вы добавите в перечисление menuitems константу MYMENU, а функция, которая будет обрабатывать соответствующий ей пункт меню, будет называться mymenu(), то вы должны будете добавить
следующий код:
case MYMENU: mymenu();
getCursorPosition();
break;
33
У нашего строчного меню есть недостаток – оно привязано к первой текстовой строке консоли. При прокрутке текста в консоли оно будет также прокручиваться. Вы можете попробовать самостоятельно доработать программу, чтобы это неудобство устранить.
■
Сделаем еще одно замечание. Большинство функций, которые определяют дескриптор окна, определяют или устанавливают его размер, атрибуты и т.д. могут не справиться со своей задачей. В этом случае они возвращают соответствующие значения, которые нужно (и правильно) проверять. Для простоты контроль ошибок в наших примерах не был реализован. Однако в реально функционирующем приложении такой контроль обязателен.
Например, чтение дескриптора консольного окна может выполняться следующим образом
hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (hStdout == INVALID_HANDLE_VALUE) {
MessageBox(NULL, L»Ошибка получения дескриптора», L»Ошибка», MB_OK | MB_ICONERROR);
return 1;
}
Здесь функция MessageBox выводит простое окно сообщений
Первый ее аргумент является идентификатором родительского окна или NULL, если такового нет. Второй аргумент является указателем на двухбайтовую строку, которая выводится в теле окна сообщения. Обычная строка превращается в массив символов типа wchar_t (каждый символ занимает в памяти два байта), если перед строкой указать префикс L. Окно MessageBox является диалоговым окном Windows и, поэтому, использует двухбайтовые коды символов в стандарте Unicode, в отличии от однобайтовых строк консоли. Третий аргумент является указателем на двухбайтовую строку, которая выводится в заголовке окна. Последний параметр типа UINT определяет какие в окне сообщений отображаются кнопки и иконки. Установка битов этого беззнакового целого числа говорит о том будет ли включен тот или иной элемент интерфейса окна сообщений. Чаще всего его задают комбинацией флагов. В приведенном выше фрагменте кода мы задали этот аргумент в виде комбинации двух флагов MB_OK | MB_ICONERROR. Первый из них говорит о необходимости отобразить кнопку OK, второй выводит иконку . А
например, флаг MB_YESNOCANCEL выводит в окне сообщений три кнопки:
.
Функция MessageBox возвращает целое значение, которое зависит от того, какая кнопка была нажата в окне сообщений.
34
Существует много других, не затронутых нами функций, которые предназначены для управления консольным окном. Познакомиться с ними вы можете по справочной системе в разделе «Console Functions».
1.2 Рисование в консольном окне
В этом параграфе мы покажем, как можно применять графические функции Windows для рисования в консольном окне. Однако помните, что графические возможности этого окна недостаточно функциональны и основным режимом работы консоли является текстовый. Тем не менее, все, что здесь будет изложено, без всяких изменений, но с некоторыми существенными улучшениями функциональности, используется в «оконных» приложениях
Windows.
Все графические функции C/C++ в Windows используют специальную структуру, которая называется контекстом окна. Мы здесь не будем описывать ее подробно. Вы должны знать, что она хранит текущие параметры области, в которой мы рисуем: цвет линий, их толщину и стиль (пунктир, сплошной,…), цвет заливки областей, размеры окна и т.д. В программах на C/C++ контекст окна хранится в переменной типа HDC, которая должна быть связана с окном, в котором происходит рисование. Простейшая команда, которая создает такую переменную, имеет вид
HDC hdc = GetDC(GetConsoleWindow());
Сейчас вы можете не задумываться о ее смысле – просто включайте эту строку в начало функции main(), а возвращенный ее дескриптор используйте во всех графических функциях. Любая функция WINDOWS, которая что-то рисует, первым параметром будет принимать переменную hdc. Перед завершением программы дескриптор контекста консольного окна рекомендуется освободить командой
ReleaseDC(NULL, hdc);
Первый параметр представляет идентификатор окна HWND, который может использоваться разными функциями программы. Обычно его получают командой
HWND hwnd = GetConsoleWindow();
Если он использовался в программе, то его идентификатор hwnd должен был бы быть передан первым аргументом в функцию ReleaseDC(hwnd,hdc).
В случае ошибки функции GetConsoleWindow() и GetDC() возвращают специальные значения, которые рекомендуется проверять, например, следующим образом:
HWND hwnd = GetConsoleWindow(); HDC hdc;
if (hwnd!=NULL)
{
hdc=GetWindowDC(hwnd);
if(hdc==0) cout<<«Error DC Window»<<endl;
}
35
else
cout << «Error Find Window» << endl;
Для упрощения кода в примерах этого параграфа мы не будем выполнять множество проверок значений, возвращаемых функциями, которые получают или создают различные объекты Windows (или их идентификаторы). Однако в реально функционирующих приложениях такой контроль обязателен.
При работе с графикой используется система координат при которой по умолчанию левый верхний угол окна имеет координаты (0,0), оси направлены вправо и вниз, а логическими единицами являются пиксели.
Пример 1a. В этом примере мы рисуем прямоугольник в консольном окне.
#include <windows.h>
void main()
{
HDC hdc = GetDC(GetConsoleWindow()); Rectangle(hdc, 100, 60, 180, 160); system(«pause»);
}
Здесь переменная hdc, содержащая дескриптор контекста консольного окна, передается первым аргументом функции Rectangle(hdc,…), которая рисует прямоугольник. Другие аргументы этой функции – координаты левого верхнего и правого нижнего углов xleft , yleft , xright , yright .
Начало координат находится в левом верхнем углу рабочей области окна. Горизонтальная ось X направлена вправо, вертикальная Y – вниз. По умолчанию единицами измерения являются пиксели.
Обратите внимание на поведение рисунка после сворачивания консольного окна, перекрытия его другим окном, изменении размера или прокручивании его внутренней области. Графика исчезает! Этого недостатка обычно нет у стандартных окон Windows потому, что они «умеют» автоматически перерисовывать свою рабочую область после событий сворачивания, перекрытия или изменения размера. В учебных консольных программах перерисовку можно выполнять вручную. Для этого любое рисование следует помещать внутрь создаваемой вами функции draw(.), и вызывать ее повторно в случае, если графика окна исчезла.
Пример 1b. Более гибкая версия консольной программы с графикой.
#include <windows.h> #include <iostream> #include <conio.h> using namespace std;
void draw(HWND hwnd, HDC hdc); void setConsoleSize();
36
void main()
{
SetConsoleTitle(L»Simple Rectangle Drawing»); HWND hwnd = GetConsoleWindow();
HDC hdc = GetDC(hwnd); |
|
setConsoleSize(); |
// задание размеров консоли |
Sleep(100); |
|
draw(hwnd, hdc); |
// функция рисования в консоли |
int iKey = 1; |
|
while (iKey != 27) { |
// Задержка и выход по клавише ESC |
if (_kbhit()) { |
|
iKey = _getch(); |
|
switch (iKey) |
|
{ |
|
case 112: case 80: case 167: case 135: |
|
draw(hwnd, hdc); |
// перерисовка консоли по клавише ‘p’ |
break; |
|
} |
|
} |
|
} |
|
ReleaseDC(hwnd, hdc); |
//освобождаем дескрипторы консоли |
}
// Функция рисования. Помещайте сюда всю графику void draw(HWND hwnd, HDC hdc)
{
Rectangle(hdc, 100, 60, 180, 160); // Рисуем прямоугольник
}
void setConsoleSize() // Задание размеров окна консоли
{
const int colConsole = 80; const int rowConsole = 30;
HANDLE hNdl = GetStdHandle(STD_OUTPUT_HANDLE); SMALL_RECT windowSize ={0,0,colConsole-1,rowConsole-1}; SetConsoleWindowInfo(hNdl, TRUE, &windowSize);
COORD bufferSize ={colConsole, rowConsole }; // размеры буфера SetConsoleScreenBufferSize(hNdl, bufferSize);
}
Во второй версии программы мы создали функцию setConsoleSize(.), которая задает размеры консольного окна без полос прокрутки (пока мы не уменьшили размеры окна). Мы также вынесли рисование в отдельную функцию draw(.), которую можем вызывать по нажатию клавиши „p‟, например для перерисовки графики, если она пропала после перекрытия консоли другим окном. Перед завершением программы мы также освободили дескрипторы консоли.
Как вы заметили, графика в консоли видна тогда, когда рисование выпоняется в видимое окно. После сворачивания или перекрытия окна консоли графика исчезает. На самом деле приложения Windows получают сообщение от ОС о том, что они должны перерисовать свое окно (или его часть) и
37
программисты помещают вызов графических функций в обработчик этого сообщения (специальную функцию). В программе, написанной для консоли, мы не можем перехватить и обработать такое сообщение. Но перерисовка консоли после восстановления видимости ее окна все равно происходит. Это приводит к рисованию «пустоты», т.е. к очистке окна. Поэтому нам приходится «выкручиваться». После сворачивания или перекрытия окна консоли рисование нужно повторить. Для этого в предыдущей программе мы создали функцию draw(.), которую могли вызвать клавишей „p‟.
Обратите также внимание на функцию Sleep(.), которую мы вызываем перед вызовом функции draw(.). Она приостанавливает выполнение потока инструкций программы на заданное количество милисекунд. На современных компьтерах, если в коде предыдущей программы не использовать функцию Sleep(.), функция draw(.) успевает выполниться еще до того, как консоль станет видимой на экране. После появления консоли на экране, окно получает сообщение о необходимости перерисовки, и в результате происходит очистка окна. Вставка функции Sleep() перед вызовом функции draw приводит к тому, что окно консоли станет видимым раньше того, как мы что – то нарисуем. Время задержки будет зависеть от быстродействия компьютера. Возможно, вставка функции Sleep()вам не понадобится.
В консольном приложении у нас есть возможность обрабатывать сообщение получения окном фокуса. Это сообщение помещается в буфер событий, который заполняется функцией ReadConsoleInput. Мы использовали эту функцию в примере 8 предыдущего параграфа. Она помещает в буфер событий информацию о мыши, клавиатуре, а также о получении окном фокуса. Если, например, буфер/массив событий наывается eventBuffer, то проверку того, что консоль получила фокус, можно выполнить следующим образом
if (eventBuffer[i].EventType == FOCUS_EVENT) { Sleep(300);
draw(hwnd, hdc);
}
Здесь опять требуется небольшая задержка, покольку рисование может завершитья до того, как окно консоли появится поверх остальных окон. Еще одна версия консольной программы с графикой может выглядеть следующим образом.
Пример 1c. Пример консольной программы с перерисовкой графики при получении окном фокуса.
#include <windows.h>
void draw(HWND hwnd, HDC hdc); void setConsoleSize();
38
void main()
{
HWND hwnd = GetConsoleWindow(); HDC hdc = GetDC(hwnd);
HANDLE rHnd = GetStdHandle(STD_INPUT_HANDLE); SetConsoleTitle(L»Simple Rectangle Drawing»);
setConsoleSize(); |
||
Sleep(100); |
// |
задержка |
draw(hwnd, hdc); |
// |
рисование любого множества фигур |
DWORD numEvents = 0; // Количество непрочитанных сообщений DWORD numEventsRead = 0; // Количество прочитанных сообщений bool isRunning = true; // флаг продолжения работы
//Ели isRunning=false, то программа завершается while (isRunning) {
// Определить количество событий консоли
GetNumberOfConsoleInputEvents(rHnd, &numEvents); if (numEvents != 0) {
//выделение памяти для хранения данных о событиях
INPUT_RECORD *eventBuffer = new INPUT_RECORD[numEvents];
//Извлечение данных во временный буфер событий eventBuffer[] ReadConsoleInput(rHnd, eventBuffer, numEvents,
&numEventsRead);
// Цикл по всем извлеченным событиям
for (DWORD i = 0; i < numEventsRead; ++i) { if (eventBuffer[i].EventType == KEY_EVENT) {
if(eventBuffer[i].Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
isRunning=false; // выход, если нажата клавиша ESC else if(eventBuffer[i].Event.KeyEvent.uChar.AsciiChar==
‘d’) |
|
draw(hwnd, hdc); |
// перерисовка по клавише ‘d’ |
} |
|
if (eventBuffer[i].EventType == FOCUS_EVENT) { |
|
Sleep(300); |
|
draw(hwnd, hdc); |
// перерисовка при получении фокуса |
}
else if (eventBuffer[i].EventType == MOUSE_EVENT) {
// обработка событий мыши
}
}
delete[] eventBuffer;
}
}
ReleaseDC(hwnd, hdc); //освобождаем дескрипторы
}
Здесь мы используем функцию setConsoleSize(), которую создали в примере 1b, и код которой остался без изменений, а также функцию draw(.), в которую вы можете помещать любые функции рисования.
Изменение размеров окна консоли не приводит к событию FOCUS_EVENT, но вызывает очистку окна. Поэтому мы оставили команду принудительной перерисовки – вызов функции draw при нажатии клавиши „d‟.
39
В программах, которые приведены далее в этом параграфе, для простоты не будет реализован контроль ошибок, не будут освобождаться ресурсы, и графические функции не будут собираться в отдельную функцию (например, draw). Однако в реально функционирующих приложениях соответствующие фрагменты кода обязательны.
■
Линия может быть жирной и тонкой, прерывистой и штрих – пунктирной, иметь определенный цвет. Это все вместе называется стилем линии (или просто пером). Текущее перо является частью структуры контекста окна. Чтобы линию нарисовать требуемым пером, вначале вы должны создать объект типа HPEN
HPEN Pen = CreatePen(PS_SOLID, 3, RGB(255,0,0));
Первый аргумент функции CreatePen определяет будет ли линия сплошной (PS_SOLID), пунктирной, штрих – пунктирной и т.д. Можно использовать значения PS_DOT, PS_DASH, PS_DASHDOT и некоторые другие. Второй аргумент определяет толщину линии, третий – задает цвет. Аргументы макроса RGB являются целыми числами со значениями от 0 до 255 и задают цвет, составленный из оттенков/яркостей трех базовых цветов: красного (Red), зеленого (Green) и синего (Blue). Нулевое значение исключает соответствующий базовый цвет, максимальное допустимое значение яркости базовых цветов 255.
По умолчанию установлено черное сплошное перо толщиной в 1 пиксель. После создания пера (HPEN) его нужно загрузить в контекст (HDC)
функцией SelectObject(HDC,HPEN). После этого все линии будут рисоваться созданным пером до тех пор, пока в контекст не будет загружено новое перо.
Есть еще один момент. В контексте хранится положение так называемого текущего указателя, который содержит координаты точки от которой следующая графическая функция начинает рисовать свою фигуру. При запуске программы этот указатель устанавливается в точку (0,0). Его местоположение на экране невидимо, он означает лишь позицию в окне для некоторых функций. Не все графические функции используют этот указатель. Функция
MoveToEx((HDC,X,Y,NULL);
переносит текущую позицию указателя в точку (X,Y) и не запоминает старую позицию (если последний аргумент равен NULL).
В следующем примере мы используем функцию
LineTo(HDC,X,Y)
которая рисует отрезок прямой от текущего положения указателя до точки (X,Y) и перемещает указатель в эту точку.
Пример 2.
#include <windows.h> void main()
{
// получаем дескриптор контекста консольного окна
HDC hdc = GetDC(GetConsoleWindow());
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
23.02.2015231.42 Кб4DS.doc
- #