Пример ниже демонстрирует, как использовать каретку в простом редакторе текста. Пример обновляет позицию каретки, поскольку пользователь вводит с клавиатуры печатный знаки и использует различные клавиши, чтобы перемещаться по рабочей области.
Демонстрационный пример
#define TEXTMATRIX(x, y) *(pTextMatrix + (y * nWindowCharsX) + x)
// Глобальные переменные.
HINSTANCE hinst; // текущий экземпляр
HBITMAP hCaret; // точечный рисунок каретки
HDC hdc; // контекст устройства
PAINTSTRUCT ps; // рабочая область для рисования
static char *pTextMatrix = NULL; // указатель на матрицу текста
static int nCharX, // ширина знака в логических ед.
nCharY, // высота знака в логических ед.
nWindowX, // ширина рабочей области
nWindowY, // высота рабочей области
nWindowCharsX, // ширина знакоместа
nWindowCharsY, // высота знакоместа
nCaretPosX, // x-позиция каретки
nCaretPosY; // y-позиция каретки
static UINT uOldBlink; // предыдущая частота мерцания
int x, y; // координаты матрицы текста
TEXTMETRIC tm; // информация о шрифте
LONG APIENTRY MainWndProc(
HWND hwnd, // дескриптор окна
UINT message, // тип сообщения
UINT wParam, // дополнительная информация
LONG lParam) // дополнительная информация
{
switch (message)
{
case WM_CREATE:
// Выбираем моноширинный системный шрифт, и получаем его матрицы.
hdc = GetDC(hwnd);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hdc, &tm);
ReleaseDC(hwnd, hdc);
// Сохраняем среднюю ширину и высоту знаков.
nCharX = tm.tmAveCharWidth;
nCharY = tm.tmHeight;
return 0;
case WM_SIZE:
// Выясняем ширину рабочей области, в пикселях
// и в количестве знаков.
nWindowX = LOWORD(lParam);
nWindowCharsX = max(1, nWindowX/nCharX);
// Выясняем ширину рабочей области, в пикселях
// и в количестве знаков.
nWindowY = HIWORD(lParam);
nWindowCharsY = max(1, nWindowY/nCharY);
// Очищаем буфер, который накапливает вводимый текст.
if (pTextMatrix != NULL)
free(pTextMatrix);
// Если имеется достаточно памяти, выделяем част ее
// для текста в буфере ввода.
pTextMatrix = malloc(nWindowCharsX * nWindowCharsY);
if (pTextMatrix == NULL)
ErrorHandler("Not enough memory.");
else
for (y = 0; y < nWindowCharsY; y++)
for (x = 0; x < nWindowCharsX; x++)
TEXTMATRIX(x, y) = ' ';
// Передвигаем каретку в начало координат.
SetCaretPos(0, 0);
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_HOME: // В начало документа (Home)
nCaretPosX = 0;
break;
case VK_END: // В конец документа (End)
nCaretPosX = nWindowCharsX - 1;
break;
case VK_PRIOR: // На страницу вверх (Page Up)
nCaretPosY = 0;
break;
case VK_NEXT: // На страницу вниз (Page Down)
nCaretPosY = nWindowCharsY -1;
break;
case VK_LEFT: // Стрелка влево (Left arrow)
nCaretPosX = max(nCaretPosX - 1, 0);
break;
case VK_RIGHT: // Стрелка вправо (Right arrow)
nCaretPosX = min(nCaretPosX + 1,
nWindowCharsX - 1);
break;
case VK_UP: // Стрелка вверх (Up arrow)
nCaretPosY = max(nCaretPosY - 1, 0);
break;
case VK_DOWN: // Стрелка вниз (Down arrow)
nCaretPosY = min(nCaretPosY + 1,
nWindowCharsY - 1);
break;
case VK_DELETE: // Удаление (Delete)
// Перемещаем все символы, которые следуют за
// удаленным символом (на той же самой строке) на один
// пробел назад (влево) в матрице.
for (x = nCaretPosX; x < nWindowCharsX; x++)
TEXTMATRIX(x, nCaretPosY) =
TEXTMATRIX(x + 1, nCaretPosY);
// Заменяем последний символ в
// строке пробелом.
TEXTMATRIX(nWindowCharsX - 1,
nCaretPosY) = ' ';
// Приложение будет рисовать не в ответ на сообщение
// WM_PAINT, так что каретку скроем.
HideCaret(hwnd);
// Перерисовываем строку, откорректировав на
// удаленный символ.
hdc = GetDC(hwnd);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
TextOut(hdc, nCaretPosX * nCharX,
nCaretPosY * nCharY,
&TEXTMATRIX(nCaretPosX, nCaretPosY),
nWindowCharsX - nCaretPosX);
ReleaseDC(hwnd, hdc);
// Показываем на экране каретку.
ShowCaret(hwnd);
break;
}
// Корректируем позицию каретки опираясь на обработку
// кода виртуальной клавиши.
SetCaretPos(nCaretPosX * nCharX,
nCaretPosY * nCharY);
return 0;
case WM_CHAR:
switch (wParam)
{
case 0x08: // Возврат на один знак (Backspace)
// Перемещаем каретку назад на один пробел, а затем
// обрабатываем аналогично клавише DEL.
if (nCaretPosX > 0)
{
nCaretPosX--;
SendMessage(hwnd, WM_KEYDOWN,
VK_DELETE, 1L);
}
break;
case 0x09: // Табуляция (Tab)
// Существующий шаг табуляции равен четырем пробелам, так что
// добавим пробелы, пока пользователь не нажал след. Tab.
do
{
SendMessage(hwnd, WM_CHAR, ' ', 1L);
} while (nCaretPosX % 4 != 0);
break;
case 0x0D: // Возврат каретки
// Перейдем в начало следующей строки.
// Нижняя строка переносит по словам обратно вверх.
nCaretPosX = 0;
if (++nCaretPosY == nWindowCharsY)
nCaretPosY = 0;
break;
case 0x1B: // Переход
case 0x0A: // Перевод строки
MessageBeep((UINT) -1);
break;
default:
// Добавим символ в буфер текста.
TEXTMATRIX(nCaretPosX, nCaretPosY) =
(char) wParam;
// Приложение будет рисовать не в ответ на сообщение
// WM_PAINT, так что каретку скроем.
HideCaret(hwnd);
// Рисуем символ на экране.
hdc = GetDC(hwnd);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
TextOut(hdc, nCaretPosX * nCharX,
nCaretPosY * nCharY,
&TEXTMATRIX(nCaretPosX, nCaretPosY), 1);
ReleaseDC(hwnd, hdc);
// Показываем на экране каретку.
ShowCaret(hwnd);
// Подготовим перенос по словам, если вы достигли
// конца строки.
if (++nCaretPosX == nWindowCharsX)
{
nCaretPosX = 0;
if (++nCaretPosY == nWindowCharsY)
nCaretPosY = 0;
}
break;
}
// Корректируем позицию каретки, опираясь
// на обработку кода символа.
SetCaretPos(nCaretPosX * nCharX,
nCaretPosY * nCharY);
return 0;
case WM_PAINT:
// Рисуем все символы в буфере, строка за строкой.
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
for (y = 0; y < nWindowCharsY; y++)
TextOut(hdc, 0, y * nCharY, &TEXTMATRIX(0, y),
nWindowCharsX);
EndPaint(hwnd, &ps);
case WM_SETFOCUS:
// Окно имеет фокус ввода. Загрузим определяемый программой
// ресурс каретки.
hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120));
// Создадим каретку.
CreateCaret(hwnd, hCaret, 0, 0);
// Откорректируем позицию каретки.
SetCaretPos(nCaretPosX * nCharX,
nCaretPosY * nCharY);
// Покажем на экране позицию каретки.
ShowCaret(hwnd);
break;
case WM_KILLFOCUS:
// Окно потеряло фокус ввода,
// так что уничтожим каретку.
DestroyCaret();
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return NULL;
}
|