Ввод и вывод текста. Буфер памяти, таймер отсчёта

В этой статье речь пойдёт о буфере и о таймере отсчёта.

Для начала убедитесь, что Вы разбираетесь в выделении памяти с помощью функции 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 будет таким:

Скрин 1

Код для функции WinMain не приводится, так как он не менялся с предыдущих уроков.
Данная программа позволяет вводить текст по мере возможности и стирать его клавишей ENTER.

Наверное, Вы заметили, что в программе в предыдущем уроке для считывания нажатой клавиши мы использовали message WM_KEYDOWN, а здесь что-то новое — WM_CHAR.

Отличительная особенность в том, что WM_KEYDOWNнужен для обработки специальных клавиш типа shift, ctrl и т.п., а WM_CHAR– отвечает за обработку символов. Обычно они работают вместе для комбинаций клавиш и вызывают друг друга. В этом Вы убедитесь, когда мы будем разбирать работу текстового редактора.

По умолчанию в MVS используется Юникод. Его отключение производится следующим образом: заходим в свойства проекта

Скрин_ЮК_1

и отключаем Юникод, нажав «Использовать многобайтовую кодировку».

Скрин_ЮК_2

После того, как Вы это сделаете, перед строками не нужно будет писать 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), мы уменьшаем его на единицу и последний элемент при обновлении окна не отображается.

В результате, при закрытии окна, мы получим такое сообщение:

Скрин 2

До встречи в следующем уроке!

Автор: Marienko L.
Дата: 09.04.2014
Поделиться:

Комментарии

  1. Achez

    Achez

    Добавьте в соответствующие места программы выше представленный код.

    Нужно хорошо разобраться в исходнике, чтобы понять, куда что добавлять. Однако же у меня получилось.

  2. Elz

    Будет ли продолжение?

    Очень интересные и простые в понимании статьи! Спасибо!

  3. Gosha

    Надо так делать:

    HFONT hOldFont;//Добавили новую переменную
    ................................................
    //Строку SelectObject(hDeviceContext,hFont) заменяем на:
    hOldFont=static_cast<HFONT>(SelectObject(hDeviceContext,hFont));//Запомнили старый шрифт
    ................................................
    //Перед  EndPaint добавляем строки:
    SelectObject(hDeviceContext,hOldFont);//Вернули старый шрифт
    DeleteObject(hFont);//Удалили шрифт созданный через CreateFont

    Иначе утечка памяти будет. И в предыдущей статье тоже.

Оставить комментарий

Вы должны войти, чтобы оставить комментарий.