Доступ к объекту Graphics вне обработчика Paint
Доступ к объекту Graphics вне обработчика Paint
В некоторых редких случаях может понадобиться доступ к объекту Graphics вне контекста обработчика события Paint. Предположим, например, что нужно перерисовать небольшой круг с центром в точке (х, у), где был выполнен щелчок кнопки мыши. Чтобы получить действительный объект Graphics в рамках контекста обработчика событий MouseDown, можно, например, вызвать статический метод Graphics.FromHwnd(). Имея опыт использования Win32, вы можете знать, что HWND является структурой данных, представляющей окно Win32. В рамках платформы .NET наследуемое свойство Handle извлекает соответствующую структуру HWND, которую затем можно использовать в качестве параметра для Graphics. FromHwnd().
private void MainForm_MouseDown(object sender, MouseEventArgs e) {
// Получение объекта Graphics через Hwnd.
Graphics g = Graphics.FromHwnd(this.Handle);
// Рисование круга 10*10 по щелчку мыши.
g.FillEllipse(Brushes.Firebrick, e.X, e.Y, 10, 10);
// Освобождение объектов Graphic, созданных напрямую.
g.Dispose();
}
Эта логика отображает круг за пределами обработчика OnPaint(), но очень важно понимать, что когда выполняется обновление формы, все такие круги стираются! Это разумно, поскольку соответствующая визуализация выполнялась в контексте события MouseDown. Значительно лучшим подходом Является создание в обработчике события MouseDown нового типа Point, который добавляется к некоторой внутренней коллекции (например, List‹T›), и только затем вызывается Invalidate(). Тогда обработчик события Раint может просто "пройти" по коллекции и перерисовать каждый Point.
public partial class MainForm: Form {
// Используется для хранения всех Point.
private List‹Point› myPts = new List‹Point›();
publiс MainForm() {
…
this.MouseDown += new MouseEventHandler(MainForm_MouseDown);
}
private void MainForm_MouseDown(object sender, MouseEventArgs e) {
// Добавление в коллекцию.
myPts.Add(new Point(e.X, e.Y));
Invalidate();
}
private void MainForm_Paint(object sender, PaintEventArgs e) {
Graphics g = e.Graphics;
g.DrawString("Привет GDI+", new Font("Times New Roman", 20), new SolidBrush(Color.Black), 0, 0);
foreach(Point p in myPts) g.FillEllipse(Brushes.Firebrick, p.X, p.Y, 10, 10);
}
}
При таком подходе уже отображенные круги будут оставаться на месте, поскольку графическая визуализация обрабатывается в рамках события Paint. На рис. 20.1 показано окно тестового запуска этого приложения.
Рис 20.1. Простое графическое приложение
Исходный код. Проект BasiсPaintForm размещен в подкаталоге, соответствующем главе 20.