13.3. Рисование без события Paint

А что, если нужно нарисовать что-то на форме вне обработчика события Paint — например, по нажатию кнопки? Как получить объект Graphics, который станет поверхностью рисования нужного нам элемента управления или формы? Существует несколько способов сделать это, но мы рассмотрим только два, наиболее удобных с моей точки зрения.

Создайте новое приложение, положите на его поверхность кнопку и напишите следующий код, выполняемый по ее нажатию:

   Graphics g = Graphics.FromHwnd(Handle);
   g.DrawRectangle(SystemPens.ActiveBorder,
      new Rectangle(10, 10, ClientSize.Width - 20,
          ClientSize.Height - 20));

Чтобы получить объект для рисования, в этом примере используется статичный метод FromHwnd() класса Graphics. Методу нужно передать свойство Handle окна, объект рисования которого вы хотите получить, а сам объект мы получаем в качестве результата работы метода.

Теперь мы можем рисовать на поверхности объекта рисования. Для примера я рисую прямоугольник с помощью метода DrawRectangle(). Этому методу передаются два параметра: перо (класс Pen), с помощью которого происходит рисование, и размеры в виде структуры Rectangle. С помощью класса Pen мы можем задать цвет и ширину пера (толщину получаемой линии). Мы пока с перьями не разбирались, поэтому я воспользовался системным пером под именем ActiveBorder из перечисления SystemPens. Перечисление SystemPens содержит системные перья, и перо ActiveBorder служит для рисования контуров окон.

В чем недостаток рисования по событию, отличному от события Paint? Непостоянность результата. Запустите пример и попробуйте нажать на кнопку. Прямоугольник появился, и пока вроде бы все прекрасно. А что, если переместить окно? Нарисованный прямоугольник снова на месте. А что, если свернуть окно и развернуть его заново? Наш рисунок исчезнет! До этого система запоминала наше окно и при перемещении окна сама восстанавливала его содержимое. Вы даже можете попытаться перекрыть свое окно другим окном, а потом убрать его, и, вполне вероятно, что прямоугольник снова окажется на своем месте. ОС пытается оптимизировать работу графики и сама восстанавливает рисунок формы. Но это не всегда так.

Когда система не может восстановить изображение формы (это обязательно происходит после восстановления окна из свернутого состояния), то она и не пытается прорисовать наш прямоугольник. Вместо этого ОС посылает окну сообщение о необходимости нарисовать свое содержимое и говорит — сделайте это самостоятельно. Поэтому то, что написано в обработчике Paint, гарантированно станет отображаться, а все остальное будет потеряно. Чтобы восстановить прямоугольник, придется нажимать кнопку заново. Вашего пользователя такой подход вряд ли обрадует, поэтому лучше выполнять рисование по событию Paint:

   bool bDrawRectangle = false;
   private void button1_Click(object sender, EventArgs e)
   {
     bDrawRectangle = true;
     Invalidate();
   }
   private void Form1_Paint(object sender, PaintEventArgs e)
   {
    if (bDrawRectangle)
      g.DrawRectangle(SystemPens.ActiveBorder,
         new Rectangle(10, 10, ClientSize.Width - 20,
                       ClientSize.Height - 20));
   }

В этом случае по нажатию кнопки значение переменной bDrawRectangle изменяется на true и вызывается метод Invalidate(), который заставляет форму перерисоваться. По событию Paint прямоугольник рисуется, только если переменная bDrawRectangle установлена в true. Теперь этот прямоугольник никуда не денется, даже если окно восстановят из свернутого состояния.

Да, я же обещал вам показать два способа получения объекта для рисования. Второй способ заключается в использовании метода CreateGraphics() формы:

   Graphics g = this.CreateGraphics();

Этот метод возвращает объект рисования для формы или элемента управления, для которого он был вызван. В данном случае он вызывается для this, а значит, вернет объект рисования текущей формы.

Предыдущая глава

13.2. Рисование по событию Paint

Следующая глава

13.4. Цвета .NET

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне