Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Lab_progr_Win / Lab4

.doc
Скачиваний:
8
Добавлен:
23.03.2015
Размер:
186.88 Кб
Скачать

Лабораторна робота №4.

Тема роботи: Робота з таймером.

Ціль роботи: Придбання досвіду створення прикладного програмного забезпечення для Windows з використанням таймера.

ТЕОРЕТИЧНА ЧАСТИНА

Таймер у Windows є пристроєм введення інформації, що періодично сповіщає додаток про те, що минув заданий інтервал часу. Ваша програма задає Windows інтервал, як би говорячи системі: "Підштовхуй мене кожні 10 секунд". Тоді Windows посилає вашій програмі періодичні повідомлення WM_TIMER, сигналізуючи про витікання інтервалу часу.

Спочатку таймер Windows може показатися менш важливим пристроєм уведення, чим клавіатура чи миша, і, звичайно, це вірно для багатьох додатків Windows. Але таймер більш корисний, чим ви можете подумати, і не тільки для програм, що индицуют час, таких як програма Windows clock, що з'являється на панелі задач. Існують також і інші застосування таймера в Windows, деякі з яких, можуть бути, не настільки очевидні:

  • Багатозадачність;

  • Підтримка відновлення інформації про стан;

  • Реалізація "автозбереження";

  • Завершення демонстраційних версій програм;

  • Завдання темпу зміни;

  • Мультимедіа.

Ви можете приєднати таймер до своєї програми за допомогою виклику функції SetTimer. Функція SetTimer містить цілий параметр, що задає інтервал, що може знаходитися в межах (теоретично) від 1 до 4 294 967 295 мілісекунд, що складає близько 50 днів. Це значення визначає темп, з яким Windows посилає вашій програмі повідомлення WM_TIMER. Наприклад, інтервал у 1000 мілісекунд змусить Windows щосекунди посилати вашій програмі повідомлення.

Якщо у вашій програмі є таймер, то вона викликає функцію KillTimer для зупинки потоку повідомлень від таймера. Ви можете запрограмувати "однократний" таймер, викликаючи функцію KillTimer при обробці повідомлення WM_TIMER. Виклик функції KillTimer очищає чергу повідомлень від усіх неопрацьованих повідомлень WM_TIMER. Після виклику функції KillTimer ваша програма ніколи не одержить випадкового повідомлення WM_TIMER.

Виклик функції SetTimer виглядає в такий спосіб:

SetTimer(hwnd, 1, iMsecInterval, NULL);

Перший параметр — це дескриптор того вікна, чия віконна процедура буде одержувати повідомлення WM_TIMER. Другим параметром є ідентифікатор таймера, значення якого повинно бути відмінним від нуля. У цьому прикладі він довільно встановлений у 1. Третій параметр — це 32-розрядне беззнакове ціле, що задає інтервал у мілісекундах. Значення 60000 задає генерацію повідомлень WM_TIMER один раз у хвилину.

Ви можете в будь-який час зупинити потік повідомлень WM_TIMER (навіть під час обробки повідомлення WM_TIMER), викликавши функцію:

KillTimer(hwnd, 1);

Другим параметром тут є той же ідентифікатор таймера, що використовувався при виклику функції SetTimer. Ви повинні перед завершенням вашої програми у відповідь на повідомлення WM_DESTROY знищити всі активні таймери.

Для приклада створимо додаток, у якому користувач використовує таймер. Ця програма, названа TIMER, установлює таймер на часовий інтервал, рівній 1 секунді. У програмі організований лічильник, значення якого збільшується на 1 при одержанні кожного повідомлення WM_TIMER, а при одержанні 10 повідомлень WM_TIMER, програма змінює колір робочої області з блакитного на червоний чи з червоного на голубой і, викликаючи функцію MessageBeep, видає гудок.

Зовнішній вигляд програми буде наступним:

Рисунок 2.5 Зовнішній вигляд програми TIMER

Створення додатка, що використовує таймер.

  1. Створіть новий проект TIMER. Потім додайте до проекту файл типу C++ Source File за назвою timer.cpp.

  2. Тепер цілком скопіюйте уміст файлу sample.cpp, що був створений у Лабораторній роботі №1 у timer.cpp.

  3. Крім заголовного файлу windows.h не знадобляться ніякі інші заголовні файли.

  4. Функцію WinMain варто піддати наступним незначним змінам:

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

