Работа с мышкой
Страница 4. Выделение строки текста


 

Выделение строки текста

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

Пример:

LRESULT APIENTRY MainWndProc(HWND hwndMain, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
HDC hdc; // дескриптор контекста устройства
TEXTMETRIC tm; // данные о размере шрифта
int i, j; // счётчики цикла
int cCR = 0; // счётчик возвратов каретки
char ch; // символ из буфера ввода
static int nBegLine; // начало выделенной линии
static int nCurrentLine = 0; // текущая выделенная строка
static int nLastLine = 0; // последняя строка текста
static int nCaretPosX = 0; // x-координата каретки
static int cch = 0; // количество введённых символов
static int nCharWidth = 0; // точная ширина символа
static char szHilite[128]; // строка текста, которая будет выделена
static DWORD dwCharX; // средняя ширина символов
static DWORD dwLineHeight; // высота строки
static POINTS ptsCursor; // координаты курсора мышки
static COLORREF crPrevText; // предыдущий цвет текста
static COLORREF crPrevBk; // предыдущий цвет фона
static PTCHAR pchInputBuf; // указатель на буфер ввода
static BOOL fTextSelected = FALSE; // флаг выделения текста
size_t * pcch;
HRESULT hResult;

switch (uMsg)
{
case WM_CREATE:

// Получаем параметры текущего шрифта.

hdc = GetDC(hwndMain);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndMain, hdc);

// Сохраняем среднюю ширину и высоту символа.

dwCharX = tm.tmAveCharWidth;
dwLineHeight = tm.tmHeight;

// Выделяем буфер для хранения ввода с клавиатуры.

pchInputBuf = (LPSTR) GlobalAlloc(GPTR,
BUFSIZE * sizeof(TCHAR));

return 0;

case WM_CHAR:
switch (wParam)
{
case 0x08: // backspace
case 0x0A: // перевод строки
case 0x1B: // escape
MessageBeep( (UINT) -1);
return 0;

case 0x09: // символ табуляции (tab)

// Преобразуем символы табуляции в четыре пробела.

for (i = 0; i < 4; i++)
SendMessage(hwndMain, WM_CHAR, 0x20, 0);
return 0;

case 0x0D: // возврат каретки

// Записываем символ возврата каретки и помещаем каретку
// в начало новой строки.

pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCurrentLine += 1;
break;

default: // отображаемый символ

ch = (char) wParam;
HideCaret(hwndMain);

// Получаем ширину символа и отображаем его.

hdc = GetDC(hwndMain);
GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam,
&nCharWidth);
TextOut(hdc, nCaretPosX,
nCurrentLine * dwLineHeight, &ch, 1);
ReleaseDC(hwndMain, hdc);

// Сохраняем символ в буфере.

pchInputBuf[cch++] = ch;

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

nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwMaxCharX)
{
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCurrentLine;
}

ShowCaret(hwndMain);

break;
}
SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
nLastLine = max(nLastLine, nCurrentLine);
break;

// Обрабатываем другие сообщения.

case WM_LBUTTONDOWN:

// Если строка текста уже выделена, то перерисовываем
// текст, чтобы убрать выделение.

if (fTextSelected)
{
hdc = GetDC(hwndMain);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
hResult = StringCchLength(szHilite, 128/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TODO: обработчик ошибки
}
TextOut(hdc, 0, nCurrentLine * dwLineHeight, szHilite, *pcch);
ReleaseDC(hwndMain, hdc);
ShowCaret(hwndMain);
fTextSelected = FALSE;
}

// Сохраняем текущие координаты курсора мышки.

ptsCursor = MAKEPOINTS(lParam);

// Определяем, на какой строке находится курсор, и сохраняем
// номер строки. Следим, чтобы номера строк не были больше
// номера последней строки текста. Результат используем
// для установки y-координаты каретки.

nCurrentLine = min((int)(ptsCursor.y / dwLineHeight),
nLastLine);

// Парсим текст буфера ввода, чтобы найти первый символ
// в выделенной строке текста. Каждая строка оканчивается
// символом возврата каретки, поэтому, чтобы найти
// выделенную строку, достаточно сосчитать возвраты каретки.

cCR = 0;
nBegLine = 0;
if (nCurrentLine != 0)
{
for (i = 0; (i < cch) &&
(cCR < nCurrentLine); i++)
{
if (pchInputBuf[i] == 0x0D)
++cCR;
}
nBegLine = i;
}

// Начиная с начала выделенной строки, измеряем ширину
// каждого символа, суммируя с шириной уже измеренного
// символа. Останавливаемся,
// когда сумма больше, чем x-координата курсора.
// Сумма используется для установки x-координаты каретки.

hdc = GetDC(hwndMain);
nCaretPosX = 0;
for (i = nBegLine;
(pchInputBuf[i] != 0x0D) && (i < cch); i++)
{
ch = pchInputBuf[i];
GetCharWidth32(hdc, (int) ch, (int) ch, &nCharWidth);
if ((nCaretPosX + nCharWidth) > ptsCursor.x) break;
else nCaretPosX += nCharWidth;
}
ReleaseDC(hwndMain, hdc);

// Устанавливаем каретку в то место, куда кликнул пользователь.

SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
break;

case WM_LBUTTONDBLCLK:

// Копируем выделенную строку в буфер.

for (i = nBegLine, j = 0; (pchInputBuf[i] != 0x0D) &&
(i < cch); i++)
{
szHilite[j++] = pchInputBuf[i];
}
szHilite[j] = '\0';

// Скрываем каретку, инвертируем цвет фона и символов,
// а затем перерисовываем выделенную строку.

HideCaret(hwndMain);
hdc = GetDC(hwndMain);
crPrevText = SetTextColor(hdc, RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc, RGB(0, 0, 0));
hResult = StringCchLength(szHilite, 128/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TODO: обработчик ошибки
}
TextOut(hdc, 0, nCurrentLine * dwLineHeight, szHilite, *pcch);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
ReleaseDC(hwndMain, hdc);

fTextSelected = TRUE;
break;

// Обрабатываем другие сообщения.

default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}

 
« Предыдущая статья   Следующая статья »