Этот ответ полностью игнорирует ваш вопрос о создании кнопок с забавными фигурами и вместо этого предназначен только для создания чего-то вроде примера, на котором вы указали ссылку на: Идентификация состояния на карте путем нажатия или наведения мыши.
Для определения состояния прост:
Если вы можете присвоить каждое государство цвета (даже если это всего лишь очень немного отличается), вы можете использовать GetPixel
, чтобы проверить, в какой стране/цвета мыши щелкнула или зависание ..
Если вы не хотите видеть видимые цвета, вы все равно можете использовать один и тот же трюк, просто используя две наложенные карты и покажите верхнюю карту, используя цветной снизу в качестве таблицы поиска.
Конечно, вам даже не нужно указывать карту поиска в элемент управления; вы можете просто использовать его Bitmap
, если он имеет тот же размер, что и видимая карта.
Не займет больше нескольких строк кода в winforms. Настройка списка состояний и их заполнение цветами будет более эффективной.
Изменить цвет более сложный. Я думаю, что я бы использовал довольно разнообразный подход: кодирование алгоритма флуд-заливки довольно просто; wikipedia имеет несколько хороших, особенно без рекурсии (на основе очереди), очень просто реализовать.
Таким образом, вы могли бы использовать наложенную копию карты и заливку состояния при наведении указатель мыши .. (Для этого, чтобы работать, вы должны убедиться, что государства может быть floodfilled, то есть, что они имеют закрытые контуры. Это может быть частью подготовки крася их.)
Когда мышь перемещается в другое состояние/цвет вы бы восстановить оригинальную карту ..
Ваш пример имеет приятный, если несколько медленно, анимация. Это было бы еще сложнее.Если вам нужно, что может быть WPF
действительно стоит задуматься .. Хотя красящая анимация выполнима в Winforms
, как и, возможно, с Color Matrix
и а Timer
это, конечно, не было построено для лоска ..
Вот кусок код, который идет по крайней мере, половину пути:
// simple but effective floodfill
void Fill4(Bitmap bmp, Point pt, Color c0, Color c1)
{
Rectangle bmpRect = new Rectangle(Point.Empty, bmp.Size);
Stack<Point> stack = new Stack<Point>();
int x0 = pt.X;
int y0 = pt.Y;
stack.Push(new Point(x0, y0));
while (stack.Any())
{
Point p = stack.Pop();
if (!bmpRect.Contains(p)) continue;
Color cx = bmp.GetPixel(p.X, p.Y);
if (cx == Color.Black) return;
if (cx == SeaColor) return;
if (cx == c0)
{
bmp.SetPixel(p.X, p.Y, c1);
stack.Push(new Point(p.X, p.Y + 1));
stack.Push(new Point(p.X, p.Y - 1));
stack.Push(new Point(p.X + 1, p.Y));
stack.Push(new Point(p.X - 1, p.Y));
}
}
}
// create a random color for the test
Random R = new Random();
// current and last mouse location
Point mouseLoc = Point.Empty;
Point lastMouseLoc = Point.Empty;
// recognize that we have move inside the same state
Color lastColor = Color.White;
// recognize the outside parts of the map
Color SeaColor = Color.Aquamarine;
// start a timer since Hover works only once
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
mouseLoc = e.Location;
timer1.Stop();
timer1.Interval = 333;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
// I keep the map in the Background image
Bitmap bmp = (Bitmap)pictureBox1.BackgroundImage;
// have we left the image?
if (!new Rectangle(Point.Empty, bmp.Size).Contains(mouseLoc)) return;
// still in the same state: nothing to do
if (lastColor == bmp.GetPixel(mouseLoc.X, mouseLoc.Y)) return;
// a random color
Color nextColor = Color.FromArgb(255, R.Next(255), R.Next(255), R.Next(256));
// we've been in the map before, so we restore the last state to white
if (lastMouseLoc != Point.Empty)
Fill4(bmp, lastMouseLoc,
bmp.GetPixel(lastMouseLoc.X, lastMouseLoc.Y), Color.White);
// now we color the current state
Fill4(bmp, mouseLoc, bmp.GetPixel(mouseLoc.X, mouseLoc.Y), nextColor);
// remember things, show image and stop the timer
lastMouseLoc = mouseLoc;
lastColor = nextColor;
pictureBox1.Image = bmp;
timer1.Stop();
}
Все, что вам нужно запустить это PictureBox pictureBox1
и Timer timer1
и версия карты, которая имеет только три цвета: черный, белый и Аквамарин.
Что нужно сделать, это нарисовать состояние, которое вы наведете на случайный цвет.
Ваши последующие шаги состоят в том, чтобы создать список всех состояний с номером, заголовком и информационным текстом. Затем вы создаете вторую версию карты, в которой вы будете окрашивать каждое состояние цветом, который вы получаете из номера состояния.
Вы можете использовать приведенный выше код для раскраски, если его немного расширить.
Наконец вы код подстановочным в Tick
случае, чтобы получить информацию, чтобы отобразить в Tooltip
..
Конечно, это при условии, что вы будете удовлетворены работы с картой в качестве Bitmap
. Источник для связи с файлом SVG
, где все данные хранятся в виде векторных данных в формате XML
. Разбор этого, чтобы получить Points
для GraphicsPath
, также является опцией, которая затем будет работать в векторной области. Но я думаю, это может занять несколько дней ..
Моя законченная, грубая версия, включая код для создания цветовой карты и кода для поиска, приходит в ок. 150 строк без комментариев.
Что вы используете? Winforms? WPF? – Omada
Добро пожаловать в StackOverflow, сложно ответить на ваш вопрос. Что именно вы пытаетесь достичь? Вы используете WPF, WinForms, web? Какая версия рамки - и что вы пробовали? – STW
Кнопка в каком контексте? Приложение WPF или Windows store? Используйте blend, чтобы проследить png в форму. – OakNinja