netlib.narod.ru | < Назад | Оглавление | Далее > |
Иногда реализация метода OnPaint требует много процессорного времени и памяти. Скажем, клиентская область может содержать сложное изображение, строящееся долгое время. В этом случае отличным решением является создание теневого растра (shadow bitmap) — карты, на которой программа рисует вне метода OnPaint то, что должно быть нарисовано в клиентской области. Тогда OnPaint сводится к простому вызову DrawImage.
В главе 8 приведена программа Scribble, позволяющая рисовать мышью на клиентской области. Но тогда я мог показать вам единственное решение, сохраняющее изображение для обновления при выполнении метода OnPaint. Это было реализовано в программе ScribbleWithSave, сохранявшей все координаты в объектах ArrayList. Ничего некорректного в таком подходе нет. Фактически, чтобы позволить пользователю редактировать рисунок путем изменения отдельных линий, нужно сохранять все точки координат. ScribbleWithSave — это первый шаг к созданию программы для работы с графикой, сохраняющей рисунок в одном из форматов метафайлов.
Вот новая версия программы Scribble — ScribbleWithBitmap, которая хранит все изображение в большой битовой карте. Данная программа может стать первым шагом к созданию программы для живописи.
ScribbleWithBitmap.cs
//--------------------------------------------------- // ScribbleWithBitmap.cs (C) 2001 by Charles Petzold //--------------------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class ScribbleWithBitmap: Form { bool bTracking; Point ptLast; Bitmap bitmap; Graphics grfxBm; public static void Main() { Application.Run(new ScribbleWithBitmap()); } public ScribbleWithBitmap() { Text = "Scribble with Bitmap"; BackColor = SystemColors.Window; ForeColor = SystemColors.WindowText; // Создаем битовую карту Size size = SystemInformation.PrimaryMonitorMaximizedWindowSize; bitmap = new Bitmap(size.Width, size.Height); // Создаем объект Graphics для битовой карты grfxBm = Graphics.FromImage(bitmap); grfxBm.Clear(BackColor); } protected override void OnMouseDown(MouseEventArgs mea) { if (mea.Button != MouseButtons.Left) return; ptLast = new Point(mea.X, mea.Y); bTracking = true; } protected override void OnMouseMove(MouseEventArgs mea) { if (!bTracking) return; Point ptNew = new Point(mea.X, mea.Y); Pen pen = new Pen(ForeColor); Graphics grfx = CreateGraphics(); grfx.DrawLine(pen, ptLast, ptNew); grfx.Dispose(); // Рисуем на битовой карте grfxBm.DrawLine(pen, ptLast, ptNew); ptLast = ptNew; } protected override void OnMouseUp(MouseEventArgs mea) { bTracking = false; } protected override void OnPaint(PaintEventArgs pea) { Graphics grfx = pea.Graphics; // Отображаем битовую карту grfx.DrawImage(bitmap, 0, 0, bitmap.Width, bitmap.Height); } }
Инструкции, добавленные в базовую программу Scribble, выделены комментариями — их немного. В конструкторе я создаю битовую карту, размер которой определяется возвращаемым значением SystemInformation.PrimaryMonitorMaximizedWindowSize. Метод FromImage класса Graphics получает объект Graphics, и затем вызовом метода Clear инициализируется битовая карта. При выполнении метода OnMouseMove метод DrawLine рисует на битовой карте и в клиентской области. При выполнении метода OnPaint осуществляется отображение битовой карты вызовом метода DrawImage.
Версия ScribbleWithBitmap гораздо короче и приятнее версии ScribbleWithSave. Однако за эту простоту надо платить: в прямом смысле теряются координаты ломанных линий. Извлечь их снова из битовой карты не так-то легко.
Вот еще одно отличие: эффективность OnPaint в ScribbleWithSave зависит от степени сложности рисунка. Чем больше на нем кривых, тем больше времени требуется методу OnPaint на их перерисовку. Скорость работы OnPaint в ScribbleWithBitmap не зависит от сложности изображения.
Как я уже говорил, ScribbleWithBitmap создает в конструкторе битовую карту, имеющую размер развернутого окна. Это хорошо показывает, какой размер должен быть у теневого растра. Однако если при работе с ScribbleWithBitmap пользователь изменит разрешение экрана, битовая карта может перестать соответствовать действительности. На такой случай установите обработчик события DisplaySettingsChanged класса SystemEvents, определенного в пространстве имен Microsoft.Win32. Но как же реагировать на само событие? Если разрешение дисплея увеличилось, можно создать новую битовую карту соответствующего размера и скопировать в нее содержимое старой карты. А если разрешение уменьшилось? Следует ли просто создать битовую карту меньшего размера и отсечь часть имеющегося изображения? Непростая задача!
netlib.narod.ru | < Назад | Оглавление | Далее > |