Чтение онлайн

на главную - закладки

Жанры

C# для профессионалов. Том II

Ватсон Карли

Шрифт:

 int maxLineInClipRegion =

WorldYCoordinateToLineIndex(e.ClipRectangle.Bottom - scrollPositionY);

 if (maxLineInClipRegion >= this.documentLines.Count || maxLineInClipRegion == -1)

maxLineInClipRegion = this.documentLines.Count - 1;

 TextLineInformation nextLine;

 for (int i = minLineInClipRegion; i <= maxLineInClipRegion; i++) {

nextLine = (TextLineInformation)documentLines[i];

dc.DrawString(nextLine.Text, mainFont, mainBrush, this.LineIndexToWorldCoordinates(i));

 }

base.OnPaint(e);

}

В

середине этой перезагружаемой версии
OnPaint
находится цикл, который перебирает все строки документа, вызывая метод
Graphics.DrawString
для рисования каждой из них. Остальная часть этого кода связана в основном с оптимизацией рисования — обычный материал для определения, что действительно необходимо нарисовать вместо необдуманного приказания экземпляру Graphics перерисовать все.

Мы начинаем с проверки, имеются ли в документе какие-либо данные. Если данных нет, мы выводим краткое сообщение, говорящее об этом вызываем реализацию

OnPaint
из базового класса и выходим. Если имеются данные, то мы начинаем проверять прямоугольник вырезания. Способ, которым это делается, состоит в вызове другого написанного нами метода
WorldYCoordinateToLineIndex
. Мы рассмотрим этот метод позже, но по сути он получает заданную у-позицию относительно верха документа и определяет, какая строка документа будет выводиться в этой точке.

При первом вызове метода

WorldYCoordinateToLineIndex
ему передается значение координаты
е.ClipRectangle.Top - scrollPositionY
. Это верх области вырезания, преобразованный в мировые координаты. Если возвращаемое значение будет -1, мы предположим, что нам нужно начать с начала документа (если верх области вырезания находится наверху граничного поля).

После того, как все это будет сделано, мы практически повторяем тот же процесс для низа прямоугольника вырезания, чтобы определить последнюю строку документа, которая находится внутри области вырезания. Индексы первой и последней строки хранятся соответственно в

minLineInClipRegion
и
maxLineInClipRegion
, поэтому мы можем просто выполнить цикл
for
между этими значениями, чтобы реализовать рисование. Внутри цикла рисования мы должны сделать приблизительно обратное преобразование для преобразования, выполненного методом
WorldYCoordinateToLineIndex
. Задан индекс строки текста и нужно проверить, где она должна быть нарисована. Это вычисление является вполне простым, но мы поместили его в другой метод
LineIndexToWorldCoordinates
, который возвращает требуемые координаты верхнего левого угла элемента. Возвращаемые координаты являются мировыми координатами, и это хорошо, так как мы уже вызвали метод
TranslateTransform
на объекте Graphics, поэтому нам нужно передать ему при запросе вывода элемента мировые координаты, а не координаты страницы.

Преобразования координат

В этом разделе мы рассматриваем реализацию вспомогательных методов, которые были использованы в примере

CapsEditor
, чтобы выполнить преобразование координат. Это методы
WorldYCoordinateToLineIndex
и
LineIndexToWorldCoordinates
, на которые мы ссылались в предыдущем разделе, а также некоторые другие методы.

Первое.

LineIndexToWorldCoordinates
получает заданный индекс строки и определяет мировые координаты верхнего левого угла строки с помощью известных ширины поля и высоты
строки:

private Point LineIndexToWorldCoordinates(int index) {

 Point TopLeftCorner =

new Point((int)margin, (int)(lineHeight*index + margin));

 return TopLeftCorner;

}

Мы также используем метод, который делает приблизительно обратное преобразование в

OnPaint
.
WorldYCoordinateToLineIndex
определяет индекс строки, но он принимает в расчет только вертикальную мировую координату. Это связано с тем, что метод используется для определения индекса строки, соответствующего верху и низу области вырезания:

private int WorldYCoordinateToLineIndex(int у) {

 if (у < margin) return -1;

 return (int)((y - margin)/lineHeight);

}

Существуют еще три метода, вызываемые из процедуры обработки, которые отвечают на двойной щелчок пользователя мышью. Прежде всего — метод, определяющий индекс строки, которая выведется в заданных мировых координатах. В отличие от

WorldYCoordinateToLineIndex
этот метод берет в расчет позиции x- и y- координат. Он возвращает -1, если нет строки текста с заданными координатами.

private int WorldCocrdinatesToLineIndex(Point position) {

 if (!documentHasData) return -1;

 if (position.Y < margin || position.X < margin) return -1;

 int index = (int) (position.Y - margin) / (int) this.lineHeight;

 // проверить, что позиция находится не ниже документа

 if (index >= documentLines.Count) return -1;

 // теперь проверим, что горизонтальная позиция располагается

 // внутри строки

 TextLineInformation theLine =

(TextLineInformation)documentLines[index];

 if (position.X > margin * theLine.Width)

 return -1;

 // все хорошо. Можно вернуть ответ.

 return index;

}

Наконец, иногда необходимо делать преобразование между индексом строки и координатами страницы, а не мировыми координатами. Это делает следующий метод:

private Point LineIndexToPageCoordinates(int index) {

 return LineIndexToWorldCoordinates(index) + new Size(AutoScrollPosition);

}

private int PageCoordinatesToLineIndex(Point position) {

 return WorldCoordinatesToLineIndex(position - new Size(AutoScrollPosition));

}

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

Поделиться:
Популярные книги

Толян и его команда

Иванов Дмитрий
6. Девяностые
Фантастика:
попаданцы
альтернативная история
7.17
рейтинг книги
Толян и его команда

Я все еще граф. Книга IX

Дрейк Сириус
9. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я все еще граф. Книга IX

Землянка для двух нагов

Софи Ирен
Фантастика:
космическая фантастика
5.00
рейтинг книги
Землянка для двух нагов

Возвышение Меркурия. Книга 15

Кронос Александр
15. Меркурий
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 15

Тактик

Земляной Андрей Борисович
2. Офицер
Фантастика:
альтернативная история
7.70
рейтинг книги
Тактик

Герцогиня в ссылке

Нова Юлия
2. Магия стихий
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Герцогиня в ссылке

Попаданка в семье драконов

Свадьбина Любовь
Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.37
рейтинг книги
Попаданка в семье драконов

Прорвемся, опера! Книга 2

Киров Никита
2. Опер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Прорвемся, опера! Книга 2

Королевская Академия Магии. Неестественный Отбор

Самсонова Наталья
Любовные романы:
любовно-фантастические романы
8.22
рейтинг книги
Королевская Академия Магии. Неестественный Отбор

Новый Рал 3

Северный Лис
3. Рал!
Фантастика:
попаданцы
5.88
рейтинг книги
Новый Рал 3

Шведский стол

Ланцов Михаил Алексеевич
3. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Шведский стол

Имя нам Легион. Том 11

Дорничев Дмитрий
11. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 11

Метатель. Книга 2

Тарасов Ник
2. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель. Книга 2

Я уже князь. Книга XIX

Дрейк Сириус
19. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я уже князь. Книга XIX