2015-05-08 63 views
6

我有一个不规则形状的图像,像一颗心或任何随机形状。 我可以在视觉上使它透明,但我只需要在形状区域上使它可以点击。我听说我应该使用“地区”这一点,但我不知道如何。如何在c中创建一个可点击的不规则形状的区域#

我试图寻找那些不为空,透明的,或空的所有像素,并创建一个点阵列与他们,但我不能创建/重塑电流控制区域。我试图制作一个自定义控件,您可以选择一个按钮或图片,并且它们是不规则形状的并且彼此接近。

以下是我处理: enter image description here

正如你可以在图片中看到,有8个不同的部分(假设左右两侧相结合)。正如你所看到的,它们彼此接近,其中一些甚至适合其他空间之间的空间。

我的目标是,举例来说,如果我点击胸肌(图中红色区域),它会改变它的颜色版本,和一堆其他的代码运行。

问题是,默认情况下,当我们添加任何带有PictureBox的图片时,它会围绕该图片的边界创建一个围绕该图片的Rectangle。因此,如果我将两张图片(如图中所示)靠近在一起,则一个空白区域会阻止我点击另一张图片。

此外,它提出了一个错误的对象,因为这个问题的ClickEvent

我正在尝试设置“引发事件区域”,我认为只是其中的图片存在,我们把它称为Graphic Region。我可以通过一个循环来确定像素的位置,该循环确定该图像的哪个坐标具有“颜色”(表示它是图片的一部分,我想要点击的区域),但我无法用该数据限制该区域。

的我想要实现的一个例子:https://www.youtube.com/watch?v=K_JzL4kzCoE

什么是做到这一点的最好方法是什么?

+0

Webforms,Windows Forms,WPF,GTK ...? – jdphenix

+0

WinForms,对不起。 –

+1

不用担心。它只会帮助你得到答案。 – jdphenix

回答

4

这两种方法解决这个问题:

Regions
  • 工作。

  • 使用透明Images

第一种方法涉及创建控件,e.g PictureBoxes​​或,其具有的图像的形状仅该形状内部点击。

这很不错,只要你有权访问构成形状的矢量轮廓

这里是制约一个Panel可见&点击Region从跟踪点列表创建了一个形状不规则的斑点一个例子:不幸的是使从一个Region

enter image description here

List<Point> points = new List<Point>(); 
points.Add(new Point(50,50));points.Add(new Point(60,65));points.Add(new Point(40,70)); 
points.Add(new Point(50,90));points.Add(new Point(30,95));points.Add(new Point(20,60)); 
points.Add(new Point(40,55)); 

using (GraphicsPath gp = new GraphicsPath()) 
{ 
    gp.AddClosedCurve(points.ToArray()); 
    panel1.Region = new Region(gp); 
} 

包含在其中的要点将不起作用;想象一个Region作为矢量形状的列表,这些由点组成,但仅用于创建包含矢量,而不是像素。

您可以跟踪形状,但这是很多工作,而且imo不值得它。

所以,如果你不具备矢量形状:去的第二种方法:

这会假设你有图片(可能png格式),这是在没有点击应该接受所有的斑点透明。

最简单和最有效的方法是将它们与它们应该位于的点一起放入一个列表中;然后,每当它们发生变化时,将它们全部绘制成一张图像,您可以将其分配给一个PictureBox.Image

这是一个Mouseclick事件,它将搜索图像列表中最顶端的Image以查找被点击的图像。与他们的位置将它们组合起来我用一个元组列表:

List<Tuple<Image, Point>> imgList = new List<Tuple<Image, Point>>(); 

我们通过这个列表中搜索每个MouseClick

