2015-02-06 174 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行,没有评论。