| 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 | < Назад | Оглавление | Далее > |