МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
Національний університет “Львівська політехніка”
кафедра САПР
З В І Т
до лабораторної роботи №3
з курсу: “ Геометричне моделювання у конструюванні інженерних об’єктів і систем ”
на тему: “Графічні функції WINDOWS - інтерфейса (WINAPI) засобами BORLAND PASCAL 7.0 for WINDOWS та BORLAND DELPHI”
Львів – 2005
Тема роботи: Графічні функції WINDOWS - інтерфейса (WINAPI) засобами BORLAND PASCAL 7.0 for WINDOWS та BORLAND DELPHI
Мета роботи: ознайомлення та практичне освоєння технології й основ роботи з графічними можливостями Windows-інтерфейсу (WinAPI) операційного середовища Windows, що можуть викликатися прикладними програмами. Вивчити основні графічні функцій та процедури WinAPI (Win32API) засобами програмного середовища Borland Pascal 7.0 for Windows та візуального середовища програмування Borland Delphi, набути практичних навиків переходу з програмування графіки для операційної системи DOS до оволодіння принципами створення Windows-программ, розробки графічних процедур та програм WinAPI.
Короткі теоретичні відомості
Принципи організації програм для DOS і для WINDOWS
DOS є однозадачною операційною системою. Програма, що виконується в середовищі DOS, керується потоком даних. Після ініціалізації (запуску програми) перша програмна процедура виробляє дані, і в залежності від їхнього змісту виробляється виконання наступної процедури, що знову генерує дані і так далі. При визначених даних виробляється деініціалізація програми.
Windows є багатозадачною операційною системою і по суті не може керуватися потоком даних. Після ініціалізації (запуску) програми керування одержує не яка-небудь робоча процедура цієї програми, а диспетчер подій.
Подія в термінах Windows розуміється як факт здійснення елементарної дії, від якого може залежати хід виконання програми. Це, приміром, натискання клавіші, переміщення курсору миші, завершення визначеного часового інтервалу.
Дії, виконувані диспетчером подій:
а) одержання (фіксація) події;
б) перевірка умови виходу з програми;
в) вибір потрібної процедури обробки події (диспетчирування).
Коли обрана процедура завершує роботу, керування знову повертається диспетчеру подій. При фіксації події, що завершує програму, диспетчер завершує свою роботу і передає керування процедурі деініціалізації.
Перевагою такої схеми керування ходом програми є універсальність. При модернізації програм для введення нової реакції на подію, що вводиться в програму, потрібно лише додати процедуру обробки цієї події без порушення базового коду програми. Для цього всі події в Windows приводяться до стандартного виду визначеної структури (повідомленню).
Терміном API (Application Programming Interface) називають інтерфейс прикладної програми Windows. Це повний набір процедур і функцій операційного середовища Windows, що можуть викликатися прикладними програмами під час їхньої роботи.
Windows API включає близько 1000 функцій, і для полегшення орієнтування в них прийнято дотримувати так називаної угорської нотації - угоди про принципи іменування функцій, змінних і констант у Windows.
Windows - програми засновані на об'єктній технології — вікна, меню, піктограми, блоки діалогу, таймер, інструменти для малювання та інші елементи створюються і керуються як об'єкти. Сама програма розглядається середовищем Windows також як об'єкт.
Об'єктів досить багато, і для їхнього однозначного визначення існують дескриптори (чи посилання - термін „Handle"). Дескриптор можна розглядати як індекс об'єкта в системному списку об'єктів Windows.
Графічні функції зі складу API Windows об'єднані в окрему групу — підсистему GDI (Graphic Device Interface, інтерфейс графічного пристрою). Важлива риса підсистеми GDI - апаратна незалежність багатьох функцій від конкретного графічного пристрою.
Контекст графічного пристрою (Device Context) — це важливий елемент графіки в середовищі операційної системи Windows. Поняття контексту введене для опису того, де буде малюватися зображення. Іншими словами, контекст графічного пристрою вказує площину відображення, на яку робиться графічний вивід. Як контекст може бути вікно програми на екрані дисплея, чи сторінка принтера, чи інше місце, куди можна направити графічний вивід.
Якщо ваша програма робить виклик графічних функцій API Windows, таких як малювання крапок, ліній, фігур, тексту тощо, необхідно вказувати ідентифікатор контексту (handle of device context) і координати. Виклик необхідного драйвера - для екрана дисплея, принтера чи іншого пристрою - робить уже сама Windows. Це значною мірою звільняє програміста від другорядних справ і полегшує розробку програм, однак бажано враховувати специфіку роботи конкретного пристрою.
Ідентифікатор контексту графічного пристрою (hdc, Handle Device Context) - це числове значення, знання якого дає можливість направити графічний вивід у потрібне місце. Перед початком малювання необхідно одержати це числове значення. Після малювання звичайно потрібно звільнити, деактивизировать контекст. Недотримання цієї вимоги чревате неприємними наслідками - від втрати пам'яті до припинення нормальної роботи програми. Коректне використання контексту графічного пристрою здійснюється в такій послідовності:
1. Створення, активізація контексту, одержання значення hdc.
2. Малювання за допомогою графічних функцій API Windows.
3. Знищення, деактивизация контексту відповідного hdc.
Для того щоб операційна система могла розрізняти вікна для здійснення діалогу з ними, усі вікна при своєму створенні реєструються в операційній системі та отримують унікальний ідентифікатор, який називається „зсилкою на вікно". Тип цієї величини — hWnd (Handle WiNDow). Синонімом терміну „змилка" є дескриптор.
Змилка на вікно може використовуватися не лише операційною системою, але й програмами для ідентифікації вікна, з яким необхідно провести маніпуляції. Приклад:
Індивідуальне завдання
Варіант № 26
Написати програму із застосуванням графічних функцій WinAPI, яка дозволяє візуалізувати графік(и) функції з можливостями масштабування у вікні на певному інтервалі. Застосувати функції зміни кольору, штриховки, зафарбування замкнутих областей, текстових підписів, виводу координатної сітки. Організувати вивід графіка у зовнішній метафайл.
Побудувати в одній області екрана графіки функцій Y1(x) і Y2(x).
x=[-1.5… 1.5]
Текст програми та алгоритм розв’язку
program laba03;
{$APPTYPE CONSOLE}
uses
SysUtils,
windows,
messages;
const
max_point = 300;
m_vidstup1 = 5;
m_vidstup2 = 20;
var
wc : TWndClassEx;
MainWnd : HWND;
Mesg : TMsg;
xPos, yPos, nWidth, nHeight : Integer;
MyDC : hDC;
rec : TRect;
// x, y: integer;
// x1, y1: integer;
// centerX,centery,centerDX: integer;
RegFirst: TRect;
RegSecond: TRect;
Pen: array[1..3] of hPen;
Brush: array[1..3] of hBrush;
range_min, range_max: Extended;
graph_points_y1, graph_points_y2: array[1..max_point] of Extended;
//обчислення першої функції завдання
function funk_y1(x: Extended):Extended;
begin
funk_y1 := (x*x-1)/(x*x*x*x+1);
end;
//обчислення другої функції завдання
function funk_y2(x: Extended):Extended;
begin
funk_y2 := -x*x*x*x*x + 2*x*x*x - 1;
end;
// обчислення функції на заданому проміжку
// та збереження всіх результатів у масиві
// для подальшої обробки
procedure calculate_funcs();
var
i, di: Extended;
mi: integer;
begin
di := 0.01;
i := range_min;
mi := 1;
while i <= range_max do
begin
graph_points_y1[mi] := -funk_y1(i);
graph_points_y2[mi] := -funk_y2(i);
i := i + di;
inc(mi);
end;
end;
procedure plote_func_y1(reg: TRect);
var
min_y, max_y, swp, oy: Extended;
mi: integer;
lenx, leny, dmx, dmy, q1: Extended;
begin
SelectObject(MyDC, Pen[3]);
min_y := graph_points_y1[1];
max_y := graph_points_y1[1];
for mi := 1 to max_point do
begin
if min_y > graph_points_y1[mi] then
begin
min_y := graph_points_y1[mi];
end;
if max_y < graph_points_y1[mi] then
begin
max_y := graph_points_y1[mi];
end;
end;
lenx := reg.Right - reg.Left - m_vidstup2*2;
leny := reg.Bottom - reg.Top - m_vidstup2*2;
dmx := lenx / max_point;
// q1 := abs(min_y);
dmy := leny / (abs(min_y)+abs(max_y));
SelectObject(MyDC, Pen[2]);
SelectObject(MyDC, Brush[2]);
Textout(MyDC, reg.Left + m_vidstup1 + 2, reg.Bottom - m_vidstup2 -5, 'Function: Y1(x)=(x^2-1)/(x^4+1)', 31);
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Top + Round(m_vidstup2/2), nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Bottom - m_vidstup2 +5);
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Top + Round(m_vidstup2/2), nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 - 5 + reg.Left, reg.Top + Round(m_vidstup2));
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Top + Round(m_vidstup2/2), nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 + 5 + reg.Left, reg.Top + Round(m_vidstup2));
TextOut(MyDC, Round(150*dmx) + m_vidstup2 + 10 + reg.Left, reg.Top + Round(m_vidstup2/2) - 2, 'Y',1);
MoveToEx(MyDC, Round(dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2, nil);
LineTo(MyDC, reg.Right - m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2);
MoveToEx(MyDC, reg.Right - m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2, nil);
LineTo(MyDC, reg.Right - m_vidstup2 - 10, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 5);
MoveToEx(MyDC, reg.Right - m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2, nil);
LineTo(MyDC, reg.Right - m_vidstup2 - 10, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 5);
TextOut(MyDC, reg.Right - m_vidstup2 - 10, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 5, 'X',1);
MoveToEx(MyDC, Round(50*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(50*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(50*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '-1',2);
MoveToEx(MyDC, Round(100*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(100*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(100*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '-0.5',4);
MoveToEx(MyDC, Round(200*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(200*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(200*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '0.5',3);
MoveToEx(MyDC, Round(250*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(250*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(250*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '1',1);
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left-2, Round(reg.Bottom - dmy*0.5) - m_vidstup2, nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left+2, Round(reg.Bottom - dmy*0.5) - m_vidstup2);
Textout(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left + 3, Round(reg.Bottom - dmy*0.5) - m_vidstup2 -2, '-0.5', 4);
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left-2, Round(reg.Bottom) - m_vidstup2, nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left+2, Round(reg.Bottom) - m_vidstup2);
Textout(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left+3, Round(reg.Bottom) - m_vidstup2 - 2, '-1', 2);
SelectObject(MyDC, Pen[3]);
SelectObject(MyDC, Brush[3]);
MoveToEx(MyDC, Round(dmx) + reg.Left + m_vidstup2, Round(graph_points_y1[1] * dmy + reg.Bottom - dmy*max_y) - m_vidstup2, nil);
for mi := 1 to max_point do
LineTo(MyDC, Round(mi*dmx) + reg.Left + m_vidstup2, Round(graph_points_y1[mi] * dmy + reg.Bottom - dmy*max_y) - m_vidstup2);
end;
procedure plote_func_y2(reg: TRect);
var
min_y, max_y, swp, oy: Extended;
mi: integer;
lenx, leny, dmx, dmy, q1: Extended;
begin
min_y := graph_points_y2[1];
max_y := graph_points_y2[1];
for mi := 1 to max_point do
begin
if min_y > graph_points_y2[mi] then
begin
min_y := graph_points_y2[mi];
end;
if max_y < graph_points_y2[mi] then
begin
max_y := graph_points_y2[mi];
end;
end;
lenx := reg.Right - reg.Left - m_vidstup2*2;
leny := reg.Bottom - reg.Top - m_vidstup2*2;
dmx := lenx / max_point;
dmy := leny / (abs(min_y)+abs(max_y));
SelectObject(MyDC, Pen[2]);
SelectObject(MyDC, Brush[2]);
Textout(MyDC, reg.Left + m_vidstup1 + 2, reg.Bottom - m_vidstup2 -5, 'Function: Y1(x)=(x^2-1)/(x^4+1)', 31);
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Top + Round(m_vidstup2/2), nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Bottom - m_vidstup2 +5);
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Top + Round(m_vidstup2/2), nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 - 5 + reg.Left, reg.Top + Round(m_vidstup2));
MoveToEx(MyDC, Round(150*dmx) + m_vidstup2 + reg.Left, reg.Top + Round(m_vidstup2/2), nil);
LineTo(MyDC, Round(150*dmx) + m_vidstup2 + 5 + reg.Left, reg.Top + Round(m_vidstup2));
TextOut(MyDC, Round(150*dmx) + m_vidstup2 + 10 + reg.Left, reg.Top + Round(m_vidstup2/2) - 2, 'Y',1);
MoveToEx(MyDC, Round(dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2, nil);
LineTo(MyDC, reg.Right - m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2);
MoveToEx(MyDC, reg.Right - m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2, nil);
LineTo(MyDC, reg.Right - m_vidstup2 - 10, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 5);
MoveToEx(MyDC, reg.Right - m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2, nil);
LineTo(MyDC, reg.Right - m_vidstup2 - 10, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 5);
TextOut(MyDC, reg.Right - m_vidstup2 - 10, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 5, 'X',1);
MoveToEx(MyDC, Round(50*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(50*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(50*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '-1',2);
MoveToEx(MyDC, Round(100*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(100*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(100*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '-0.5',4);
MoveToEx(MyDC, Round(200*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(200*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(200*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '0.5',3);
MoveToEx(MyDC, Round(250*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 - 2, nil);
LineTo(MyDC, Round(250*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2);
TextOut(MyDC, Round(250*dmx) + reg.Left + m_vidstup2, Round(reg.Bottom - dmy*max_y) - m_vidstup2 + 2, '1',1);
SelectObject(MyDC, Pen[3]);
SelectObject(MyDC, Brush[3]);
MoveToEx(MyDC, Round(dmx) + reg.Left + m_vidstup2, Round(graph_points_y2[1] * dmy + reg.Bottom - dmy*max_y) - m_vidstup2, nil);
for mi := 1 to max_point do
LineTo(MyDC, Round(mi*dmx) + reg.Left + m_vidstup2, Round(graph_points_y2[mi] * dmy + reg.Bottom - dmy*max_y) - m_vidstup2);
end;
Procedure Setka();
{var dx: integer;
Pen : hPen;
x1, y1: integer;}
Begin
{
Pen := CreatePen(ps_Dash, 1, RGB(100,100,100));
SelectObject(MyDC, Pen);
x1 := centerX;
y1 := centerY;
dx := centerDX;
while (x1 < (rec.right-50)) do
begin
MoveToEx(MyDC, x1, y1, nil);
LineTo(MyDC, x1, (rec.Bottom-50));
x1 := x1 + dx;
end;
x1 := centerX;
y1 := centerY;
dx := centerDX;
while (y1 < (rec.Bottom-50)) do
begin
MoveToEx(MyDC, x1, y1, nil);
LineTo(MyDC, (rec.Right-50), y1);
y1 := y1 + dx;
end;
}
End;
Procedure InitLab;
begin
Pen[1] := CreatePen(ps_Solid, 1, RGB(100,10,100));
Pen[2] := CreatePen(ps_Solid, 1, RGB(0,0,0));
Pen[3] := CreatePen(ps_Solid, 1, RGB(100,100,10));
// Brush[1] := CreateSolidBrush(RGB(152,184,220));
Brush[1] := CreateSolidBrush(RGB(255,255,255));
Brush[2] := CreateSolidBrush(RGB(152,0,0));
Brush[3] := CreateSolidBrush(RGB(0,184,0));
range_min := -1.5;
range_max := 1.5;
end;
Procedure DrawGrids(reg: TRect);
begin
DrawEdge(MyDC, reg, EDGE_ETCHED, BF_RECT);
SelectObject(MyDC, Pen[1]);
SelectObject(MyDC, Brush[1]);
Rectangle(MyDC, reg.Left + m_vidstup1, reg.Top + m_vidstup1, reg.Right - m_vidstup1, reg.Bottom - m_vidstup1);
// MoveTo
end;
procedure calc_new_size_window;
begin
with RegFirst do
begin
Top := rec.Top + 10;
Left := rec.Left + 10;
Bottom := Round(rec.Bottom / 2) - 5;
Right := rec.Right - 10;
end;
with RegSecond do
begin
Top := Round(rec.Bottom / 2) + 5;
Left := rec.Left + 10;
Bottom := rec.Bottom - 10;
Right := rec.Right - 10;
end;
end;
function WindowProc(wnd : HWND; Msg : Integer; Wparam : Wparam; Lparam : Lparam): Lresult;
stdcall;
Begin
case msg of
wm_destroy:
Begin
postquitmessage(0);
exit;
Result := 0;
End;
else Result := DefWindowProc(wnd, msg, wparam, lparam);
end;
end;
begin
wc.cbSize := sizeof(wc);
wc.style := cs_hredraw or cs_vredraw;
wc.lpfnWndProc := @WindowProc;
wc.cbClsExtra := 0;
wc.cbWndExtra :=0;
wc.hInstance := HInstance;
wc.hIcon := LoadIcon(0, idi_application);
wc.hCursor := LoadCursor(0, idc_arrow);
wc.hbrBackground := COLOR_BTNFACE+1;
wc.lpszMenuName := nil;
wc.lpszClassName := 'WinMin : Main';
RegisterClassEx(wc);
xPos := 100;
yPos := 150;
nWidth := 400;
nHeight := 250;
MainWnd := CreateWindowEx(0, 'WinMin : Main', 'Win Min', ws_overlappedwindow,
xPos, yPos, nWidth, nHeight, 0, 0, Hinstance, nil );
ShowWindow(MainWnd, CmdShow);
// centerX := 50;
// centerY := 50;
// centerDX := 50;
InitLab; //ініціалізуєм все що нам потрібне для роботи
calculate_funcs; //проводим обчислення функцій
While GetMessage(Mesg, 0, 0, 0) do
begin
TranslateMessage(Mesg);
DispatchMessage(Mesg);
GetClientRect(MainWnd, rec);
calc_new_size_window;
MyDC := GetDC(MainWnd);
DrawGrids(RegFirst);
DrawGrids(RegSecond);
plote_func_y1(RegFirst);
plote_func_y2(RegSecond);
ReleaseDC(MainWnd, MyDC);
DeleteDC(MyDC);
end;
end.
Результат виконання роботи
Висновок: Під час даної лабораторної роботи я ознайомилась з графічними можливостями Windows-інтерфейсу (WinAPI) операційного середовища Windows, що можуть викликатися прикладними програмами, з основними графічними функціями та процедурами WinAPI (Win32API).