使用带有透明颜色区域的图像按钮

Use image Button with transparent color area

我有一张 PNG 格式的图片,透明且颜色正常。

我将这个用于一个按钮:

this.Button1.BackColor = System.Drawing.Color.Transparent;
this.Button1.BackgroundImage = Image;
this.Button1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.Button1.FlatAppearance.BorderSize = 0;
this.Button1.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Transparent;
this.Button1.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent;
this.Button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.Button1.Location = new System.Drawing.Point(0, 0);
this.Button1.Margin = new System.Windows.Forms.Padding(0);
this.Button1.Name = "Skin";
this.Button1.Size = new System.Drawing.Size(294, 194);
this.Button1.TabIndex = 7;
this.Button1.UseVisualStyleBackColor = false;

而我在点击透明区域时,仍然算作点击Button。

如何让这个按钮只在点击彩色区域时调用点击事件?

当我点击透明区域时,我希望它算作点击这个按钮后面的对象。

您有两个选择:

  • 使用 ButtonRegion

  • 使用 ButtonBackgroundImage 并检查用户点击的每个 Click

选项一仅可行如果你可以创建一个Region,它需要一个GraphicsPath,这意味着你需要创建shape 你需要来自 Graphics primitves 像直线和曲线等..

如果您只有 Bitmap 和透明度,最好不要使用带有 RegionButton

相反,您可以使用 Button1 并在每次点击时检查所点击像素的透明度。

如果它是透明的你调用它下面的控件的点击事件..

private void Button1_MouseClick(object sender, MouseEventArgs e)
{
    Size r = Button1.BackgroundImage.Size;
    // check that we have hit the image and hit a non-transparent pixel
    if ((e.X < r.Width && e.Y < r.Height) &&
            ((Bitmap)Button1.BackgroundImage).GetPixel(e.X, e.Y).A != 0)
    {
        Console.WriteLine("BUTTON clicked");  // test
        // do or call your click actions here!
    }
    // else pass the click on..
    else
    {
        // create a valid MouseEventArgs
        MouseEventArgs ee = new MouseEventArgs(e.Button, e.Clicks, 
                                e.X + Button1.Left, e.Y + Button1.Top, e.Delta);
        // pass it on to the stuff below us
        pictureBox1_MouseClick(pictureBox1, ee);

        Console.WriteLine("BUTTON NOT clicked");  // test
    }
}

请注意,检查假设您有一个正常的布局,按钮图像位于左上角并且没有缩放。如果您需要缩放图像,您应该保留一个缩放位图来进行检查。但是如果您可以使用未缩放的图像,您应该这样做,因为这样看起来会更好。

请注意我是如何为下面的控件创建正确的 MouseEventArgs 参数的,这样您也可以在那里访问按钮或鼠标的位置..

另请注意,使用 MouseClick 事件比 Click 事件更容易,因为它已经有了鼠标位置..

如果您 need/want 改用 Click 事件,您可以跳过创建 EventArgs,因为它没有有意义的数据;只需通过点击传递 e..

Click 活动可以这样开始:

private void Button1_Click(object sender, EventArgs e)
{
    // we need the location of the clicked pixel:
    Point clickLocation = Button1.PointToClient(Control.MousePosition);
    // the rest can proceed as above, just with simple EventArgs..

如果您想检查所有鼠标单击事件并将它们中的每一个传递给父级,您将必须对它们全部进行编码。

先来看看order of events on MSDN

  1. MouseDown event.
  2. Click event.
  3. MouseClick
  4. MouseUp event.

所以我们需要从 MouseDown 开始。我们可以在辅助函数 hitTest 中进行测试,因此我们可以重新使用它..:[=​​41=]

Button clickedButton = null;
MouseEventArgs ee = null;

void hitTest(Button btn, MouseEventArgs e)
{
    Size r = btn.BackgroundImage.Size;
    // check that we have hit the image and hit a non-transparent pixel
    if ((e.X < r.Width && e.Y < r.Height) &&
            ((Bitmap)btn.BackgroundImage).GetPixel(e.X, e.Y).A != 0)
    {
        clickedButton = btn;
        ee = new MouseEventArgs(e.Button, e.Clicks, e.X + btn.Left, e.Y + btn.Top, e.Delta);
    }
    else clickedButton = null;
}

现在我们对所有四个事件进行编码。我们只需要调用 hitTest 一次,然后在 Click 事件中传递简单、未修改的 e 参数:

private void Button1_MouseDown(object sender, MouseEventArgs e)
{
    hitTest(sender as Button, e);
    if (sender != clickedButton)
        yourParent_MouseDown((sender as Button).Parent, ee);
    else // do your stuff
}

private void Button1_Click(object sender, EventArgs e)
{
    if (sender != clickedButton)
        yourParent_Click((sender as Button).Parent, e);
    else // do your stuff
}

private void Button1_MouseClick(object sender, MouseEventArgs e)
{
    if (sender != clickedButton)
        yourParent_MouseClick((sender as Button).Parent, ee);
    else // do your stuff
}

private void Button1_MouseUp(object sender, MouseEventArgs e)
{
    if (sender != clickedButton)
        yourParent_MouseUp((sender as Button).Parent, ee);
    else // do your stuff
}

当然,您还需要为 yourParent 编写所有四个事件的代码..