首先是好消息:编程部分并不难,即使使用良好的旧 Winforms,您也可以在几行代码内完成核心检查。但是,可点击区域不能是 Winforms 中的按钮。
这里有两种解决方案:
解决方案 1:您可以定义一个区域列表,称为区域并测试是否被点击。
这是一个开始:我定义了一个非常简单的Rectangle Region 和一个不那么简单的Polygon Region 并测试每次点击是否被点击。如果它被击中,我会将其数据输出到表单的标题文本中:
//..
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; }
}
}
测试程序中的区域不可见。为了进行测试,您可能需要添加如下内容:
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); }
}
但现在有个坏消息:您可以将区域定义为看起来像真实状态的复杂多边形,但这是很多工作的!网络上有现成的图像地图编辑器,用于在网站上制作可点击的地图。您最好的课程可能是使用其中一个来创建所有这些多边形,然后将 html 输出转换为您可以读入程序的点列表。你甚至可能会很幸运地找到现成的美国图像地图,但我还没有看过..
更新:那里有许多美国的图像地图。一个甚至在wikipedia 上。将这些坐标转换为适合您的地图将是一项任务,但比从头开始创建它们要容易得多,imo。我已更改代码以包含来自维基百科来源的一个坐标列表。猜猜状态!
我已经实现了一个程序,它允许您单击一个状态并在 78 行代码中显示名称,不包括具有 50 个状态的文本文件。
解决方案 2:
您可以准备一个彩色地图并将颜色用作Dictionary<Color, string> 或Dictionary<Color, StateInfo> 的键,而不是多边形列表。您必须确保每个状态都有一种唯一的颜色,并且图像没有被压缩为 jpeg,否则会引入伪影并弄乱键映射。
接下来将每种颜色映射到相关信息;这是真正的工作,因为您必须知道这些状态才能创建字典;-)
最后你可以在你创建的字典中查找点击的颜色:
Color c = ((Bitmap) pictureBox1.Image).GetPixel(e.X, e.Y)
string StateName = stateDictionary[c];
如果您使用类或结构作为字典中的值,则可以包括大写字母等。
您可以缩放,但必须相应地缩放点击位置;如果不是在 PictureBox 中而是在不可见的颜色代码位图中查找关键颜色,您甚至可以显示地理图像。
总而言之,一个更简单的解决方案 imo.. 你的选择!
一旦你开始工作,你就可以玩拖放了。在这里,您需要在 DragDrop 或 Mouseup 上进行测试,以查看您在哪里放置了标签。
这是一个不错的项目,值得创建一些类来让事情变得更容易和更可扩展..!
对于真正的 Button,您可能会幸运地使用 WPF。