Выбор строки текста
Пример в этом разделе взят из простой программы обработки текстов. Он включает в себя код, который дает возможность пользователю устанавливать позицию каретки, щелкая где-нибудь по строке текста и выбрать (выделить) строку текста, дважды щелкая мышью где-нибудь по ней.
Демонстрационный пример
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: // возврат на один символ
case 0x0A: // перевод строки
case 0x1B: // переход (с регистра на регистр)
MessageBeep( (UINT) -1);
return 0;
case 0x09: // табуляция
// Преобразуем табуляцию в четыре последовательных пробела.
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))
{
// Добавляем код, который дает возможность безопасно, как только возможно,
// завершить работу по ошибке.
return;
}
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))
{
// Добавляем код, который дает возможность безопасно,
// завершить работу по ошибке.
return;
}
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;
}
|