2015-02-06 176 views
0

我想製作一個顯示每個狀態的地圖,當將鼠標懸停在某個狀態上時,相應的形狀會改變顏色並且會顯示一些關於它的信息。爲按鈕創建自定義形狀

下面是類似的東西 kartograph.org/showcase/usa-projection

使用.NET 4.5,C#基於Web的例子,和WinForms是否有可能與巴頓和處理鼠標事件的實現這一目標?

+2

你在用什麼?的WinForms? WPF? – Omada 2015-02-06 19:51:29

+1

歡迎來到StackOverflow,很難根據你的問題提供答案。你究竟想達到什麼目的?你使用WPF,WinForms,網頁嗎?什麼框架版本 - 你嘗試過什麼? – STW 2015-02-06 19:52:05

+0

在什麼情況下的按鈕?一個WPF或Windows商店應用程序?使用混合來追蹤一個PNG的形狀。 – OakNinja 2015-02-06 19:52:41

回答

2

這不是一個完整的答案,但可能會讓你走上正確的道路。

WinForms不會讓你以這種方式使用Button對象; WinForms按鈕的定製能力非常有限 - 如果它是一個選項,WPF可能會適用於此。

要在WinForms中執行此操作,您可能需要使用GDI並將每個狀態加載到它自己的Graphics對象中,併爲Click事件等編寫自己的管道。雖然我不能提供一個具體的例子,但它應該是可行的,但它也可能是一個相當大的工作量(特別是對於諸如圖像的透明部分之類的東西)。但是,如果您要麼查看WPF,要麼查看與GDI對象的交互,您應該可以取得進展。

+0

我並不想要一個特別的按鈕,但一些工作..我想我會採取你的建議和使用WPF,但我必須先熟悉它自己..感謝您的幫助 – 2015-02-06 20:37:11

0

這個答案完全忽略了關於創建具有滑稽形狀的按鈕的問題,而只處理了構建類似於您顯示的鏈接的示例:通過單擊或懸停鼠標來標識地圖上的狀態。

要識別的狀態很簡單:

如果你可以指定每個狀態的顏色(即使它僅僅是非常略有不同),你可以使用GetPixel來檢查哪個國家/彩色鼠標點擊或爲懸停..

如果您不想看到可見的顏色,您仍然可以使用相同的技巧,只需使用兩個疊加的地圖並顯示頂部地圖,同時使用下面的彩色地圖作爲查找表。

當然,你甚至不需要把查找映射到控件中;只要它與可見地圖尺寸相同,就可以簡單地使用它的Bitmap

在winforms中不會佔用更多的代碼行。設置狀態列表並填充顏色將會有更多的工作。

改變顏色比較棘手。我想我會在這裏使用一個相當不同的方法:編碼floodfill算法非常簡單; wikipedia有幾個很好的,特別是沒有遞歸(基於隊列)的實現非常簡單。

所以,你可以使用地圖的覆蓋副本,floodfill狀態鼠標懸停在..(對於這個工作,你需要確保狀態可以被floodfilled,即他們有封閉輪廓,這可能是他們着色的準備工作的一部分。)

當鼠標移動到不同的國家/顏色,你會恢復原來的地圖..

你舉的例子有一個很好的,如果有點慢,動畫。這將更加棘手。如果你需要,也許WPF真的是值得考慮的。雖然着色動畫Winforms是可行的爲好,也許有Color MatrixTimer它肯定不是爲浮華建..

這裏是一塊代碼去至少有一半的方式:

// 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 pictureBox1Timer timer1,並且只有3種顏色地圖的版本:黑色,白色和海藍寶石。

它會做的是畫一個隨機顏色懸停的狀態。

您的下一步是創建一個包含數字,標題和信息文本的所有狀態列表。然後,您創建第二個版本的地圖,使用從州編號中派生出的顏色爲每個州的顏色着色。

如果稍微擴大一點,可以使用上面的代碼着色。

最後你的代碼在Tick事件的查找來獲得信息,以在Tooltip顯示..

當然,這是假設你是滿意與地圖爲Bitmap工作。要鏈接的源使用SVG文件,其中所有數據都以XML格式存儲爲矢量數據。解析這個得到PointsGraphicsPath也是一個選項,然後將在矢量領域工作。但我想這可能需要幾天的時間才能建立..

我完成,粗糙的版本,包括創建顏色映射的代碼和執行查找的代碼進來ca. 150行,沒有評論。