МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
КАФЕДРА ІНФОРМАЦІЙНИХ СИСТЕМ ТА МЕРЕЖ
/
ЗВІТ
про виконання лабораторної роботи № 2
“ Засоби графічного виведення на екран”
з дисципліни “Проблемно-орієнтоване програмування”
Варіант 17
Львів 2016
Мета роботи: полягає у вивченні API-функцій для виведення текстової та графічної інформації у вікно програми для Windows.
Теоретичні відомості:
При посилці повідомлення WM_PAINT - Викликаємо функції малювання BeginPaint(),GetClientRect(), SetTextColor(), DrawText(), EndPaint(). За назвою видно, що ці функції роблять. Функція BeginPaint() в прямому сенсі починає малювати. Тільки для цього їй потрібно мати дескриптор вікна і об'єкт PAINTSTRUCT (у нас це ps). Вона повертає значення типу HDC, тому нам потрібно присвоїти їй hDc. GetClientRect() вибирає область. Параметри у неї аналогічні попередній функції: дескриптор вікна і покажчик на об'єкт класу RECT (у нас це rect). Функція SetTextColor()повертає колір тексту. Її параметри: повертається значення функції BeginPaint() - hDC і покажчик на об'єкт класу COLORREF. Ми могли і не задавати окремо колір тексту, створюючи при цьому змінну colorText, а могли зробити це прямо в ній. Але з точки зору читання коду і його тями - це в корені не правильно. Намагайтеся завжди оголошувати змінні окремо і писати в коментарях, навіщо вони потрібні і тоді не буде питань, які параметри має функція, через рік як ви останній раз закрили проект по WinAPI. Також дотримуйтесь угорську нотацію з програмування, суть якої: імена змінних повинні нести сенс їхнього існування і показувати тип даних. Оголошення функції DrawText():
1
3
4
5
6
7
int DrawText(
HDC hDC,// дескриптор контекста устр-ва
LPCTSTR lpchText, // указатель на нашу строку
int nCount, // длина текста (если равно -1, то определяет сам)
LPRECT lpRect, // указатель на объект RECT
UINT uFormat // формат отображения текста
);
На рахунок перших 4х параметрів все ясно. Четвертий uFormat - Має декілька видів. Зазвичай використовуються DT_SINGLELINE, DT_CENTER і DT_VCENTER для відображення тексту в центрі області, в одну лінію. Але Ви можете змінити параметри (про що поговоримо в наступних уроках). Функція EndPaint() має два параметри: дескриптор вікна і об'єкт ps. Помітили аналогію з BeginPaint()? Що робити при виклику WM_PAINT, ми знаємо (не забуваємо в
кінці дописати break).WM_DESTROY надсилається віконця функцією DestroyWindow(), яка викликається у разі, якщо ми його закрили. А це відбувається в операторі default.
Варіант №17
Порядок виконання роботи
Написати програму (або змінити наведену у роботі програму) для виведення графіка функції:
/
Код програми:
#include "stdafx.h"
#include "Resource.h"
#include <math.h>
BOOL RegClass(WNDPROC, LPCTSTR, UINT);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInstance;
wchar_t szClassName[] = L"GraphClass";
typedef struct
{
wchar_t name[20];
float x[50];
float y[50];
} FUNC;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpszCmdLine, int nCmdShow)
{
MSG msg;
HWND hwnd;
::hInstance = hInstance;
if (!RegClass(WndProc, szClassName, COLOR_WINDOW))
return FALSE;
hwnd = CreateWindow(szClassName, L"Гpaфік функції y=sinh(x)", WS_OVERLAPPEDWINDOW
| WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1500, 1000, 0, 0,
hInstance, NULL);
if (!hwnd) return FALSE;
while (GetMessage(&msg, 0, 0, 0))
DispatchMessage(&msg);
return msg.wParam;
}
BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbClsExtra = wc.cbWndExtra = 0;
wc.lpfnWndProc = Proc;
wc.hInstance = hInstance;
wc.lpszClassName = szName;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SMALL));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(HBRUSH)(brBackground + 2);
wc.lpszMenuName = NULL;
return (RegisterClass(&wc) != 0);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
static HDC hdc;
static HPEN hPen;
static HPEN hOldPen;
static short cx, cy;
static FUNC myfunc;
char BufA[20];
wchar_t BufW[10];
switch (msg)
{
case WM_SIZE:
{ cx = LOWORD(lParam); cy = HIWORD(lParam);
return 0;
}
case WM_CREATE:
{ wcscpy(myfunc.name, L"sinh(x)");
for (int i = 0; i<50; i++)
{
myfunc.x[i] = (float)(0.25*i);
myfunc.y[i] = (float)sinh(myfunc.x[i]);
}
return 0;
}
case WM_PAINT:
{ hdc = BeginPaint(hwnd, &ps); //Задаємо область для виведення графіка
int x0 = cx / 20; //Ліва межа графіка
int xc = cx - x0; //Права межа графіка
int y0 = cy / 20; //Верхня межа графіка
int yc = (cy / 1.1) ; //Середина графіка по осі у
int amp = yc - y0; //Амплітуда графіка
float ymax = 0.; //Максимум функції
float ymin = 0.; //Мінімум функції
//Виводимо назву функції
TextOut(hdc, x0 + 8, y0 / 4, myfunc.name, wcslen(myfunc.name));
//Виводимо назву змінної
TextOut(hdc, xc + x0 / 2, yc + y0 / 20 , L"x", 1);
//Виводимо вісь ординат
MoveToEx(hdc, x0, cy - y0 / 2, NULL);
LineTo(hdc, x0, y0 / 2);
//Виводимо вісь абсцис
MoveToEx(hdc, x0, yc, NULL);
LineTo(hdc, xc + x0 / 2, yc);
//Визначаємо максимум та мінімум функції
for (int i = 0; i<50; i++)
{
float ycurr = myfunc.y[i];
if (ymax<ycurr) ymax = ycurr;
else if (ymin>ycurr) ymin = ycurr;
}
if (ymax<fabs(ymin)) ymax = (float)fabs(ymin);
//Встановлюємо масштаб по осі у
float dy = (float)amp / ymax;
//Встановлюємо масштаб по осі х
float dx = (float)(xc - x0) / (myfunc.x[49] - myfunc.x[0]);
//Створюємо перо синього кольору для малювання
hPen = CreatePen(PS_SOLID, 4, RGB(200, 100, 100));
hOldPen = (HPEN)SelectObject(hdc, hPen);
//Встановлюємо курсор в першу точку графіка
MoveToEx(hdc, x0, (int)(yc - dy*myfunc.y[0]), NULL);
//З' єднуємо точки графіка лініями
for (int i = 1; i<50; i++)
{
//Обчислюємо координати поточної точки
int xcurr = (int)(dx*(myfunc.x[i] - myfunc.x[0]) + x0),
ycurr = (int)(yc - dy*myfunc.y[i]);
//Виводимо пряму до поточної точки
LineTo(hdc, xcurr, ycurr);
TextOut(hdc, xcurr, ycurr, L"Іванов Вадим Богданович",23 );
}
//Робимо перо знову чорним
hPen = CreatePen(1, 1, RGB(0, 0, 0));
SelectObject(hdc, hPen);
//Наносимо поділки по осі абсцис
int i;
for (i = 0; i<50; i += 10)
{
if (i == 0) continue;
MoveToEx(hdc, (int)(dx*(myfunc.x[i] - myfunc.x[0]) + x0), yc + 4, NULL);
LineTo(hdc, (int)(dx*(myfunc.x[i] - myfunc.x[0]) + x0), yc - 5);
_gcvt(myfunc.x[i] - myfunc.x[0], 3, BufA);
TextOutA(hdc, (int)(dx*(myfunc.x[i] - myfunc.x[0]) + x0 - 10), yc + 5, BufA,
strlen(BufA));
}
//Наносимо поділки по осі ординат
i = 0;
float y, h = (ymax - ymin) / 5;
for (y = 0; y <= ymax; y += h, i++)
{
MoveToEx(hdc, x0 - 4, (int)(yc - i*(yc - y0) / 5), NULL);
LineTo(hdc, x0 + 5, (int)(yc - i*(yc - y0) / 5));
_gcvt(y, 6, BufA);
TextOutA(hdc, x0 - 35, (int)(yc - i*(yc - y0) / 5) - 10, BufA, strlen(BufA));
if (y == 0) continue;
_gcvt(-y, 6, BufA);
TextOutA(hdc, x0 - 40, (int)(yc + i*(yc - y0) / 5) - 10, BufA, strlen(BufA));
}
ValidateRect(hwnd, NULL); //Оновлюємо екран
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
{
SelectObject(hdc, hOldPen);
DeleteObject(hPen);
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Результат роботи :
/
Висновок: виконуючи дану лабораторну роботу я ознайомився з API-функціями для виведення текстової та графічної інформації у вікно програми для Windows. Використовуючи приклад, даний у методичних вказівках, побудував власний графік відповідно до свого варіанту.