【问题标题】:Use image Button with transparent color area使用带有透明颜色区域的图像按钮
【发布时间】:2015-05-31 14:28:04
【问题描述】:

我有一张透明且颜色正常的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;

当我点击透明区域时,它仍然算作点击按钮。

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

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

【问题讨论】:

  • 如果您可以访问排除透明区域的 GraphicsPath,您可以限制按钮的区域。不幸的是,您无法将位图转换为路径..
  • 是的,我搜索了几天,但我没有看到任何解决方案。我真的很想在winform中创建一个自定义按钮,但我所要做的就是让那个自定义按钮变成矩形......
  • 那么,您的图像是什么样的?可以完成简单的形状,但复杂的图像不能精确地工作。请参阅this post 的开头(仅)以了解将控件的 reion 限制为形状的示例。
  • 它看起来像一片叶子。
  • 查看我更新的简单答案!

标签: c# button png


【解决方案1】:

你有两个选择:

  • 使用ButtonRegion

  • 使用ButtonBackgroundImage 并检查用户使用每个Click 击中的内容

只有选项一才可行如果你可以创建一个Region,它需要一个GraphicsPath,这意味着你需要创建你需要的形状 Graphics 原语,如线条和曲线等。

如果您只有具有透明度的Bitmap,最好不要将ButtonRegion 一起使用。

相反,您可以使用 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 事件更容易,因为它已经有了鼠标位置..

如果您需要/想要改用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 事件。
  2. 点击事件。
  3. 鼠标点击
  4. MouseUp 事件。

所以我们需要从MouseDown 开始。我们可以在辅助函数hitTest 中进行测试,所以我们可以重复使用它..:

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 编写所有四个事件..

【讨论】:

  • 非常感谢!它可以工作,我使用事件鼠标向下鼠标而不是单击..
  • 但是无论如何调用按钮的父鼠标单击/鼠标向上/鼠标向下(所有鼠标事件)?我希望所有鼠标事件都转到父级而不是仅单击鼠标。
  • 不,我不是那个意思,我已经做了,我的意思是即使它父母没有这些鼠标事件句柄,我怎样才能让它在透明区域仍然接收鼠标动作?
  • 我不明白。什么是父母?您只能调用代码中存在的事件..
  • 我不是要调用一个事件。我的意思是我们可以在某个位置调用点击“动作”,控件将检查该位置是否有点击事件。
猜你喜欢
  • 2016-03-29
  • 1970-01-01
  • 2021-09-18
  • 2019-12-13
  • 2015-11-06
  • 2015-02-05
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
相关资源
最近更新 更多