Ввод и вывод данных Win32 API

В этой статье мы научимся обрабатывать данные, поступающие с клавиатуры. В дальнейшем это будет полезным пособием при создании простейшего текстового редактора типа notepad.exe.

Ниже представлен листинг:

#include <windows.h> 

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

int WINAPI WinMain(HINSTANCE hInst, 
	               HINSTANCE hPrevInst, 
				   LPSTR pCommandLine, 
				   int nCommandShow){ 
	TCHAR className[] = L"Мой класс"; 
	HWND hWindow; 
	MSG message; 
	WNDCLASSEX windowClass;

	windowClass.cbSize        = sizeof(windowClass); 
	windowClass.style         = CS_HREDRAW | CS_VREDRAW; 
	windowClass.lpfnWndProc   = WindowProcess; 
	windowClass.lpszMenuName  = NULL; 
	windowClass.lpszClassName = className; 
	windowClass.cbWndExtra    = NULL; 
	windowClass.cbClsExtra    = NULL; 
	windowClass.hIcon         = LoadIcon(NULL, IDI_WINLOGO); 
	windowClass.hIconSm       = LoadIcon(NULL, IDI_WINLOGO); 
	windowClass.hCursor       = LoadCursor(NULL, IDC_ARROW); 
	windowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 
	windowClass.hInstance     = hInst; 

	if(!RegisterClassEx(&windowClass))
	{
		MessageBox(NULL, L"Не получилось зарегистрировать класс!", L"Ошибка", MB_OK);
		return NULL; 
	}
	hWindow = CreateWindow(className, 
		                   L"Программа ввода символов", 
						   WS_OVERLAPPEDWINDOW, 
						   CW_USEDEFAULT, 
						   NULL,
						   CW_USEDEFAULT,
						   NULL, 
						   (HWND)NULL, 
						   NULL, 
						   HINSTANCE(hInst), 
						   NULL
						  );
	if(!hWindow){
		MessageBox(NULL, L"Не получилось создать окно!", L"Ошибка", MB_OK);
		return NULL;
	}
	ShowWindow(hWindow, nCommandShow); 
	UpdateWindow(hWindow); 
	while(GetMessage(&message, NULL, NULL, NULL)){
		TranslateMessage(&message); 
		DispatchMessage(&message); 
	}
	return message.wParam; 
}

LRESULT CALLBACK WindowProcess(HWND hWindow, 
	                           UINT uMessage, 
							   WPARAM wParameter, 
							   LPARAM lParameter)
{
	HDC hDeviceContext;
	PAINTSTRUCT paintStruct;
	RECT rectPlace;
	HFONT hFont;
	static char text[2]={' ','\0'};
	switch (uMessage)
	{
	case WM_CREATE:
		MessageBox(NULL, 
		      L"Пожалуйста, вводите символы и они будут отображаться на экране!",
		      L"ВНИМАНИЕ!!!", MB_ICONASTERISK|MB_OK);
		break;
	case WM_PAINT: 
		hDeviceContext = BeginPaint(hWindow, &paintStruct);
		GetClientRect(hWindow, &rectPlace); 
		SetTextColor(hDeviceContext, NULL); 
		hFont=CreateFont(90,0,0,0,0,0,0,0,
						 DEFAULT_CHARSET,
						 0,0,0,0,
						 L"Arial Bold"
						 );
		SelectObject(hDeviceContext,hFont);
		DrawText(hDeviceContext, (LPCWSTR)text, 1, &rectPlace, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
		EndPaint(hWindow, &paintStruct);
		break;
	case WM_KEYDOWN:
		switch (wParameter)
		{
		case VK_HOME:case VK_END:case VK_PRIOR:
		case VK_NEXT:case VK_LEFT:case VK_RIGHT:
		case VK_UP:case VK_DOWN:case VK_DELETE:
		case VK_SHIFT:case VK_SPACE:case VK_CONTROL:
		case VK_CAPITAL:case VK_MENU:case VK_TAB:
		case VK_BACK:case VK_RETURN:
			break;
		default:
		text[0]=(char)wParameter;
		InvalidateRect(hWindow, NULL, TRUE);
		break;
		}break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWindow, uMessage, wParameter, lParameter);
	}
	return NULL;
}

Данная программа выводит цифры и буквы, при этом не реагирует на нажатие дополнительных клавиш, типа enter, shift и т.д.

В функции WinMain() ничего нового. А в WindowProcess() мы добавили обработчики событий нажатия клавиши.

Нажатие  любой клавиши автоматически посылает системе аппаратное сообщение, которое обрабатывается и высылается приложению. За эту операцию отвечает сообщение WM_KEYDOWN.

Его описание сложно и на данном этапе не имеет смысла, так как мы не включили кириллицу. При посылке этого сообщения в wParameter записывается значение нажатой клавиши. Конечно же, всё зависит от клавиатуры, раскладки. Поэтому всего кодов для клавиш много и мы не будем описывать, что делать при нажатии той или иной, а просто исключим значения не нужных нам клавиш.

