Итак, что же такое строка
состояния? Это небольшое окно, занимающее нижнюю часть главного окна приложения.
В большинстве программ под управлением Windows имеется строка состояния. В программе
Microsoft Internet Explorer в строке состояния отображаются текущие данные открытия
Web-страничек. Когда страничка полностью загружена, в строке состояния пишется:
"Готово". Когда вы наводите мышь на гиперссылку, текст в строке меняется
на текст этой ссылки. Некоторые Web-программисты пишут на языках Java и Java
Script небольшие шалости - например бегущая строка, в которое бегут процентики
и надпись: "Форматирование винчестера: 50% завершено". И число процентов
быстро возрастает.
Кроме того, часто в программах, предназначенных для длительного использования
- например в текстовых редакторах, часто в строке состояние показана текущая
дата, время и день недели.
В строке состояния также можно отображать маленькие иконки, подсказки и многое
другое.
Для удобства использования строки состояния вы можете разделить её на секции.
Например при работе с файлами вы можете в одной секции указывать размер файла,
а в другое - оставшееся свободное место на диске.
Стиль секций также может меняться. Текст может быть как вдавленным, так и выпуклым.
При перемещении главного окна, строка состояния должна перемещаться вместе с
ним и изменять размеры вместе с ним, растягиваясь или сужаясь.
Что можно делать со строкой состояния?
1. Создание строки
HWND CreateStatusWindow(LONG style, LPCSTR lpszText,
HWND hwndParent, UINT wID);
style - стиль окна
lpszText - указатель на текст в окне
hwndParent - родительское окно
wID - идентификатор строки состояния
2. Разделение строки на секции. Для разделение
строки состояния на секции, нужно создать массив с размерами разделителей:
int pParts[3];
cx=LOWORD(lParam);
pParts[0]=cx-200;
pParts[1]=cx-100;
pParts[2]=cx;
Потом мы посылаем сообщение SB_SETPARTS с указанием количества разделителей
и массива их длин.
SendMessage(hStatus, SB_SETPARTS, 3, (LPARAM)pParts);
3. Для вывода текста в строку состояния нужно послать сообщение SB_SETTEXT
с указанием ячейки (третий аргумент) и текста.
SendMessage(hStatus, SB_SETTEXT, 1, (LONG)Buf);
Итак, в путь!
1. Создайте новый проект типа Win32 Application. Назовите проект Status и нажмите
Ок. В следующем окне выберите "A typical Hello World Application".
Нажмите Finish. Ок.
2. В нашей программе в строке состояния, поделенной на секции будут отображаться
текущая дата и время. Для этого разделим строку состояния на три части. Текущие
дату и время мы будем получать каждую секунду с помощью системного таймера и
функции GetLocalTime().
3. Добавьте в список заголовочных файлов файл commctrl.h - библиотеку общих
элементов управления.
4. Выберите в меню Project->Add to Project->Files.... Укажите в окне "Открыть"
файл comctl32.lib, находящийся в папке: ...\Microsoft Visual Studio\VC98\Lib\.
В списке файлов должен появиться новый файл - статическая библиотка общих элементов
управления
5. В начале исходного кода программы добавьте макроопределение идентификатора
строки состояния:
#define ID_STATUS 200
6. В функции окна объявим следующие переменные:
static HWND hStatus; //идентификатор окна строки состояния
static int pParts[3]; //массив частей строки состояния
static short cx; //вспомогательная переменная для вычисления координат
SYSTEMTIME st; //структура
системной даты и времени
int day, month, year, sec, min, hour; //вспомогательные переменные
char Buf[256]; //строковый буфер
7. Для создания строки состояния
в обработчике сообщения WM_CREATE запишем:
hStatus=CreateStatusWindow(WS_CHILD|WS_VISIBLE, " ", hWnd, ID_STATUS);
Эта строка создаёт новое дочернее окно - строку состояния, родительским окном
которого является окно hWnd, а идентификатор ID_STATUS, объявленный выше.
Далее мы посылаем окну сообщение SB_SETTEXT, чтобы записать в первую секцию
слово "Готово".
SendMessage(hStatus, SB_SETTEXT, 0, (LONG)"Готово");
Здесь же надо инициализировать таймер.
SetTimer(hWnd, 1, 1000, NULL);
Здесь мы создали таймер, родительским окном которого является hWnd, идентификатор
1, период 1000 мс или 1 сек. Так как часы изменяют своё время с периодичностью
в 1 сек, следует задать именно этот период. Но если вы не хотите, чтобы часы
мигали каждую секунду, отвлекая и раздражая, можете изменить период на 3-5 сек.
case WM_CREATE:
hStatus=CreateStatusWindow(WS_CHILD|WS_VISIBLE, "Готово", hWnd, ID_STATUS);
SendMessage(hStatus, SB_SETTEXT, 0, (LONG)"Готово");
SetTimer(hWnd, 1, 1000, NULL);
break;
8. Но такая строка состояния будет существовать отдельной жизнью от главного
окна. Кроме того, мы не разделали её на части. Вставим в обработчик сообщения
WM_SIZE - изменение размеров главного окна функцию MoveWindow, которая будет
старательно перемещать строку состояния вслед за главным окном.
MoveWindow(hStatus, 0,0,0,0, TRUE);
Дальше мы узнаем ширину
главного окна:
cx=LOWORD(lParam);
Занесём в массив pParts координаты секций, на которые поделим строку состояния.
pParts[0]=cx-130;
pParts[1]=cx-60;
pParts[2]=cx;
Для разделения строки состояния на 3 перегородки, пошлём окну сообщение SB_SETPARTS.
Массив pParts - параметры перегородок.
SendMessage(hStatus, SB_SETPARTS, 3, (LPARAM)pParts);
//Измененеи размеров окна
case WM_SIZE:
MoveWindow(hStatus, 0,0,0,0, TRUE);
cx=LOWORD(lParam);
pParts[0]=cx-130;
pParts[1]=cx-60;
pParts[2]=cx;
SendMessage(hStatus, SB_SETPARTS, 3, (LPARAM)pParts);
break;
9. Уже почти всё готово.
Только наша строка не знает, который сейчас час. Напишем обработчик сообщения
WM_TIMER.
У нас уже создан экземпляр структуры SYSTEMTIME.
SYSTEMTIME st;
Функция GetLocalTime заполняет эту структуру текущими и датой и временем на
момент своего вызова.
GetLocalTime(&st);
Запишем в наши переменные значения этих полей:
day=st.wDay;
month=st.wMonth;
year=st.wYear;
hour=st.wHour;
min=st.wMinute;
sec=st.wSecond;
Запишем в буфер эти значения и запишем в секцию текст буфера:
sprintf(Buf, "%02d:%02d:%02d", day, month, year);
SendMessage(hStatus, SB_SETTEXT, 1, (LONG)Buf);
Вот, как выглядит этот обработчик целиком:
case WM_TIMER:
GetLocalTime(&st);
day=st.wDay;
month=st.wMonth;
year=st.wYear;
hour=st.wHour;
min=st.wMinute;
sec=st.wSecond;
sprintf(Buf, "%02d:%02d:%02d", day, month, year);
SendMessage(hStatus, SB_SETTEXT, 1, (LONG)Buf);
sprintf(Buf, "%02d:%02d:%02d", hour, min, sec);
SendMessage(hStatus, SB_SETTEXT, 2, (LONG)Buf);
break;
10. Удалите обработчик сообщения
WM_PAINT, который нам не потребуется.
11. Вот, как выглядит функция окна целиком:
//Функция окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static short cx; //вспомогательная переменная
static int pParts[3]; //массив частей строки состояния
static HWND hStatus; //идентификатор окна
SYSTEMTIME st; //экземпляр структуры
int day, month, year, sec, min, hour; //переменные даты и времени
char Buf[256]; //строковый буфер
switch (message)
{
//Изменение размеров окна
case WM_SIZE:
MoveWindow(hStatus, 0,0,0,0, TRUE);
cx=LOWORD(lParam);
pParts[0]=cx-130;
pParts[1]=cx-60;
pParts[2]=cx;
SendMessage(hStatus, SB_SETPARTS, 3, (LPARAM)pParts);
break;
case WM_CREATE:
hStatus=CreateStatusWindow(WS_CHILD|WS_VISIBLE, "Готово", hWnd, ID_STATUS);
SendMessage(hStatus, SB_SETTEXT, 0, (LONG)"Готово");
SetTimer(hWnd, 1, 1000, NULL);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
//Обработка элементов меню
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
//Сообщение таймера
case WM_TIMER:
GetLocalTime(&st);
day=st.wDay;
month=st.wMonth;
year=st.wYear;
hour=st.wHour;
min=st.wMinute;
sec=st.wSecond;
sprintf(Buf, "%02d:%02d:%02d", day, month, year);
SendMessage(hStatus, SB_SETTEXT, 1, (LONG)Buf);
sprintf(Buf, "%02d:%02d:%02d", hour, min, sec);
SendMessage(hStatus, SB_SETTEXT, 2, (LONG)Buf);
break;
case WM_DESTROY:
PostQuitMessage(0);
KillTimer(hWnd,1);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
12. Запустите программу!