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

Сайт управляется системой uCoz