Сделать карту кнопок?
Как мне сделать следующее? Я не спрашиваю о конкретном коде, но мне нужно какое-то направление, поскольку я ломал голову над этим уже несколько недель. Просто я хочу сделать карту, например. Соединенные Штаты и каждый штат - это отдельная картинка или область, которую можно навести и щелкнуть. Я пытался играть с PNG и прозрачные пленки, но я в тупике. Более амбициозно, я бы хотел перетаскивать надписи с прописными буквами над каждым состоянием, а затем отбрасывать их там, тогда есть процесс, в котором если метка / заглавная буква соответствуют состоянию, которое она исправляет, иначе это не так.
Я пробовал ГИС (?) Я хочу сделать это на C#, но я не могу понять, как это сделать до сих пор. Кто-нибудь может помочь? Это слишком сложно в C#? Должен ли я использовать другой подход? Пожалуйста, какой подход?
1 ответ
Сначала хорошие новости: часть программирования не так сложна, и даже со старыми добрыми Winforms вы можете выполнять проверки ядра в несколько строк. Однако интерактивные области не могут быть кнопками в Winforms.
Вот два решения:
Решение 1: Вы можете определить список областей, называемых регионами, и проверить, нажали ли вы один из них.
Вот начало: я определяю очень простой Rectangle Region
и не все так просто Polygon Region
и проверяйте при каждом щелчке, если один был поражен. Если это было сделано, я выводил его данные в текст заголовка формы:
//..
using System.Drawing.Drawing2D;
//..
public Form1()
{
InitializeComponent();
// most real states don't look like rectangles
Region r = new Region(new Rectangle(0, 0, 99, 99));
regions.Add(r);
List<int> coords = new List<int>() {23,137, 76,151, 61,203,
117,283, 115,289, 124,303, 112,329, 76,325, 34,279, 11,162};
List<Point> points = new List<Point>();
for (int i = 0; i < coords.Count ; i += 2)
points.Add(new Point(coords[i], coords[i+1]));
byte[] fillmodes = new byte[points.Count];
for (int i = 0 ; i < fillmodes.Length; i++) fillmodes[i] = 1;
GraphicsPath GP = new GraphicsPath(points.ToArray(), fillmodes);
regions.Add(r);
}
List<Region> regions = new List<Region>();
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
using (Graphics G = pictureBox1.CreateGraphics() )
foreach(Region r in regions)
{
Region ri = r.Clone();
ri.Intersect(new Rectangle(e.X, e.Y, 1, 1));
if (!ri.IsEmpty(G)) // hurray, we got a hit
{ this.Text = r.GetBounds(G).ToString(); break; }
}
}
Области в тестовой программе не видны. Для тестирования вы можете добавить что-то вроде этого:
private void button1_Click(object sender, EventArgs e)
{ // paint a non-persistent filling
using (Graphics G = pictureBox1.CreateGraphics())
foreach (Region r in regions)
{ G.FillRegion(Brushes.Red, r); }
}
Но теперь для плохих новостей: вы можете определить регионы как сложные многоугольники, которые выглядят как реальные состояния, но это много работы! В сети есть готовые редакторы карт изображений для создания интерактивных карт на веб-сайтах. Лучше всего использовать один из них для создания всех этих многоугольников, а затем преобразовать вывод html в список точек, которые вы можете прочитать в своей программе. Возможно, вам даже повезет, и вы найдете готовые карты изображений для США, но я не смотрел..
Обновление: есть много карт с изображением США. Один даже в википедии. Преобразование этих координат в соответствии с вашей картой будет задачей, но намного проще, чем создавать их с нуля, imo. Я изменил код для включения одного списка кординатов из источника в Википедии. Угадай государство!
Я реализовал программу, которая позволяет нажимать на состояние и отображает имя в 78 строках кода, исключая текстовый файл с 50 состояниями.
Решение 2:
Вместо списка полигонов вы можете подготовить цветную карту и использовать цвета в качестве ключей в Dictionary<Color, string>
или же Dictionary<Color, StateInfo>
, Вы должны убедиться, что каждое состояние имеет один уникальный цвет и что изображение не сжимается в формате jpeg, что может привести к появлению артефактов и путанице в сопоставлении клавиш.
Затем вы сопоставляете каждый цвет с соответствующей информацией; это настоящая работа, потому что вы должны знать эти состояния для создания словаря;-)
Наконец, вы можете посмотреть выбранный цвет в словаре, который вы создали:
Color c = ((Bitmap) pictureBox1.Image).GetPixel(e.X, e.Y)
string StateName = stateDictionary[c];
Если вы используете класс или структуру в качестве значения в словаре, вы можете включить заглавные буквы и т. Д.
Вы можете масштабировать, но должны масштабировать местоположение щелчка соответственно; Вы даже можете отобразить географическое изображение, если посмотрите на цвет ключа не в PictureBox, а в невидимом растровом коде цвета. В общем, еще более простое решение, имхо.. Ваш выбор!
Как только вы это заработаете, вы можете играть с перетаскиванием. Здесь вы захотите протестировать DragDrop или, возможно, Mouseup, чтобы увидеть, где вы сбросили метку.
Это хороший проект, и стоит создать несколько классов, чтобы упростить и расширить его возможности!
Для настоящих кнопок вам повезет с WPF.