Страница 4 из 6 Выделение строки текста В данном разделе приведён пример, который был взят из обычного текстового редактора. Он включает код, позволяющий пользователю обычным щелчком устанавливать каретку в любом месте текста, а также выделять (подсвечивать) строку текста двойным щелчком. Пример: 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; } |