private void pictureBox1_MouseClick(object sender, MouseEventArgs e) 
{ 
    int found = -1; 
    // I search backward because I drew forward: 
    for (int i = imageList1.Images.Count - 1; i >= 0; i--) 
    { 
     Bitmap bmp = (Bitmap) imgList[i].Item1; 
     Point pt = (Point) imgList[i].Item2; 
     Point pc = new Point(e.X - pt.X, e.Y - pt.Y); 
     Rectangle bmpRect = new Rectangle(pt.X, pt.Y, bmp.Width, bmp.Height); 
     // I give a little slack (11) but you could also check for > 0! 
     if (bmpRect.Contains(e.Location) && bmp.GetPixel(pc.X, pc.Y).A > 11) 
      { found = i; break; } 
    } 

    // do what you want with the found image.. 
    // I show the image in a 2nd picBox and its name in the form text: 
    if (found >= 0) { 
     pictureBox2.Image = imageList1.Images[found]; 
     Text = imageList1.Images.Keys[found]; 
    } 

} 

这里是我组合的图像为一体。请注意,对于测试,我已将它们添加到ImageList对象。这具有严重的缺点,因为所有图像都被缩放到一个普通尺寸。你可能会想创建一个你自己的正确列表!

Bitmap patchImages() 
{ 
    Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height); 
    imgList.Clear(); 
    Random R = new Random(1); 

    using (Graphics G = Graphics.FromImage(bmp)) 
    { 
     foreach (Image img in imageList1.Images) 
     { 
      // for testing: put each at a random spot 
      Point pt = new Point(R.Next(333), R.Next(222)); 
      G.DrawImage(img, pt); 
      // also add to the searchable list: 
      imgList.Add(new Tuple<Image, Point>(img, pt)); 
     } 
    } 
    return bmp; 
} 

我把它叫做启动:

private void Form1_Load(object sender, EventArgs e) 
{ 
    pictureBox1.Image = patchImages(); 
} 

旁白:所有的图像绘制成一个通过这种方式,也是唯一一个可以让你自由的重叠图像。 Winforms不支持与重叠控件的真实透明度。并且为每个形状测试一个Pixel(最多)也是非常快的。

+0

2.如果我需要将图像部分改为正确的话,我应该重新打印一遍图像。 –

+0

没错。这是一个快速操作,所以不用担心!您需要维护搜索列表,并注意保留每张图片的一个副本。 – TaW

+0

列表>图片>将比ImageList存储图片的好选择吗? –

0

您是否试过图像映射?

http://www.w3schools.com/TAGS/tag_map.asp

这应该给你你需要什么就可以开始制作地图叠加在图像上。

+0

我正在处理WinForms –

+0

啊,我的错误。这里是一个图像地图项目的胜利形式:http://www.codeproject.com/Articles/2820/C-Windows-Forms-ImageMap-Control – mjw

+0

假设我有一个自定义图像,并假设它是天使的翅膀,可以当我点击翅膀内的空白区域时,这可以防止引发点击事件? 或者让我说里面有一个圆圈和另一个圆圈,内圈不会阻止它的空白区域点击外圈。 这是我的问题 –

1

这是一个处理图像掩码的Winforms示例。当用户点击蒙版图像时,弹出一个消息框。这种基本技术显然可以修改以适应。

public partial class Form1 : Form { 
    readonly Color mask = Color.Black; 
    public Form1() { 
     InitializeComponent(); 
    } 

    private void pictureBox1_Click(object sender, EventArgs e) { 
     var me = e as MouseEventArgs; 
     using (var bmp = new Bitmap(pictureBox1.Image)) { 
      if (me.X < pictureBox1.Image.Width && me.Y < pictureBox1.Image.Height) { 
       var colorAtMouse = bmp.GetPixel(me.X, me.Y); 
       if (colorAtMouse.ToArgb() == mask.ToArgb()) { 
        MessageBox.Show("Mask clicked!"); 
       } 
      } 
     } 
    } 
} 

pictureBox1具有从心脏形状的资源加载的Image我优渥。

+0

这看起来像只能处理与掩码颜色匹配的pictureBox内的像素。即使他只使用纯色图像,也不允许在帧中的任何其他遮罩颜色对象。 – mjw

+0

在这种情况下,我们假设,图像被涂成黑色的权利?顺便谢谢你的回答,我会改进我的问题,这是迄今为止最好的答案,但不是我的意思。 –

+0

我能想到的一种可能性是将'PictureBox'子类化并修改消息处理程序以允许点击,然后使用子类显示“真实”图像。只需一分钟(或两个) – jdphenix

相关问题