【问题标题】:PictureBox - Handle Click Event on Non-Transparent Area of ImagePictureBox - 处理图像非透明区域的点击事件
【发布时间】:2016-12-22 06:47:54
【问题描述】:

我必须在 C# 中创建一个窗口窗体,其中两个 PictureBox 重叠。 TopPictureBox 包含一个透明的 png 图片。默认情况下,可以通过单击 TopPictureBox 中图像的任何可见或透明区域来单击 TopPictureBox。但我想让 TopPictureBox 只能通过单击图像的可见区域而不是透明区域来单击。另外我想让光标只在图像的可见区域发生变化,而不是在透明区域。

有没有办法做到这些?

我正在使用此代码使 TopPictureBox 透明。

TopPictureBox.BackColor = Color.Transparent;

感谢您的帮助。

【问题讨论】:

    标签: c# .net winforms transparency picturebox


    【解决方案1】:

    一种方法是检查用户单击的像素的颜色是否与表单的背景颜色相同。如果是,那么用户点击了一个透明区域。

    (注意:正如 Reza 所说,此代码只能在没有重叠的 PictureBoxes 时使用,即仅当图像的透明区域与 Form 的背景颜色相同时)

    Color pixelColour;
    
    private void myPicturebox_MouseClick(object sender, MouseEventArgs e)
    {
       if (e.Button == MouseButtons.Left) 
       {
         pixelColour = ((Bitmap)myPicturebox.Image).GetPixel(point.X, point.Y);
         if (this.BackColor == pixelColour)
         {
            // User clicked on transparent area
         }
         else
         {
            // User clicked on image
         }
       }
    }
    

    【讨论】:

    • 谢谢你,很抱歉问这个问题有什么办法可以用光标来做吗?
    • @Suprovo 你的意思是当光标在表单上移动时,而不是点击?
    • 1. 如果基于SizeModePictureBox 图像位于PictureBox 的中心怎么办? 2.this.BackColor 相比,在 PictureBox 下的图像的深蓝色部分似乎是错误的。
    • @Aniruddha Varma 是的,光标仅在进入可见图像区域时更改,或在退出可见图像区域时返回默认值,而不是在透明区域中。 PictureBox_MouseEnte‌​r 方法更改透明区域上的光标,因为它与 PictureBox 一起使用。我的意思是。我只想将可见的图像区域作为带有光标更改的按钮。
    • @RezaAghaei 你说得对,谢谢 - 我会更新答案,提到它在这些情况下不起作用。如果你知道怎么做,请编辑!
    【解决方案2】:

    检查PictureBox 中的位置是否为Transparent 取决于PictureBoxImageSizeMode 属性。

    您不能简单地使用BitmapGetPixel,因为图像位置和大小根据SizeMode 不同。你应该先根据SizeMode检测Image的大小和位置:

    public bool HitTest(PictureBox control, int x, int y)
    {
        var result = false;
        if (control.Image == null)
            return result;
        var method = typeof(PictureBox).GetMethod("ImageRectangleFromSizeMode",
          System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        var r = (Rectangle)method.Invoke(control, new object[] { control.SizeMode });
        using (var bm = new Bitmap(r.Width, r.Height))
        {
            using (var g = Graphics.FromImage(bm))
                g.DrawImage(control.Image, 0, 0, r.Width, r.Height);
            if (r.Contains(x, y) && bm.GetPixel(x - r.X, y - r.Y).A != 0)
                result = true;
        }
        return result;
    }
    

    然后你可以简单地使用HitTest方法来检查鼠标是否在PictureBox的不透明区域上:

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (HitTest(pictureBox1,e.X, e.Y))
            pictureBox1.Cursor = Cursors.Hand;
        else
            pictureBox1.Cursor = Cursors.Default;
    }
    
    private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
    {
        if (HitTest(pictureBox1, e.X, e.Y))
            MessageBox.Show("Clicked on Image");
    }
    

    还将BackColor 设置为Color.Transparent 只会使PictureBox 相对于其父级透明。例如,如果您在 Form 中有 2 个 PictureBox 设置透明背景色,只是因为您看到了表单的背景。要制作支持透明背景的PictureBox,您应该自己绘制控件后面的内容。你可以在这篇文章中找到TransparentPictureBoxHow to make two transparent layer with c#?

    【讨论】:

    • 哦,这就是评论中SizeMode 引用的意思。感谢您的代码!
    • @AniruddhaVarma 是的。使用上面的代码,您可以检查一个点是否透明。它可以使用不同的SizeMode 值(如StretchImageZoomCenterImageNormal)正常工作。
    • 还将BackColor 设置为Color.Transparent 只会使PictureBox 相对于其父级透明。例如,如果您在 Form 中有 2 个 PictureBox 设置透明背景色,只是因为您看到了表单的背景。要制作支持透明背景的PictureBox,您应该自己绘制控件后面的内容。你可以在这篇文章中找到TransparentPictureBoxHow to make two transparent layer with c#?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 2015-05-19
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    相关资源
    最近更新 更多