Сделать карту кнопок?

Как мне сделать следующее? Я не спрашиваю о конкретном коде, но мне нужно какое-то направление, поскольку я ломал голову над этим уже несколько недель. Просто я хочу сделать карту, например. Соединенные Штаты и каждый штат - это отдельная картинка или область, которую можно навести и щелкнуть. Я пытался играть с 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.

Другие вопросы по тегам