HWND hWnd;

MSG msg ;

WNDCLASS wndclass ;

static char szAppName[] = " Beeper1" ;

RegisterClass (&wndclass) ;

hWnd = CreateWindow (szAppName, " Simple Counter", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,hInstance, NULL) ;

Крім цього, тому що ми будемо використовувати таймер, то потрібно установити його. А разом з цим можна зробити перевірку на наявність доступних таймерів. У ранніх версіях Windows у кожен конкретний момент часу у всій системі могли бути активними тільки 16 таймерів. Користувачі Windows швидко визначили це, намагаючись запустити як найбільше програм Clock. Спроба запустити програму 17 разів приводила до появи повідомлення про помилку "No more clocks or timers" (Немає доступних таймерів). Хоча Windows 3.0 подвоїла кількість припустимих таймерів до 32, а Windows 95 практично взагалі зняла які б те ні було обмеження, включення обробки помилок у програмі Windows як і раніше вважається гарним стилем програмування. Розглянемо обробку таких ситуацій.

Якщо немає доступних таймерів, значенням що повертається функцією SetTimer є NULL. Наша програма могла б нормально працювати і без таймера, але тому що таймер нам просто необхідний, то в додатка не залишається вибору, як тільки завершитися через неможливість працювати. Якщо ви викликаєте в WinMain функцію SetTimer, то ви можете завершити свою програму, просто повертаючи FALSE з WinMain. Але це некрасивий спосіб завершення програми. Користувач залишиться в неведенні, чому не завантажується його додаток. Набагато зручніше — і набагато простіше — для виводу повідомлення на екран використовувати вікно повідомлень Windows.

Вікно повідомлень (створюється за допомогою функції MessageBox()) — це спливаюче вікно, що з'являється завжди в центрі екрана. У вікнах повідомлень є рядок заголовка, але немає рамки, що дозволяє змінювати розміри вікна. Рядок заголовка звичайно містить ім'я додатка. Вікно повідомлень містить у собі саме повідомлення й одну, дві чи три кнопки (які-небудь сполучення кнопок OK, Retry, Cancel, Yes, No і інших). У вікні повідомлень може також знаходитися раніше визначений значок: рядкове "i" (що означає "information" — інформація), окличний, питальний чи забороняючий знаки. Останній являє собою білий символ X на червоному фоні (як дійсний знак "стіп"). Ви, імовірно, уже бачили безліч вікон повідомлень при роботі з Windows.

За замовчуванням вікна повідомлень є "модальними вікнами додатка" (application modal). Це означає, що користувач повинний якось відреагувати на вікно повідомлень перед тим, як додаток продовжить роботу. Однак, користувач може переключитися на інші додатки. Отже, чому б ні дати користувачу можливість закрити один з додатків, що використовують таймер, і тоді вже успішно завантажити свій додаток за допомогою наступного коду:

#include <windows.h>

#define ID_TIMER 1

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

PSTR szCmdLine, int iCmdShow)

