Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
113 views
in Technique[技术] by (71.8m points)

c# - Make a Map of Buttons?

How do I do the following I'm not asking for specific code but I need some direction as I have been racking my brains on this for weeks. Simply I want to make a map of the eg. united states and each state is a different picture or area that can be moused over and clicked. I tried playing with png and transparencies but I'm at a dead end. More ambitiously I'd like to drag labels with state capitals over each state and drop them there then have a process where if the label/capital matches the state it correct else it's not.

I've tried GIS(?) I want to do this C# but I can't get traction how to do it so far. Can anyone help? Is this too difficult in C#? SHould i be using another approach? Please what is the approach?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The good news first: The programming part is not so hard and even with good old Winforms you can do the core checks in a few lines. The clickable areas can't be Buttons in Winforms, however.

Here are two solutions:

Solution 1 : You can define a list of areas, called regions and test if one got clicked.

Here is a start: I define a very simple Rectangle Region and a not so simple Polygon Region and test on each click if one was hit. If it was hit I output its data into the Form's title text:

//..
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; }
    }

}

The regions in the test programm are not visible. For testing you may want to add something like this:

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); }
}

But now for the bad news: You can define regions to be complicated polygons that look like real states, however that is a lot of work! There are ready-made image map editors out there in the web for making clickable maps on websites. Your best course might be to use one of these to create all those polygons and then convert the html output to a list of points you can read into your program. You may even get lucky and find ready image maps for the USA, but I haven't looked..

Update: There are many image maps of the USA out there. One is even on wikipedia. Converting these coordinates to fit your map will be a task but lot easier than creating them from scratch, imo. I have changed the code to include one list of cordinates from the wikipedia source. Guess the state!

I have implmented a program that lets you click on a state and displays the name in 78 lines of code, excluding the text file with the 50 states.

Solution 2:

Instead of a list of polygons you can prepare a colored map and use the colors as keys into a Dictionary<Color, string> or Dictionary<Color, StateInfo>. You must make sure that each state has one unique color and that the image is not compressed as jpeg, which would introduce artifacts and mess up the key mapping.

Next you map each color to the related info; this is the real work because you must know those states to create the Dictionary ;-)

Finally you can look up the clicked color in the Dictionary you have created:

Color c = ((Bitmap) pictureBox1.Image).GetPixel(e.X, e.Y)
string StateName = stateDictionary[c];

If you are using a class or struct as your value in the dictionary you can include the capital etc..

You can zoom but must scale the click location accordingly; you can even display a geographical Image if you look up the key color not in the PictureBox but in an invisible color code bitmap. All in all an even simpler solution imo.. your pick!

Once you got that working, you can play with drag&drop. Here you'll want to test on DragDrop or maybe on Mouseup to see where you have dropped the Label.

This is a nice project and well worth of creating a few classes to make things easier and more expandable..!

For real Buttons you may get lucky with WPF.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...