Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

240

Такой метод установки таймера используется редко. Он удобен, если в программе в разное время делается много вызовов функции SetTimer, и при этом не запоминаются те таймерные идентификаторы, которые уже использовались.

Теперь, поскольку вы знаете, как использовать таймер в Windows, вы готовы к знакомству с парой полезных программ, использующих таймер.

Использование таймера для часов

Часы — это наиболее очевидное применение таймера, поэтому давайте рассмотрим два типа часов, одни цифровые, другие аналоговые. Программа DIGCLOCK, представленная на рис. 7.5, создает всплывающее окно, которое позиционируется в верхнем правом углу экрана. Программа выводит день недели, дату и время, как показано на рис. 7.6.

DIGCLOCK.MAK

#------------------------

# DIGCLOCK.MAK make file

#------------------------

digclock.exe : digclock.obj

$(LINKER) $(GUIFLAGS) -OUT:digclock.exe digclock.obj $(GUILIBS)

digclock.obj : digclock.c $(CC) $(CFLAGS) digclock.c

DIGCLOCK.C

/*-----------------------------------------

 

DIGCLOCK.C --

Digital Clock Program

 

(c) Charles Petzold, 1996

-----------------------------------------

*/

#include <windows.h> #include <time.h>

#define ID_TIMER

1

#define YEAR (datetime->tm_year % 100) #define MONTH(datetime->tm_mon + 1) #define MDAY (datetime->tm_mday) #define WDAY (datetime->tm_wday) #define HOUR (datetime->tm_hour) #define MIN (datetime->tm_min) #define SEC (datetime->tm_sec)

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void SizeTheWindow(int *, int *, int *, int *);

char sDate[2], sTime[2], sAMPM[2][5]; int iDate, iTime;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

static char szAppName[] = "DigClock";

HWND

hwnd;

MSG

msg;

int

xStart, yStart, xClient, yClient;

WNDCLASSEX

wndclass;

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= 0;

wndclass.hInstance

= hInstance;

241

wndclass.hIcon

= NULL;

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szAppName;

wndclass.hIconSm

= NULL;

RegisterClassEx(&wndclass);

SizeTheWindow(&xStart, &yStart, &xClient, &yClient); hwnd = CreateWindow(szAppName, szAppName,

WS_POPUP | WS_DLGFRAME | WS_SYSMENU, xStart, yStart,

xClient, yClient,

NULL, NULL, hInstance, NULL);

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

{

MessageBox(hwnd, "Too many clocks or timers!", szAppName,

MB_ICONEXCLAMATION | MB_OK);

return FALSE;

}

ShowWindow(hwnd, SW_SHOWNOACTIVATE);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

void SizeTheWindow(int *pxStart, int *pyStart, int *pxClient, int *pyClient)

{

HDC hdc;

TEXTMETRIC tm;

hdc = CreateIC("DISPLAY", NULL, NULL, NULL); GetTextMetrics(hdc, &tm);

DeleteDC(hdc);

*pxClient =

2

* GetSystemMetrics(SM_CXDLGFRAME)

+

16*tm.tmAveCharWidth;

*pxStart

=

 

GetSystemMetrics(SM_CXSCREEN)

-

*pxClient;

*pyClient =

2

* GetSystemMetrics(SM_CYDLGFRAME) + 2*tm.tmHeight;

*pyStart

=

 

0;

 

 

}

 

 

 

 

 

void SetInternational(void)

{

static char cName [] = "intl";

iDate = GetProfileInt(cName, "iDate", 0);

iTime = GetProfileInt(cName, "iTime", 0);

GetProfileString(cName, "sDate",

"/",

sDate,

2);

GetProfileString(cName, "sTime",

":",

sTime,

2);

GetProfileString(cName, "s1159", "AM",

sAMPM[0], 5);

GetProfileString(cName, "s2359", "PM", sAMPM[1], 5);

}

void WndPaint(HWND hwnd, HDC hdc)

{

242

static char szWday[] = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";

char

cBuffer[40];

 

 

 

 

int

iLength;

 

 

 

 

 

RECT

rect;

 

 

 

 

 

struct tm

*datetime;

 

 

 

 

time_t

lTime;

 

 

 

 

 

time(&lTime);

 

 

 

 

 

datetime = localtime(&lTime);

 

 

 

iLength = wsprintf(cBuffer, " %s %d%s%02d%s%02d

\r\n",

(PSTR) szWday + 4 * WDAY,

 

 

 

 

iDate == 1

? MDAY

: iDate ==

2

? YEAR

: MONTH,(PSTR) sDate,

 

iDate == 1

? MONTH : iDate ==

2

? MONTH : MDAY, (PSTR) sDate,

 

iDate == 1

? YEAR

: iDate ==

2

? MDAY

: YEAR);

if(iTime == 1)

iLength += wsprintf(cBuffer + iLength, " %02d%s%02d%s%02d ", HOUR,(PSTR) sTime, MIN,(PSTR) sTime, SEC);

else

iLength += wsprintf(cBuffer + iLength, " %d%s%02d%s%02d %s ", (HOUR % 12) ?(HOUR % 12) : 12,

(PSTR) sTime, MIN,(PSTR) sTime, SEC, (PSTR) sAMPM [HOUR / 12]);

GetClientRect(hwnd, &rect);

DrawText(hdc, cBuffer, -1, &rect, DT_CENTER | DT_NOCLIP);

}

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

