В этой статье речь пойдёт о буфере и о таймере отсчёта.
Для начала убедитесь, что Вы разбираетесь в выделении памяти с помощью функции alloc (malloc), free, с помощью операторов new, delete и понимаете функцию преобразованию itoa().
Рассмотрим листинг, представленный ниже:
LRESULT CALLBACK WindowProcess(HWND hWindow, UINT uMessage, WPARAM wParameter, LPARAM lParameter) { HDC hDeviceContext; PAINTSTRUCT paintStruct; RECT rectPlace; HFONT hFont; static PTCHAR text; static int size = 0; switch (uMessage) { case WM_CREATE: text=(PTCHAR)GlobalAlloc(GPTR,50000*sizeof(TCHAR)); break; case WM_PAINT: hDeviceContext = BeginPaint(hWindow, &paintStruct); GetClientRect(hWindow, &rectPlace); SetTextColor(hDeviceContext, NULL); hFont=CreateFont(50,0,0,0,0,0,0,0, DEFAULT_CHARSET, 0,0,0,VARIABLE_PITCH, "Arial Bold"); SelectObject(hDeviceContext,hFont); if(wParameter != VK_RETURN) DrawText(hDeviceContext, (LPCSTR)text, size, &rectPlace, DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hWindow, &paintStruct); break; case WM_CHAR: switch(wParameter) { case VK_RETURN: size=0; break; default: text[size]=(char)wParameter; size++; break; } InvalidateRect(hWindow, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(NULL); GlobalFree((HGLOBAL)text); break; default: return DefWindowProc(hWindow, uMessage, wParameter, lParameter); } return NULL; }
Результат после ввода CppStudio.com будет таким:
Код для функции WinMain
не приводится, так как он не менялся с предыдущих уроков.
Данная программа позволяет вводить текст по мере возможности и стирать его клавишей ENTER.
Наверное, Вы заметили, что в программе в предыдущем уроке для считывания нажатой клавиши мы использовали message WM_KEYDOWN
, а здесь что-то новое — WM_CHAR
.
Отличительная особенность в том, что WM_KEYDOWN
нужен для обработки специальных клавиш типа shift, ctrl и т.п., а WM_CHAR
– отвечает за обработку символов. Обычно они работают вместе для комбинаций клавиш и вызывают друг друга. В этом Вы убедитесь, когда мы будем разбирать работу текстового редактора.
По умолчанию в MVS используется Юникод. Его отключение производится следующим образом: заходим в свойства проекта
и отключаем Юникод, нажав «Использовать многобайтовую кодировку».
После того, как Вы это сделаете, перед строками не нужно будет писать L, и представленный код не будет иметь ошибок. По этой причине в программе прошлого урока было не правильное отображение некоторых символов.
Теперь второе отличие: мы можем вводить текст (примерно до 50 кБ), который сохранится в буфере.
Конструкция создания, использования, удаления буфера выглядит так:
static PTCHAR text; text=(PTCHAR)GlobalAlloc(GPTR,50000*sizeof(TCHAR)); if() { //.... // заполняем буфер информацией, используем её, где нам нужно //..... GlobalFree((HGLOBAL)text); }
Она аналогична alloc()
и free()
и её смысл абсолютно такой же.
PTCHAR — указатель на тип TCHAR
.
GPTR — режим выделения памяти (в данном случае фиксированное)
HGLOBAL — тип возвращаемого значения функции GlobalAlloc()
Третье достоинство нашей программы — возможность стирать текст (строки 36-38).
В случае нажатия клавиши ENTER – мы делаем окно не действительным с помощью функции InvalidateRect()
(строка 44), тем самым вызываем сообщение WM_PAINT
. В нём прописано, что если параметр wParameter
был равен VK_RETURN
(то есть ENTER), то мы перерисовываем окно и не вызываем функцию DrawText()
.
И, как и обещалось ранее, добавим в функцию таймер и некоторые другие особенности.
static int sec = 0; TCHAR workTime[10]; //... switch (wParameter) { case WM_CREATE: SetTimer(hWindow, 1, 1000, NULL); //... SetForegroundWindow(hWindow); break; case WM_CHAR: //... case VK_BACK: if(size!=0) size--; break; case WM_TIMER: sec++; break; case WM_DESTROY: KillTimer(hWindow, 1); _itoa(sec, workTime, 10); MessageBox(NULL, (LPCSTR)workTime, "Время работы программы (сек.):", MB_ICONASTERISK|MB_OK); //... break; }
Добавьте в соответствующие места программы выше представленный код.
Функция SetTimer()
создаёт таймер. Первый параметр — дескриптор окна, третий — интервал срабатывания WM_TIMER
в миллисекундах, второй — количество вызовов WM_TIMER
в заданный интервал времени. Четвёртый параметр — нам не нужен.
В сообщении WM_TIMER
мы увеличиваем sec
на единицу.
Функция KillTimer()
— удаляет таймер. Параметры те же, что и в SetTimer()
.
Чтобы отобразить время работы программы, в WM_DESTROY
мы преобразовываем int
в TCHAR
массив при помощи функции _itoa
, выводим строку на экран, удаляем таймер и освобождаем память, выделенную под буфер.
Функция SetForegroundWindow(HWND)
– делает окно активным. Например, если Вы находитесь на сайте CppStudio.com и при этом идёт компиляция данной программы, это окно появится поверх браузера с фокусом для ввода.
Для возможности удаления одного или нескольких символов добавлен обработчик VK_BACK
– нажатие клавиши backspace. Если size
не равен нулю (то есть не был нажат ENTER), мы уменьшаем его на единицу и последний элемент при обновлении окна не отображается.
В результате, при закрытии окна, мы получим такое сообщение:
До встречи в следующем уроке!
Комментарии
Achez
Нужно хорошо разобраться в исходнике, чтобы понять, куда что добавлять. Однако же у меня получилось.
Elz
Будет ли продолжение?
Очень интересные и простые в понимании статьи! Спасибо!
Gosha
Надо так делать:
Иначе утечка памяти будет. И в предыдущей статье тоже.