netlib.narod.ru | < Назад | Оглавление | Далее > |
Изображая на форме графические фигуры и текст, обычно сначала определяют координаты всех элементов, после чего рисуют их, вызывая соответствующие методы. Но часто в программах применяют интерфейс на основе мыши, чтобы дать пользователю возможность выбирать графические объекты и манипулировать ими. Значит, программа должна работать по обратному принципу, определяя координаты указателя, чтобы выяснить, на какой графический элемент указывает мышь.
Этот процесс называется определением позиции курсора (hit-testing). Он может быть довольно сложным, особенно если клиентское окно содержит перекрывающиеся фигуры и текст, набранный пропорциональным шрифтом, но иногда определить позицию курсора довольно просто. Фактически показанная выше программа MouseCursors определяет позицию курсора, чтобы узнать, какой вид ему следует придать.
Программа Checker рисует в своей клиентской области несколько прямоугольников. Если щелкнуть по нарисованному программой прямоугольнику, в нем появится крестик, который исчезнет при повторном щелчке.
Checker.cs
//---------------------------------------- // Checker.cs (C) 2001 by Charles Petzold //---------------------------------------- using System; using System.Drawing; using System.Windows.Forms; class Checker: Form { protected const int xNum = 5; // Кличество клеток по горизонтали protected const int yNum = 4; // Количество клеток по вертикали protected bool[,] abChecked = new bool[yNum, xNum]; protected int cxBlock, cyBlock; public static void Main() { Application.Run(new Checker()); } public Checker() { Text = "Checker"; BackColor = SystemColors.Window; ForeColor = SystemColors.WindowText; ResizeRedraw = true; OnResize(EventArgs.Empty); } protected override void OnResize(EventArgs ea) { base.OnResize(ea); // Иначе ResizeRedraw не будет работать cxBlock = ClientSize.Width / xNum; cyBlock = ClientSize.Height / yNum; } protected override void OnMouseUp(MouseEventArgs mea) { int x = mea.X / cxBlock; int y = mea.Y / cyBlock; if (x < xNum && y < yNum) { abChecked[y, x] ^= true; Invalidate(new Rectangle(x * cxBlock, y * cyBlock, cxBlock, cyBlock)); } } protected override void OnPaint(PaintEventArgs pea) { Graphics grfx = pea.Graphics; Pen pen = new Pen(ForeColor); for (int y = 0; y < yNum; y++) for (int x = 0; x < xNum; x++) { grfx.DrawRectangle(pen, x * cxBlock, y * cyBlock, cxBlock, cyBlock); if (abChecked[y, x]) { grfx.DrawLine(pen, x * cxBlock, y * cyBlock, (x + 1) * cxBlock, (y + 1) * cyBlock); grfx.DrawLine(pen, x * cxBlock, (y + 1) * cyBlock, (x + 1) * cxBlock, y * cyBlock); } } } }
При любом изменении размеров формы программа пересчитывает значения cxBlock и cyBlock, задающие размеры каждого прямоугольника. Программа также поддерживает массив abChecked, хранящий значения типа bool, каждое из которых указывает, есть ли крестик в некотором прямоугольнике. Метод OnPaint рисует контур каждого прямоугольника и, если значение abChecked для этого прямоугольника равно true, рисует в нем крестик.
Определение позиции курсора происходит при исполнении метода OnMouseUp (я выбрал именно его, а не OnMouseDown, чтобы точнее воспроизвести событие OnClick, происходящее при отпускании кнопки мыши). Программа делит значения координат мыши на cxBlock и cyBlock, чтобы получить значения индексов в массиве abChecked. После этого она инвертирует значение переменной типа bool и делает недействительным соответствующий прямоугольник.
Вот типичный вид программы Checker после зачеркивания нескольких прямоугольников:
netlib.narod.ru | < Назад | Оглавление | Далее > |