Отображение масштабируемой карты с горячими точками в C#
Создание масштабируемой карты с горячими точками на удивление легко, хотя получить правильные детали немного сложно. Программа отображает карту в нескольких разных масштабах. Если карта не будет соответствовать форме в текущем масштабе, она отобразит полосы прокрутки, чтобы вы могли перемещаться по карте. Если вы наведите курсор на точку доступа на карте (города в этом примере), курсор изменится на руку. Наконец, если вы нажмете точку доступа, программа отобразит сообщение. В реальном приложении вы можете предпринять другие действия, такие как открытие формы или страницы браузера для точки доступа.
Во время разработки я создал меню «Масштаб» с записями Full Scale, 1/2 и 1/4. Вы можете добавить другие записи, если они имеют смысл для вашей масштабируемой карты.
Я установил свойство Tag каждого свойства шкалы для соответствующего коэффициента масштабирования. Полная шкала получает значение 1, 1/2 получает значение 0,5, а 1/4 получает значение 0,25. Все эти записи используют один и тот же обработчик событий Click, и этот код использует запись Tag, чтобы увидеть, как она должна масштабировать масштабируемую карту.
Это делает удивительно легким добавить новые масштабы. Просто создайте новую запись в меню, установите ее свойство Tag и сделайте так, чтобы он использовал один и тот же обработчик событий.
Также во время разработки я добавил изображение масштабируемой карты к ресурсам программы. (Откройте меню «Проект» и выберите «Свойства». На вкладке «Ресурсы» откройте раскрывающееся меню «Добавить ресурс», выберите «Добавить существующий файл», выберите файл изображения карты и нажмите «Добавить».)
Форма программы содержит элемент управления Panel с AutoScroll = True. Этот элемент управления содержит PictureBox с именем picMap, который отображает изображение карты. Если picMap слишком велика, чтобы вписаться в панель , панель Panel автоматически отображает полосы прокрутки и соответственно перемещает picMap, когда пользователь прокручивает.
Во время выполнения код начинается с определения некоторых переменных и путем инициализации списка Hotspots.
// Карта. private Bitmap Map; // Горячие точки. private ListHotspots = new List (); // Текущий масштаб. private float MapScale; // Подготовьте карту для первого просмотра. private void Form1_Load(object sender, EventArgs e) { // Инициализация горячих точек. Hotspots.Add(new Rectangle(88, 509, 22, 22)); Hotspots.Add(new Rectangle(140, 577, 20, 20)); Hotspots.Add(new Rectangle(161, 609, 20, 20)); ... Hotspots.Add(new Rectangle(1234, 1076, 16, 18)); // Если мы должны нарисовать горячие точки, добавьте их на карту. Map = Properties.Resources.GCMap; #if DRAW_HOTSPOTS using (Graphics gr = Graphics.FromImage(Map)) { foreach (Rectangle hotspot in Hotspots) { gr.FillRectangle(Brushes.Blue, hotspot); } } #endif // Отображение исходной карты. picMap.SizeMode = PictureBoxSizeMode.Zoom; picMap.Image = Map; // Начнем с малого масштаба. SetMapScale(mnuScale4); }
После определения переменных и инициализации списка Hotspots, код загружает масштабируемое изображение карты из ресурса. Затем, если определена директива препроцессора DRAW_HOTSPOTS (она прокомментирована в коде, который вы можете скачать), программа отмечает каждую точку доступа синим прямоугольником.
Код устанавливает свойство picMap элемента управления SizeMode в Zoom, чтобы элемент управления заставлял его изображение заполнять доступную область управления. Затем программа устанавливает свойство Image элемента управления на изображение карты.
Обработчик событий Form_Load заканчивается вызовом метода SetMapScale, показанного в следующем коде, для отображения масштабируемой карты в масштабе, выбранном mnuScale4 tt > пункт меню (шкала 1/4).
// Масштабируем карту. private void mnuScaleMap_Click(object sender, EventArgs e) { SetMapScale(sender as ToolStripMenuItem); } private void SetMapScale(ToolStripMenuItem checked_item) { // Выберите правильный пункт меню. foreach (ToolStripMenuItem item in scaleToolStripMenuItem.DropDownItems) item.Checked = (item == checked_item); // Масштабируем карту. MapScale = float.Parse(checked_item.Tag.ToString()); picMap.Size = new Size( (int)(Map.Width / MapScale), (int)(Map.Height / MapScale)); }
Метод mnuScaleMap_Click - это обработчик событий, используемый всеми элементами меню шкалы. Он просто вызывает SetMapScale, передавая этот метод элементу меню, который поднял событие Click.
Метод SetMapScale проверяет нужный пункт меню и снимает флажки с других элементов. Затем он анализирует свойство Tag выбранного элемента и сохраняет его в переменной MapScale. Он заканчивается путем калибровки элемента управления picMap, поэтому он масштабирует карту соответствующим образом. Например, если мы просматриваем карту в масштабе 1/2, то MapScale - 0,5, а PictureBox - вдвое больше, чем это необходимо для отображения карты в полном размере. PictureBox автоматически масштабирует карту, чтобы она соответствовала.
Единственные другие части кода, которые я сейчас объясню, касаются обнаружения горячих точек, когда мышь перемещается по ним. Метод HotspotAtPoint, показанный в следующем коде, возвращает индекс точки доступа в определенной позиции.
// Возвращаем индекс точки доступа в этот момент // или -1, если там нет хот-спота. private int HotspotAtPoint(Point mouse_point) { // Отрегулируйте текущий масштаб карты. mouse_point = new Point( (int)(mouse_point.X / MapScale), (int)(mouse_point.Y / MapScale)); // Проверяем горячие точки. for (int i = 0; i < Hotspots.Count; i++) if (Hotspots[i].Contains(mouse_point)) return i; // Мы не нашли точку доступа, содержащую точку. return -1; }
Метод HotspotAtPoint принимает в качестве параметра точку в координатах элемента управления PictureBox. Метод начинается с масштабирования координат точки X и Y, чтобы он представлял точку в исходной системе координат карты. Например, если карта отображается в масштабе 1/2, то точка (100, 50) в PictureBox действительно представляет точку (100 / 0,5, 50 / 0,5) = (200, 100) на карте.
Затем код перебирается через список Hotspots, который ищет точку доступа, содержащую позицию мыши. Если он найдет такую точку доступа, код вернет свой индекс. Если нет точки доступа, содержащей точку, метод возвращает -1.
Для бонусных очков вы можете использовать следующий оператор LINQ вместо этого цикла, чтобы найти точку доступа, содержащую позицию мыши. Код примера включает этот комментарий.
return Hotspots.FindIndex(hotspot => hotspot.Contains(mouse_point));
Следующий код показывает, как программа использует метод HotspotAtPoint.
// Увидим, если мы закончили точку доступа. private void picMap_MouseMove(object sender, MouseEventArgs e) { // Увидим, если мы закончим горячую точку. if (HotspotAtPoint(e.Location) >= 0) picMap.Cursor = Cursors.Hand; else picMap.Cursor = Cursors.Default; } // Посмотрим, нажали ли мы горячую точку. private void picMap_MouseClick(object sender, MouseEventArgs e) { int i = HotspotAtPoint(e.Location); if (i >= 0) MessageBox.Show("You clicked hotspot " + i); }
Когда мышь перемещается по элементу управления picMap, выполняется обработчик события picMap_MouseMove. Он вызывает HotspotAtPoint, чтобы получить индекс точки доступа под мышью или -1, если нет точки доступа. Если мышь находится над точкой доступа, код устанавливает курсор в сторону. Если мышь не находится над точкой доступа, код устанавливает курсор на значение по умолчанию.
Когда пользователь нажимает на масштабируемую карту, обработчик события picMap_MouseClick вызывает HotspotAtPoint, чтобы получить индекс точки доступа под мышью. Если результат равен по крайней мере 0, что указывает на то, что мышь находится над точкой доступа, код отображает сообщение, указывающее индекс точки доступа. В реальном приложении вы можете захотеть, чтобы код выполнял что-то еще, например, просматривая информацию о горячей точке и отображая ее.