Попадание в заданную область и операции перетаскивания для PictureBox
Попадание в заданную область и операции перетаскивания для PictureBox
Вы, конечно, можете отображать изображения Bitmap на поверхности любого производного класса Control непосредственно, но вы быстро обнаружите, что гораздо более широкие возможности и лучший контроль дает размещение изображения в рамках типа PictureBox. Например, поскольку тип PictureBox является производным от Control, он наследует соответствующие функциональные возможности, например, способность обрабатывать различные события, поддерживать всплывающие подсказки или контекстные меню и т.д. Такого поведения можно добиться и при непосредственном использовании Bitmap, но при этом вам придется создавать соответствующий программный код самостоятельно.
Чтобы продемонстрировать пользу типа PictureBox, давайте создадим простую "игру", которая будет способна "распознать" присутствие указателя мыши на графическом изображении. При щелчке пользователя кнопкой мыши в границах изображения включается режим "перетаскивания", и пользователь может перемещать изображение по форме. Чтобы сделать ситуацию интереснее, давайте проконтролируем, где пользователь "отпустит" изображение. Если это произойдет в рамках некоторого прямоугольника визуализации GDI+, будет выполнено некоторое заданное действие (оно будет описано чуть позже). Вы, возможно, знаете, что процесс обнаружения событий мыши в заданной области называется проверкой попадания в заданную область.
Тип PictureBox наследует большинство своих функциональных возможностей от базового класса Control. Ряд членов Control был уже рассмотрен в предыдущей главе, и это позволяет нам сразу перейти к обсуждению вопроса назначения изображения члену PictureBox с помощью свойства Image (снова заметим, что файл happyDude.bmp должен находиться в каталоге приложения).
public partial class MainForm: Form {
// Содержит изображение улыбающегося лица.
private PictureBox happyBox = new PictureBox();
public MainForm() {
// Конфигурация PictureBox.
happyBox.SizeMode = PictureBoxSizeMode.StretchImage;
happyBox.Locaton = new System.Drawing.Point(64, 32);
happyBox.Size = new System.Drawing.Size(50, 50);
happyBox.Cursor = Cursors.Hand;
happyBox.Image = new Bitmap("happyDude.bmp");
// Добавление в коллекцию Controls формы.
Controls.Add(happyBox);
}
}
Кроме свойства Image, нам будет интересно только свойство SizeMode, для которого используются значения перечня PiсtureBoxSizeMode. Этот тип используется для контроля того, как соответствующее изображение должно отображаться в рамках рабочего прямоугольника PictureBox. Здесь мы используем PictureBoxSizeMode.StretchImage, означающее то, что изображение следует растянуть на всю заданную типом PictureBox область (которая в данном случае имеет размеры 50?50 пикселей).
Следующей задачей является обработка событий MouseMove.MouseUр и MouseDown для члена-переменной PictureBox с помощью вполне стандартного синтаксиса обработки событий C#.
public MainForm() {
…
// Добавление обработчиков для ряда событий.
happyBox.MouseDown += new MouseEventHandler(happyBox_MouseDown);
happyBox.MouseUp += new MouseEventHandler(happyBox_MouseUp);
happyBox.MouseMove += new MouseEventHandler(hарруВох_MouseMove);
Controls.Add(happyBox);
InitializeComponent();
}
Обработчик событий MouseDown сохраняет поступающие на вход значения координат (х, у) местоположения указателя в двух членах-переменных (oldX и oldY) для использования в дальнейшем, а также устанавливает значение true (истина) для члена-переменной (isDragging) типа System.Boolean, когда происходит перетаскивание. Добавьте эти члены-переменные в форму и реализуйте обработчик события MouseDown так, как предлагается ниже.
private void happyBox_MouseDown(object sender, MouseEventArgs e) {
isDragging = true;
oldX = e.X;
oldY = e.Y;
}
Обработчик события MouseMove просто изменяет местоположение PictureBox (с помощью свойств Тор и Left), в зависимости от сдвига положения указателя по сравнению со значениями, полученными при обработке события MouseDown.
private void happyBox_MouseMove(object sender, MouseEventArgs e) {
if (isDragging) {
// Необходимо для вычисления нового значения Y в зависимости
// от того, где была нажата кнопка мыши.
happyBox.Top = happyBox.Top + (e.Y – oldY);
// То же для X (используя в качестве основы oldX).
happyBox.Left = happyBox.Left + (e.X – oldX);
}
}
Обработчик события MouseUp устанавливает для isDragging значение false (ложь), чтобы сигнализировать об окончаний операции перетаскивания. Кроме того, если событие MouseUp происходит в тот момент, когда PictureBox содержится в пределах отображаемого средствами GDI+ Rectangle, мы будем считать, что пользователь победил в этой (очень примитивной) игре. Сначала добавьте в класс Form член Rectangle (с именем dropRect и заданными размерами).
public partial class MainForm: Form {
private PictureBox happyBox = new PictureBox();
private int oldX, oldY;
private bool isDragging;
private Rectangle dropRect = new Rectangle(100, 100, 140, 170);
…
}
Обработчик события MouseUp теперь можно реализовать так.
private void happyBox_MouseUp(object sender, MouseEventArgs e) {
isDragging = false;
// Находится ли указатель внутри заданного прямоугольника?
if (dropRect.Contains(happyBox.Bounds)) MessageBox.Show("Вы победили!", "Этот сладкий вкус умения…");
}
Наконец, в рамках обработки события Paint нужно отобразить в форме прямоугольную область (заданную переменной dropRect).
private void MainForm_Paint(object sender, PaintEventArgs e) {
// Отображение целевого прямоугольника.
Graphics g = e.Graphics;
g.FillRectangle(Brushes.AntiqueWhite, dropRect);
// Вывод инструкции.
g.DrawString("Тащите этого парня сюда!", new Font("Times New Roman", 25), Brushes.Red, dropRect);
}
Запустив свое приложение, вы увидите окно, подобное показанному на рис. 20.19.
Рис. 20.19. Увлекательная игра "Счастливый пижон"
Если вы сделаете все, что требуется для победы в игре, вы увидите окно "восхваления", показанное на рис. 20.20.
Рис 20.20. У вас железные нервы!
Исходный код. Проект DraggingImages размещен в подкаталоге, соответствующем главе 20.