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