|
Программирование >> Вывод графики
соответствующие действия (которые, в зависимости от ситуации, могут означать генерацию исключения либо модификацию запроса таким образом, чтобы получить как можно более близкий результат в рамках возможностей данного устройства). Однако DC не только имеет дело с аппаратным устройством. Он служит в качестве моста между приложением и Windows, и принимает во внимание любые требования и ограничения, налагаемые на рисование Windows. Например, если Windows знает, что необходимо перерисовать лишь часть окна вашего приложения, DC перехватит и отменит попытки рисования вне этой области. Благодаря связи DC с Windows, работа через контекст устройств может упростить ваш код и в других отношениях. Например, аппаратным устройствам необходимо сообщать, где следует рисовать объекты, и обычно им нужны координаты, отсчитываемые относительно верхнего левого угла экрана (или другого выходного устройства). Однако приложения обычно отображают нечто в клиентской области (области, зарезервированной для рисования) собственного окна, возможно, используя собственную систему координат. Поскольку окно может быть позиционировано в любом месте экрана, и пользователь в любой момент может его переместить, преобразования между этими системами координат могут оказаться непростой задачей. Однако DC всегда знает, где находится ваше окно, и может выполнять такие преобразования автоматически. В GDI+ контекст устройства помещен в оболочку базового класса .NET с именем System.Drawing.Graphics. Большая часть рисования выполняется вызовом методов экземпляра Graphics. Фактически, поскольку класс Graphics отвечает за выполнение большинства операций рисования, очень немного в GDI+ происходит такого, что не касалось бы тем или иным образом экземпляра Graphics, а потому понимание того, как управлять этим объектом, является ключом к пониманию того, как рисовать на устройствах отображения с помощью GDI+. Рисование контуров Этот раздел мы начнем с короткого примера - DisplayAtStartup, чтобы показать рисование в главном окне приложения. Все примеры этой главы созданы в Visual Studio 2008 как Windows-приложения на C#. Вспомним, что для проектов этого типа мастер, генерирующий код, создаст класс с именем Forml, унаследованный от System. Windows.Form, который будет представлять главное окно приложения. Также будет сгенерирован класс Program (находящийся в файле Program.cs), представляющий главную стартовую точку приложения. Если не указано иначе, во всех последующих примерах кода новый или модифицированный код будет означать код, который мы добавим к коду, сгенерированному мастером. (Коды примеров доступны на прилагаемом компакт-диске.) При использовании .NET, когда мы говорим о приложения, отображающих различимее элементы управления, термин форма в основном заменяет окно и означает прямоугольный объект, занимающий место на экране по требованию приложения. В настоящей главе мы отдаем предпочтение термину окно , потому что в контексте ручного рисования элементов оно более осмысленно. Но мы также будем говорить о формах, сселаясь на классы .NET, которсе порождают экземпляры форм/окон. И, наконец, мы будем использовать термин рисование , описывая процесс отображения некоторых элементов на экране или другом выходном устройстве. В первом примере будет просто создана форма и выполнено рисование на ней в теле конструктора. Отметим, что этот способ не является ни лучшим, ни, к тому же, правильным способом рисования на экране - вы быстро обнаружите, что с этим примером связана проблема, состоящая в том, что он не в состоянии перерисовать что бы то ни было после запуска. Однако этот пример позволяет проиллюстрировать несколько важных моментов, касающихся рисования, не обременяя слишком большим объемом работы. Для построения этого примера создадим в Visual Studio 2008 приложение Windows. Сначала установим белый фон формы. В данном примере эта строка будет находиться после метода InitializeComponent(), так что Visual Studio 2008 сможет распознать ее и изменить представление формы в конструкторе. Чтобы найти метод InitializeComponent(), нужно щелкнуть на кнопке Show All Files (Показать все файлы) в проводнике решений (Solution Explorer) Visual Studio, затем щелкнуть на значке + рядом с файлом Form1.cs. Здесь мы найдем файл Form1.Designer.cs. Именно в этом методе находится метод InitializeComponent() . Можно использовать представление конструктора, чтобы установить цвет фона, но это даст тот же результат за счет автоматического добавления той же самой строки: private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Text = Form1 ; this.BackColor = System.Drawing.Color.White; Затем мы добавим код к конструктору Form1. Создадим объект Graphics, вызвав метод формы CreateGraphics(). Объект Graphics содержит в себе Windows DC (контекст устройства), который нам понадобится для рисования. Контекст устройства ассоциирован с дисплеем, а также с данным окном: public Form1() InitializeComponent(); Graphics dc = CreateGraphics(); Show(); Pen bluePen = new Pen(Color.Blue, 3); dc.DrawRectangle(bluePen, 0,0,50,50); Pen redPen = new Pen(Color.Red, 2); dc.DrawEllipse(redPen, 0, 50, 80, 60); Как видите, здесь вызывается метод Show() для отображения окна. Это приводит к немедленному показу окна на экране, потому что невозможно выполнить никакого рисования до тех пор, пока окно не отображено. Если окно не отображено, рисовать не на чем. И, наконец, мы выведем прямоугольник, начиная с координат (0,0) шириной и высотой 50, а также эллипс в координатах (0,50) шириной 80 и высотой 50. Отметим, что координаты (x,y) транслируются в x пикселей вправо и y пикселей вниз, начиная от левого верхнего угла клиентской области окна. Перегрузки методов DrawRectangle() и DrawEllipse() , которые мы используем, принимают по пять параметров каждая. Первый параметр каждой из них представляет собой экземпляр класса System.Drawing.Pen. Объект Pen (перо) - один из множества поддерживающих рисование объектов - содержит информацию о том, как рисовать линии. Наше первое перо указывает, что линия должна быть синего цвета и иметь ширину 3 пикселя; второе перо сообщает, что линия должна быть красного цвета и шириной 2 пикселя. Остальные четыре параметра - это координаты и размер. Для прямоугольника они представляют координаты (x,y) левого верхнего угла, Drawing ShafKS Sample д I В р.Ь I Рис. 33.1. Результат рисования прямоугольника и эллипса дополненные его шириной и высотой. Для эллипса эти числа представляют то же самое, если вообразить гипотетический прямоугольник, в который вписан эллипс, а не сам эллипс. На рис. 33.1 показан результат работы этого кода. Конечно, поскольку наша книга не цветная, вы не увидите здесь разных цветов. Этот рисунок демонстрирует два важных момента. Во-первых, здесь ясно можно видеть расположение клиентской области окна. Она представлена белым полем, установленным через свойство BackColor. Прямоугольник приютился в левом верхнем углу этой области, как и можно было ожидать по его координатам (0,0). Во-вторых, заметно, что верхняя часть эллипса слегка перекрывает прямоугольник, чего нельзя было ожидать на основе указанных для него координат. В этом виновата сама Windows, поскольку она решает, где проводить линии, ограничивающие прямоугольник и эллипс. По умолчанию Windows пытается центрировать линии по границе контура, что не всегда можно сделать в точности, потому что линия должна быть нарисована по пикселям (что очевидно). Обычно граница контура проходит между пикселями. В результате линия толщиной в 1 пиксель будет нарисована внутри начала контура - ниже его верхней и правее левой границ, но вне нижней и правой сторон, а потому контуры, которые должны примыкать друг к другу, перекроются на один пиксель. Мы указали более толстые линии, а потому перекрытие больше. Можно изменить поведение по умолчанию, установив свойство Pen.Alignment, как описано в документации по SDK, но пока для наших целей вполне подойдет поведение по умолчанию. К сожалению, запустив этот пример, мы увидим, что наша форма ведет себя несколько странно. Все в порядке, если после ее появления оставить ее на месте. Также все будет нормально, если перетаскивать ее по экрану с помощью мыши. Если же попытаться минимизировать окно и затем восстановить его снова, то наши тщательно нарисованные фигуры исчезнут! То же произойдет, если перетащить какое-то другое окно над нашим примером так, чтобы оно частично перекрывало нарисованные контуры. Если это окно снова убрать, мы увидим, что исчезнет часть нашего рисунка, и мы увидим только половинку прямоугольника и половинку эллипса! Что происходит? Проблема возникает, когда скрывается часть окна, так как Windows обычно немедленно отбрасывает всю информацию о невидимом изображении. Это приходится делать потому, что в противном случае для сохранения экранных данных потребовался бы астрономический объем памяти. Типичный компьютер может работать с видеокартой, отображающей изображение размером 1024x768 пикселей при цветовой глубине 24 бита, что подразумевает, что на хранения каждого пикселя экрана потребуется 3 байта, т.е. 2,25 Мбайт на весь экран (что означает 24-битная цветовая глубина будет пояснено далее в этой главе). Однако нередко оказывается, что пользователь работает с 10 или 20 минимизированными окнами в панели задач. В худшем случае получаем 20 окон, каждое из которых занимает полный экран в развернутом виде. Если бы Windows действительно сохраняла всю визуальную информацию этих окон, ожидая момента, когда пользователь развернет их, то понадобилось бы 45 Мбайт видеопамяти! В наше время хорошая видеокарта имеет 64, 128, 256 или 512 Мбайт памяти и справится с этим, но всего несколько лет назад 4 Мбайт видеопамяти были обычным делом, и тогда избыток пришлось бы сохранять в основной памяти компьютера. Множество людей до сих пор работают на старых машинах, неко-
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |