2015-02-06 4 views
0

Я хотел бы создать карту, показывающую каждое состояние, зависающее над определенным состоянием, соответствующая форма изменит цвет, и появится некоторая информация о нем.Создайте пользовательскую форму для кнопки

Вот веб-пример чего-то подобного kartograph.org/showcase/usa-projection

Использование .NET 4.5, C# и WinForms можно ли добиться этого с помощью кнопки и обработки событий мыши ?

+2

Что вы используете? Winforms? WPF? – Omada

+1

Добро пожаловать в StackOverflow, сложно ответить на ваш вопрос. Что именно вы пытаетесь достичь? Вы используете WPF, WinForms, web? Какая версия рамки - и что вы пробовали? – STW

+0

Кнопка в каком контексте? Приложение WPF или Windows store? Используйте blend, чтобы проследить png в форму. – OakNinja

ответ

2

Это не полный ответ, но может привести вас к правильному пути.

WinForms не позволит вам использовать объект Button таким образом; Кнопки WinForms довольно ограничены в своей способности настраиваться - WPF, скорее всего, поддается этому, если это вариант.

Для этого в WinForms вполне вероятно, что вам нужно будет использовать GDI и загружать каждое состояние в собственный графический объект и писать собственную сантехнику для событий кликов и т. Д. Хотя я не могу предложить конкретный пример, это должно быть осуществимо, но также, вероятно, будет достаточно много работы (особенно для таких вещей, как прозрачные части изображения).

Однако, если вы либо смотрите в WPF, либо взаимодействуете с объектами GDI, вы сможете добиться прогресса.

+0

Мне не нужна кнопка в частности, но что-то для работы. Я думаю, что я собираюсь взять ваш совет и использовать WPF, но сначала я должен ознакомиться с ним. Спасибо за вашу помощь. –

0

Этот ответ полностью игнорирует ваш вопрос о создании кнопок с забавными фигурами и вместо этого предназначен только для создания чего-то вроде примера, на котором вы указали ссылку на: Идентификация состояния на карте путем нажатия или наведения мыши.

Для определения состояния прост:

Если вы можете присвоить каждое государство цвета (даже если это всего лишь очень немного отличается), вы можете использовать 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 строк без комментариев.

Смежные вопросы