|
Программирование >> Вывод графики
Фигуры рисуются, как и раньше, начиная с верхнего левого угла клиентской области - как если бы мы вообще не двигали линейку прокрутки. Прежде, чем мы разбираться с тем, как решить эту проблему, тщательно исследуем, что мы видим на этих образах экрана. Начнем с примера BigShapes, показанного на рис. 33.8. В этом примере полное окно только что перерисовано. Просмотрев код, мы видим, что он инструктирует экземпляр Graphics нарисовать прямоугольник, начиная с левой верхней координаты (0,0) - относительно левого верхнего угла клиентской области окна - что и происходит. Проблема состоит в том, что экземпляр Graphics трактует координаты как относящиеся к клиентской области окна и ничего не знает о линейках прокрутки. Наш код не пытается исправить координаты в соответствии с текущим положением линеек прокрутки. То же самое происходит с эллипсом. Теперь посмотрим на снимок экрана, показанный на рис. 33.9. После прокрутки мы замечаем, что верхняя часть окна выглядит хорошо. Это потому, что она была нарисована при запуске приложения. Когда мы прокручиваем окно, Windows достаточно умна, чтобы обнаружить, какие из отображаемых битов экрана можно просто переместить в соответствии с положением линейки прокрутки. Это - наиболее эффективный процесс, поскольку он может использовать для этого аппаратное ускорение. Неверно отображенная часть находится в нижней трети окна. Эта часть не была нарисована при запуске приложения, поскольку тогда она выходила за пределы клиентской области. Это значит, что Windows попросит наше приложение BigShapes нарисовать эту область. То есть она сгенерирует событие Paint, передав ему координаты прямоугольника отсечения. И это приведет к вызову нашего переопределенного метода OnPaint() . Одним способом решения этой проблемы может быть выражение координат для рисования относительно верхнего левого угла документа - т.е. их нужно преобразовать таким образом, чтобы выразить относительно левого верхнего угла клиентской области окна (рис. 33.11). Чтобы сделать эту диаграмму яснее, документ на ней несколько увеличен в высоту и ширину, но это не меняет сути дела. Мы предполагаем наличие небольшой горизонтальной прокрутки наряду с вертикальной. На рис. 33.11 тонкие прямоугольники помечают границы экранной области и границы всего документа. Толстыми линиями отображаются прямоугольник и эллипс, которые мы пытаемся нарисовать. P отмечает некоторую произвольную точку на рисунке, которую мы используем для примера. Рис. 33.10. Восстановление окна после минимизации Рис. 33.11. Выражение координат для рисования относительно верхнего левого угла документа При вызове методов рисования экземпляр Graphics применяет вектор из точки B в (скажем) точку P, выраженный как экземпляр Point. Нам нужно преобразовать его в вектор из точки A в точку P. Проблема состоит в том, что мы не знаем, что собой представляет вектор из точки A в точку P. Мы знаем, что имеется вектор от B до P - просто координаты точки P относительно верхнего левого угла документа, т.е. позиция в документе, где нужно нарисовать точку P. Мы также знаем, что вектор от B до A - это просто величина прокрутки; это содержится в свойстве класса Form под названием AutoScrollPosition. Однако нам не известен вектор от A до P. Если вы помните математику, то легко найдете решение этой задачи - для этого нужно просто вычесть один вектор из другого. Предположим, для примера, что чтобы попасть из B в P, нужно переместиться на 150 пикселей по горизонтали вправо и на 200 пикселей по вертикали вниз, в то время как для того, чтобы попасть из B в A, нужно переместиться на 10 пикселей вправо и на 57 вниз. Это значит, что для того, чтобы попасть из A в P, необходимо переместиться на 140 (150 - 10) вправо и на 143 (200 - 57) вниз. Чтобы еще более упростить это, класс Graphics реализует метод, который выполняет за нас эти вычисления. Он называется TranslateTransform(). Ему передаются горизонтальная и вертикальная координаты, сообщающие, где находится верхний левый угол клиентской области по отношению к верхнему левому углу документа (таким образом, свойство AutoScrollPosition представляет вектор от B к A). Устройство Graphics теперь самостоятельно обработает все координаты с учетом относительного расположения клиентской области и документа. Для выражения этого длинного объяснения с помощью кода нам понадобится добавить всего одну строку: dc.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y); Однако в нашем примере все будет несколько сложнее, потому что также потребуется отдельно проверить, нужно ли вообще что-то рисовать, посмотрев на область отсечения. Эту проверку придется исправить с учетом текущей позиции прокрутки. Когда мы все это сделаем, наш код рисования будет выглядеть следующим образом: protected override void OnPaint( PaintEventArgs e ) base.OnPaint(e); Graphics dc = e.Graphics; Size scrollOffset = new Size(this.AutoScrollPosition); if (e.ClipRectangle.Top+scrollOffset.Width < 350 e.ClipRectangle.Left+scrollOffset.Height < 250) Rectangle rectangleArea = new Rectangle (rectangleTopLeft+scrollOffset , rectangleSize); Rectangle ellipseArea = new Rectangle (ellipseTopLeft+scrollOffset, ellipseSize); dc.DrawRectangle(bluePen, rectangleArea); dc.DrawEllipse(redPen, ellipseArea); Теперь наш код работает отлично, и мы, наконец, можем получить правильный экран после прокрутки, как показано на рис. 33.12. Рис. 33.12. Правильный экран после прокрутки Мировые координаты, страничные координаты и координаты устройства Разница между измерением положения относительно верхнего левого угла документа и относительно верхнего левого угла экрана (рабочего стола) настолько важна, что в GDI+ предусмотрены специальные наименования для этих координатных систем. □ Мировые координаты (world coordinates) - указывают позицию точки, измеренную в пикселях от левого верхнего угла документа. □ Страничные координаты (page coordinates) - указывают позицию точки, измеренную в пикселях от левого верхнего угла клиентской области. Разработчики, знакомые с GDI, заметят, что мировые координаты соответствуют тому, что в GDI называется логическими координатами, а страничные координаты - тому, что известно как координаты устройства. Как разработчик, ранее имеющий дело с GDI, вы также отметите, что способ преобразования между логическими координатами и координатами устройства в GDI+ изменился. В GDI преобразование происходило через контекст устройства с помощью функций Windows API LPtoDP() и DPtoLP(). В GDI+ имеется класс Control, от которого происходит как Form, так и все разнообразные элементы управления Windows Forms, и этот класс поддерживает всю информацию, необходимую для выполнения преобразований. В GDI+ также выделена третья система координат, называемая координатами устройства (device coordinates). Координаты устройства подобны страничным координатам, за исключением того, что в качестве единиц измерения не используются пиксели. Вместо них применяются другие единицы измерения, определяемые пользователем через вызов Graphics.PageUnit. Возможные единицы измерения помимо пикселей включают дюймы и миллиметры. Хотя в данной главе мы не будем использовать свойство PageUnit, вы можете счесть его полезным в качестве способа работы с различными разрешениями графических устройств. Например, 100 пикселей на большинстве мониторов занимают около дюйма. Однако лазерные принтеры могут иметь 1200 или более точек на дюйм (dots per inch - dpi), а это значит, что эти 100 пикселей на принтере будут выглядеть значительно меньше. Установив единицу измерения, скажем, в дюймах, и, указав размер фигуры в 1 дюйм, вы можете обеспечить одинаковый размер при ее выводе на разные устройства. Это делается так: Graphics dc = this.CreateGraphics(); dc.PageUnit = GraphicsUnit.Inch; К возможным единицам измерения, доступным в перечислении GraphicsUnit, относятся следующие: □ Display - определяет единицу измерения дисплея; □ Document - определяет единицу документа (1/300 дюйма) в качестве единицы измерения; □ Inch - определяет дюйм в качестве единицы измерения; □ Millimeter - определяет миллиметр в качестве единицы измерения; □ Pixel - определяет пиксель в качестве единицы измерения; □ Point - определяет точку принтера (1/72 дюйма) в качестве единицы измерения; □ World - определяет мировую систему координат в качестве единицы измерения.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |