Окт 16

Просмотрщик текстовых файлов

Приложение TextViewer предназначено для чтения и вывода на экран текстового файла. В приложении демонстрируются: использование полос прокрутки, вывод текста при помощи функций TextOut и TabbedTextOut, а также использование региона отсечения.
В этом примере также показано, что использование идей ООП вряд ли ухудшает качество программного кода, скорее — наоборот. С этой целью разработан класс «Document для решения тех подзадач, которые связаны с загрузкой, хранением и выводом документа в клиентскую область окна с учетом его прокрутки. Интерфейс класса содержится в файле KDocument.h, а его реализация — в файле KDocument.cpp.
Обратите внимание на следующие особенности реализации класса KDocument:
Для хранения текстового документа используется член класса lines, который
объявлен как вектор строк типа string.
В методе Open заданный входной файл читается по строкам. Предполагается, что строки разделяются символом \п. Каждая прочитанная строка добавляется в конец вектора lines. Затем в цикле for вычисляется максимальная длина строки lineLenMax с учетом возможного присутствия символов табуляции. Присутствие символа табуляции в строке lines[i] проверяется методом find класса string, который возвращает позицию обнаруженного символа \t или значение -1, если символ табуляции не обнаружен. В методе ScrollSettings величина lineLenMax используется для установки максимального значения диапазона горизонтальной полосы прокрутки.
В методе Initialize вычисляются размеры «единиц данных» для скроллинга. Величина cxChar задает шаг изменения в горизонтальном измерении, а величина yStep — шаг изменения в вертикальном измерении. Для вычислений используются метрики текста, полученные в параметре tm.
Метод ScrollSettings предназначен для установки параметров вертикальной и горизонтальной полос прокрутки при заданных ширине width и высоте height клиентской области окна.
Метод UpdateVscroll выполняет итоговую обработку всех сообщений от вертикальной полосы прокрутки. В нем же производятся прокрутка содержимого окна при помощи функции ScrollWindow, обновление положения движка с помощью SetScrolUnfo и обновление клиентской области при помощи функции UpdateWindow. Более подробные комментарии по этому этапу можно найти в разделе «Полосы прокрутки и вывод текста».
Обратите особое внимание на первые две инструкции в теле функции. Они предваряются комментариями «ограничение на положительное приращение» и «ограничение на отрицательное приращение». Первая инструкция обеспечивает прекращение прокрутки при продвижении документа к его концу, как только позиция движка достигнет значения vertRange - (int)vsi.nPage. В этом положении движка последняя страница документа полностью видна в окне и дальнейшая прокрутка теряет смысл. Заметим, что преобразование к типу int для поля vsi.nPage необходимо для корректного выполнения макроса min.
Вторая инструкция обеспечивает прекращение прокрутки при продвижении документа к его началу, как только позиция движка достигнет значения vsi.nMin.
Метод UpdateHscroll производит итоговую обработку всех сообщений от горизонтальной полосы прокрутки. Реализация метода аналогична реализации метода UpdateVscroll.
Метод PutText предназначен для вывода фрагмента текста из документа в клиентскую область окна.
Для создания полей слева и справа от видимого в окне текста (в данном примере шириной в один символ) используется регион отсечения hRgn. Он создается вызовом функции CreateRectRgnlndirect, причем в качестве аргумента передается адрес прямоугольника rect, который в вертикальном измерении совпадает с прямоугольником клиентской области, а в горизонтальном измерении уменьшен слева и справа на величину cxChar. Созданный регион выбирается в контекст устройства функцией SelectClipRgn.
Фрагмент текста выводится в цикле for в соответствии с текущим положением движка vsi.nPos на вертикальной полосе прокрутки и текущим положением движка hsi.nPos на горизонтальной полосе прокрутки. Если в текущей строке lines[i] нет символов табуляции, то вызывается функция TextOut. В противном случае используется функция TabbedTextOut.
По умолчанию в контексте устройства установлен режим отображения ММ_ТЕХТ, поэтому начало координат совмещено с левым верхним углом клиентской области. Координата у для вывода каждой следующей строки вычисляется с учетом смещения yStep.
Если значение hsi.nPos совпадает со значением hsi.nMin, то координата х, вычисляемая по формуле cxChar x (hsi.nMin - hsi.nPos + 1), имеет значение cxChar. В этом случае строка выводится в окно, начиная с первого символа. А поскольку в контексте устройства выбран регион отсечения с дескриптором hRgn, то первый видимый символ в окне нельзя выводить левее, чем х = cxChar.
В случае hsi.nPos > 0 координата х будет принимать сначала нулевое, а потом отрицательные значения, абсолютная величина которых возрастает по мере прокрутки документа по горизонтали вправо. То есть начало вывода строки приходится на точку экрана, лежащую слева за пределами окна приложения. Разумеется, за счет отсечения, за которым следит Windows, пользователь будет видеть только ту часть строки, которая попадает в клиентскую область окна. А еще точнее, только ту часть строки, которая попадает в регион отсечения.
Перед выходом из функции инструкция SelectClipRgn(hdc, NULL) удаляет из контекста устройства выбранный ранее регион отсечения.