С 87-й по 101-ю строки мы обрабатываем сообщение WM_KEYDOWN (нажатие клавиши). Сначала мы создаём переключатель switch для значения wParameter, куда записан идентификатор клавиши. С 90-й по 95-ю строки мы исключаем значения home, end, page up, page down, стрелка влево, стрелка вправо, стрелка вверх, стрелка вниз, delete, shift, space, ctrl, caps lock, alt, tab, backspace, enter соответственно. Возможно, на вашей клавиатуре есть ещё клавиши, вы можете также их исключить  при необходимости, потому что при нажатии будет «абракадабра». То есть если в идентификаторе wParameter у нас эти значения, мы ничего не делаем – в 96-й строке оператор break.

А под значениями default у нас выполняется преобразование. В 66 строке мы создали статическую строку типа char из 2-х элементов. Статическая она, потому что в процессе работы программы мы неоднократно выходим из WindowProcess() в цикл обработки с GetMessage(), расположенный в WinMain(), а значение клавиши нам нужно сохранять. Ну а в 98 строке мы инициализируем её первый элемент wParameter-ом.

В следующей строке мы вызываем функцию InvalidateRect(), после чего выходим из WM_KEYDOWN. Первым параметром идёт – дескриптор окна, вторым – область будущего «затирания» окна (NULL –  всё окно перерисовывается в WM_PAINT), третьим параметром идёт «затирание» фона (если TRUE, то стираем). При этом мы автоматически посылаем приложению message WM_PAINT и окно перерисовывается заново. Для чего это нужно?

Как мы помним в случаях сворачивания, перемещения окна вызывается WM_PAINT. Нам же это нужно сделать явно, то есть сделать окно недействительным, для того, чтобы сразу вывести значение нажатой клавиши на экран. Иначе она появится только тогда, когда мы начнём манипулировать окном.

Теперь возвратимся 65-й строке. В ней объявлен экземпляр класса HFONT, который отвечает за шрифт, его размер и другие премудрости. Он будет использоваться в WM_PAINT.

В 69-й строке есть обработчик сообщения WM_CREATE. Он срабатывает, когда создаётся окно, то есть вызывается функция CreateWindow(). На этом этапе решено создать дополнительное окно с сообщением для удобства (строки 70-72).

Наконец, обработчик WM_PAINT. С 75-й по 77-ю строки происходит вызов функций контекста устройства (описывалось в статье).

А с 78-й по 82-ю строки вызывается функция CreateFont(). С её помощи мы меняем шрифт, и размер буквы. Вот её описание:

HFONT CreateFont(int,    // высота шрифта
                 int,    // ширина символов
                 int,    // угол наклона букв
                 int,    // угол наклона строки
                 int,    // толщина букв («жирность»)
                 DWORD,  // курсив
                 DWORD,  // подчеркивание
                 DWORD,  // перечеркивание
                 DWORD,  // набор символов
                 DWORD,  // точность вывода
                 DWORD,  // точность отсечения
                 DWORD,  // качество вывода
                 DWORD,  // шаг между буквами
                 LPCTSTR // имя шрифта
                );

Шрифт выставлен Arial Bold – то есть Arial жирным. В строке 83 мы задаём контексту изменённые параметры шрифта. С 84-й по 85-ю строки ничего нового. Мы вводим на экран полученный идентификатор клавиши, преобразованный в тип char. В функции DrawText() его нужно преобразовать к типу LPCWSTR, что она и требует.

Результат работы программы при вводе буквы «с» такой:

БезымянныйScreenshot_1

В следующей статье мы научимся обрабатывать дополнительные клавиши,  переключать раскладку,  создавать таймеры отсчёта.

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

Комментарии

  1. npavelFax

    Работа через интернет официальная работа.

  2. npavelFax

    Официальная работа в интернете с обучением.

  3. Fird

    Извините за нубский вопрос…
    Но как объединить это окно с программой?
    Вить если мы сделали красивое окно с кучей кнопок, но оно ничего не может само по себе.
    Не совсем понимаю как правильно сформировать вопрос, как получилось.

    • takeNmake

      Программа — это код, а окно — это результат работы программы. Объединить их невозможно. Может Вы имеете ввиду объединение двух программ? Что также не имеет смысла. Всё зависит от того, какие цели Вы преследуете. Если хотите создать многофункциональную программу, то нужно запастись терпением и научиться обрабатывать различные функции API. Конечный результат программы данного урока — будет текстовый редактор. И это полноценная программа, которую Вы сможете модифицировать и добавить в неё обработчик мыши, меню и т.п.
      Подробнее в следующих уроках.

  4. takeNmake

    а вообще в коде должно быть так: static char text[2]={‘ ‘,»};

  5. Крабь Апров

    у вас ошибка, в строке 66 там вы написали (static char text[2]={‘ ‘,»};) вы не поставили пробел во вторых ковычках, и читал как пустую, выдавая ошибку, или это только у меня? Во всяком случаее исправил, и работает

     

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

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