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

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

Жанры

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

Ватсон Карли

Шрифт:

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

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

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

В очень сложном приложении можно даже написать целый класс, который отвечает за рисование на экране. Несколько лет назад, когда MFC были стандартной технологией для приложений с интенсивным использованием GDI, MFC следовали этой модели с помощью класса C++ с именем

С<Имя_приложения>View
, который отвечал за это. Однако даже в таком случае этот класс имел функцию-член
OnDraw
, которая была создана, чтобы быть точкой входа для большинства запросов рисования.

Вычисление размеров объектов и размера документа

Мы возвращаемся теперь к примеру

CapsEditor
и разбираем методы
CalculateLineWidths
и
CalculateDocumentSize
, которые вызываются из метода
LoadFile
:

private void CalculateLineWidths {

 Graphics dc = this.CreateGraphics;

 foreach (TextLineInformation nextLine in documentLines) {

nextLine.Width = (uint)dc.MeasureString(nextLine.Text, mainFont).Width;

 }

}

Этот метод просто выполняется на каждой прочитанной строке и использует метод

Graphics.MeasureString
для определения и сохранения значения величины горизонтального пространства экрана, которое требуется строке. Мы сохраняем значение, так как
MeasureString
является весьма интенсивным с вычислительной точки зрения. Так как в нашем примере
CapsEditor
не слишком легко определить высоту и положение каждого элемента, то этот метод почти наверняка будет реализован, чтобы вычислить все эти величины.

Теперь, когда мы знаем размер каждого элемента на экране и можем вычислить приблизительное его положение, определим реальный размер документа. Высота, по существу, равна числу строк, умноженному на высоту каждой строки. Ширину необходимо определить просмотром всех строк, чтобы выявить самую длинную и взять ширину этой строки. Для высоты и ширины также желательно допустить небольшие поля вокруг выводимого документа, чтобы приложение выглядело более привлекательно. (Нежелательно, чтобы текст прикасался к одному из углов клиентской области.) Вот метод, который вычисляет размер документа:

private void CalculateDocumentSize {

 if (!documentHasData) {

documentSize = new Size(100, 200);

 } else {

documentSize.Height = (int)(nLines*lineHeight) + 2*(int)margin;

uint maxLineLength = 0;

foreach (TextLineInformation nextWord in documentLines) {

uint tempLineLength = nextWord.Width + 2*margin;

if (tempLineLength > maxLineLength) maxLineLength = tempLineLength;

}

documentSize.Width = (int)maxLineLength;

 }

 this.AutoScrollMinSize = documentSize;

}

Этот

метод сначала проверяет, есть ли данные для вывода. Если данных нет, мы слегка схитрим и зададим жестко кодированный размер документа такой величины, чтобы хватило места для выведения большими красными буквами предупреждения <Empty Document>. В противном случае необходимо воспользоваться методом
MeasureString
для определения реального размера документа.

После этого размер документа сообщается экземпляру класса Form, задавая свойство

Form.AutoScrollMinSize
. Когда это сделано, за сценой происходит кое-что интересное. В процессе задания этого свойства клиентская область становится недействительной и инициируется событие
Paint
в связи с тем, что изменение размера документа означает необходимость добавить или изменить панели прокрутки, а также, что вся клиентская область почти наверняка будет перерисована. Это в полной мере иллюстрирует то, что было сказано ранее об использовании метода
Form.Invalidate
. Если вернуться назад к коду
LoadFile
, то станет понятно, что вызов метода
Invalidate
в этом методе является на самом деле излишним. Клиентская область будет объявлена недействительной в любом случае, когда задается размер документа. Явный вызов метода
Invalidate
в реализации метода
LoadFile
оставлен для иллюстрации. Фактически в этом случае все, что будет делать вызванный метод
Invalidate
, является ненужным запросом повторного события
Paint
. Однако это в свою очередь подтверждает, что
Invalidate
дает Windows возможность оптимизировать производительность. Второе событие Paint не будет фактически инициировано: Windows увидит, что в очереди уже находится событие
Paint
, и сравнит запрошенные недействительные области, чтобы попробовать объединить их. В этом случае оба события Paint будут определять всю клиентскую область, поэтому ничего не нужно делать, и Windows спокойно удалит второй запрос
Paint
. Конечно, это действие займет какое-то процессорное время, но оно будет ничтожным по сравнению с тем, сколько времени потребуется для реального выполнения рисования.

OnPaint

Итак, мы увидели, как

CapsEditor
загружает файл. Теперь пришло время посмотреть, как выполняется рисование:

protected override void OnPaint(PaintEventArgs e) {

 Graphics dc = e.Graphics;

 int scrollPositionX = this.AutoScrollPosition.X;

 int scrollPositionY = this.AutoScrollPosition.Y;

 dc.TranslateTransform(scrollPositionX, scrollPositionY);

 if (!documentHasData) {

dc.DrawString("<Empty Document>", emptyDocumentFont,

emptyDocumentBrush, new Point(20, 20));

base.OnPaint(e);

 return;

 }

 // определить, какие строки находятся в вырезанном прямоугольнике

 int minLineInClipRegion =

WorldYCoordinateToLineIndex(е.ClipRectangle.Top - scrollPositionY);

 if (minLineInClipRegion == -1) minLineInClipRegion = 0;

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

На границе империй. Том 3

INDIGO
3. Фортуна дама переменчивая
Фантастика:
космическая фантастика
5.63
рейтинг книги
На границе империй. Том 3

На границе империй. Том 5

INDIGO
5. Фортуна дама переменчивая
Фантастика:
боевая фантастика
попаданцы
7.50
рейтинг книги
На границе империй. Том 5

Ученичество. Книга 2

Понарошку Евгений
2. Государственный маг
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Ученичество. Книга 2

Адвокат вольного города 3

Кулабухов Тимофей
3. Адвокат
Фантастика:
городское фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Адвокат вольного города 3

Мымра!

Фад Диана
1. Мымрики
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Мымра!

Пипец Котенку! 2

Майерс Александр
2. РОС: Пипец Котенку!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Пипец Котенку! 2

Инкарнатор

Прокофьев Роман Юрьевич
1. Стеллар
Фантастика:
боевая фантастика
рпг
7.30
рейтинг книги
Инкарнатор

Часовая битва

Щерба Наталья Васильевна
6. Часодеи
Детские:
детская фантастика
9.38
рейтинг книги
Часовая битва

Небо для Беса

Рам Янка
3. Самбисты
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Небо для Беса

#Бояръ-Аниме. Газлайтер. Том 11

Володин Григорий Григорьевич
11. История Телепата
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 11

Пистоль и шпага

Дроздов Анатолий Федорович
2. Штуцер и тесак
Фантастика:
альтернативная история
8.28
рейтинг книги
Пистоль и шпага

Дракон - не подарок

Суббота Светлана
2. Королевская академия Драко
Фантастика:
фэнтези
6.74
рейтинг книги
Дракон - не подарок

Её (мой) ребенок

Рам Янка
Любовные романы:
современные любовные романы
6.91
рейтинг книги
Её (мой) ребенок

Не грози Дубровскому! Том III

Панарин Антон
3. РОС: Не грози Дубровскому!
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не грози Дубровскому! Том III