{

HDC hdc;

PAINTSTRUCT ps;

switch(iMsg)

{

case WM_CREATE : SetInternational(); return 0;

case WM_TIMER :

InvalidateRect(hwnd, NULL, FALSE); return 0;

case WM_PAINT :

hdc = BeginPaint(hwnd, &ps); WndPaint(hwnd, hdc); EndPaint(hwnd, &ps);

return 0;

case WM_WININICHANGE : SetInternational(); InvalidateRect(hwnd, NULL, TRUE); return 0;

case WM_DESTROY : KillTimer(hwnd, ID_TIMER); PostQuitMessage(0); return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

Рис. 7.5 Программа DIGCLOCK

243

Рис. 7.6 Окно программы DIGCLOCK

Во всех приведенных до сих пор программах использовался стиль окна WS_OVERLAPPEDWINDOW в качестве третьего параметра функции CreateWindow. В программе DIGCLOCK используется стиль окна:

WS_POPUP | WS_DLGFRAME | WS_SYSMENU

Это выражение задает "всплывающее" (popup) окно с рамкой окна диалога и системным меню. Стиль всплывающего окна чаще используется в окнах диалога и окнах сообщений, и очень редко для приложений. Кроме этого в программе DIGCLOCK используется еще и другой вариант вызова функции ShowWindow:

ShowWindow(hwnd, SW_SHOWNOACTIVATE);

Обычно окно программы становится активным при запуске. SW_SHOWNOACTIVATE сообщает Windows о том, что программа DIGCLOCK не должна изменять активное окно. Однако вы можете сделать активным окно DIGCLOCK, щелкнув на нем мышью, или нажав клавиши <Alt>+<Tab> или <Alt>+<Esc>. Хотя в программе DIGCLOCK нет символа системного меню, но если она активна, вы по-прежнему можете получить доступ к системному меню, нажимая комбинацию клавиш <Alt>+<Spacebar> (<Alt>+<пробел>).

Позиционирование и изменение размеров всплывающего окна

Всплывающее окно программы DIGCLOCK устанавливается в верхнем правом углу экрана. Окно должно быть достаточно большим, чтобы вместить две строки текста по 16 символов в каждой. Процедура SizeTheWindow в DIGCLOCK.С определяет подходящие параметры для использования их при вызове функции CreateWindow. Обычно программа не может получить размер текста без предварительного создания самого окна, поскольку описатель окна нужен для получения описателя контекста устройства. Программе DIGCLOCK удается обойти эту проблему путем получения информации об экране из описателя контекста устройства с помощью функции CreateIC. Эта функция похожа на функцию CreateDC, обычно используемую для создания контекста принтера (как будет показано в главе 15), но эта функция используется для получения информации из контекста устройства. Размера текста в сочетании с информацией, полученной от GetSystemMetrics, достаточно для получения начального положения и размеров окна.

Получение даты и времени

В своей функции WndPaint программа DIGCLOCK использует функции языка С time и locatetime для определения текущих даты и времени. Функция locatetime помещает всю необходимую вам информацию в структуру; несколько макроопределений в начале программы помогают сделать вызовы wsprintf более читаемыми. (Вы должны избегать выполнения функций MS-DOS и ROM BIOS в вашей программе для Windows; вместо этого пользуйтесь функциями Windows или библиотекой языка С периода выполнения.)

Обеспечение международной поддержки

Windows обеспечивает международную поддержку. Файл WIN.INI, создаваемый при инсталляции Windows, содержит раздел, озаглавленный [intl]. Это список информации, относящейся к формату даты, времени, валюты и чисел. Вы можете выводить на экран даты в одном из трех разных форматов: месяц-день-год, год-месяц-день или день-месяц-год. Разделителем между этими тремя числами может быть наклонная черта, тире, точка или, фактически, любой понравившийся вам символ. Вы можете выводить время либо в 12-ти, либо в 24-часовом формате; для разделения часов, минут и секунд обычно используется точка или двоеточие.

Функция SetInternational в DIGCLOCK извлекает эту информацию для форматирования из WIN.INI с помощью функций GetProfileInt (для целых) и GetProfileString (для строк). Эти вызовы должны содержать значения по умолчанию, если Windows не сможет найти требуемые значения в WIN.INI. Функция SetInternational сохраняет эти значения в глобальных переменных, имеющих такие же имена, что и текстовые строки, которые идентифицируют их в WIN.INI. Функция WndPaint использует эти значения, полученные из WIN.INI, для форматирования выводимых на экран даты и времени, а затем вызывает функцию DrawText для выравнивания двух строк текста в окне.

Независимо от времени получения сообщения WM_TIMER, оконная процедура программы DIGCLOCK, для выработки сообщения WM_PAINT, делает окно недействительным. Но WndProc также делает окно недействительным при получении сообщения WM_WININICHANGE. Любое приложение, которое изменяет файл WIN.INI, посылает сообщение WM_WININICHANGE всем активным приложениям Windows. Если секция [intl]

Соседние файлы в предмете Операционные системы