Выбор строки текста

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

Демонстрационный пример

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; 
} 

 

Назад в оглавление
На главную страницу

Hosted by uCoz