{

hwnd = CreateWindow (szAppName, "Simple Counter",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, NULL, hInstance, NULL) ;

while (!SetTimer (hwnd, ID_TIMER, 1000, NULL))

if (IDCANCEL == MessageBox (hwnd,

"Too many clocks or timers!", szAppName,

MB_ICONEXCLAMATION | MB_RETRYCANCEL))

return FALSE ;

ShowWindow (hwnd, iCmdShow) ;

UpdateWindow (hwnd) ;

Вікно повідомлень, створюване в даному фрагменті коду, має дві кнопки з написами Retry і Cancel. Якщо користувач клацає на кнопці Cancel, функція MessageBox повертає значення рівне IDCANCEL, і програма завершується. Якщо користувач клацає на кнопці Retry, функція SetTimer викликається знову.

Рис. Вікно повідомлень, що пропонує вибір

  1. Функцію WndProc необхідно піддати більш ретельній обробці. Т.к. програма містить таймер, то в програмі потрібно обробляти повідомлення від таймера WM_TIMER:

#include <windows.h>

#define ID_TIMER 1

static int count=0,count2=0;

char buf[3]="";

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {

HDC hdc ;

PAINTSTRUCT ps ;

RECT rc ;

static BOOL fFlipFlop = FALSE ;

switch (iMsg)

{

case WM_TIMER:

count+=1;

count2+=1;

if (count2==10){count2=0;fFlipFlop = !fFlipFlop ;}

itoa(count,buf,10);

InvalidateRect (hwnd, NULL, FALSE) ;

return 0 ;

case WM_PAINT :

hdc = BeginPaint (hwnd, &ps) ;

У даному фрагменті коду створюється два лічильники: count для підрахунку секунд і count2 для організації зміни кольору робочої області з блакитного на червоний чи з червоного на голубой через кожні 10 секунд. Для зміни кольору використовується прапор fFlipFlop. Для повного розуміння роботи програми, розглянемо обробку повідомлення WM_PAINT.

  1. Для обробки повідомлення WM_PAINT внесіть у функцію WndProc наступний код:

#include <windows.h>

#define ID_TIMER 1

static int count=0,count2=0;

char buf[3]="";

static char textscreen[80] = "Count: seconds" ;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {

HDC hdc ;

PAINTSTRUCT ps ;

RECT rc ;

static BOOL fFlipFlop = FALSE ;

HBRUSH hBrush ;

switch (iMsg)

{

case WM_TIMER:

case WM_PAINT :

hdc = BeginPaint (hwnd, &ps) ;

GetClientRect (hwnd, &rc) ;

hBrush = CreateSolidBrush (fFlipFlop ? RGB(255,0,0) : RGB(0,0,255)) ;

FillRect (hdc, &rc, hBrush) ;

TextOut(hdc, 100, 40, textscreen, strlen(textscreen));

TextOut(hdc, 150, 40, buf, strlen(buf));

EndPaint (hwnd, &ps) ;

DeleteObject (hBrush) ;

return 0 ;

У нашій програмі для зміни кольору робочої області використовується кисть. Кисті використовуються для заповнення умісту фігур, що малюються. Використання кисті визначає колір і зразок заповнення. За замовчуванням у контексті робочої області вікна встановлена кисть чорного кольору і суцільного заливання. Для створення кольорової суцільної кисті використовується функція CreateSolidBrush(). Як аргумент якої використовується значення кольору. У розглянутій програмі, значення кольору буде задаватися прапором fFlipFlop: якщо значення fFlipFlop = 1, то колір фону буде червоним (RGB(255,0,0)), у противному випадку, колір фону буде синім (RGB(0,0,255)). Потім, коли кисть створена, зафарбовування фона здійснюється функцією FillRect(). У загальному вигляді ця функція виглядає в такий спосіб:

int FillRect (

HDC hDC, // дескриптор контексту пристрою

CONST RECT *lprc, // покажчик на структуру з прямокутником

HBRUSH hbr // дескриптор кисті

);

Потім за допомогою функції TextOut() здійснюється вивід тексту на екран у наступному виді: «Count: XX seconds».

І, нарешті, в обробці повідомлення WM_PAINT, варто видалити створену раніше кисть. Це здійснюється за допомогою функції DeleteObject().

  1. Тому що наша програма використовує таймер, то по завершенні програми таймер варто звільнити. Для цього в програму додайте наступну інструкцію:

case WM_DESTROY :

KillTimer (hwnd, ID_TIMER) ;

PostQuitMessage (0) ;

return 0 ;

Запустіть програму на виконання.

ПРАКТИЧНА ЧАСТИНА

  1. Виконаєте програму counter, описану в лабораторній роботі.

  1. Створіть програму, при запуску якої створюється м'яч, що скаче по робочій області вікна. Для завдання темпу стрибків м'яча в програмі використовуйте таймер. Сам м'яч є бітовим образом. Спочатку програма створює м'яч шляхом створення бітового образа, що вона вибирає в контекст пам'яті, а потім викликає прості функції GDI. Програма малює растровий м'яч на екрані шляхом передачі блоку бітів з іншого контексту пам'яті.

Контрольні питання:

  1. Як додаток може встановити таймер? Що відбувається після його встановки?

  2. Яким способом можна змусити Windows посилати повідомлення таймера звичайній віконній процедурі додатка?

  3. Яким способом можна змусити Windows посилати повідомлення невіконним функціям додатка? Яка це повинна бути функція? Чому?

  4. Що таке ідентифікатор таймера? Для чого при обробці повідомлень від таймера варто перевіряти переданий разом з повідомленням ідентифікатор таймера?

Соседние файлы в папке Lab_progr_Win