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