Use an image button with a transparent color area

I have a PNG image with transparent and normal color.

I use this for one button:

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;

      

And when I click on the transparent area, it still counts as a button click.

How can I make this button only clickable when I click on the colored area?

And when I click on the transparent area, I want it to be considered a click on the object behind that button.

+3


source to share


1 answer


You have two options:

  • Use Button

    with Region

    .

  • Use Button

    with BackgroundImage

    and check what user clicks with eachClick

Option 1 is only possible if you can create Region

one that accepts GraphicsPath

, which means you need to create the shape that you need to Graphics

prime lines and curves, etc.

If you only Bitmap

have transparency, you better not use Button

with Region

.

Instead, you can use Button1

and each click you check the transparency of the clicked pixel.

If it's transparent, you fire the click event of the control below it.

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
    }
}

      

Note that the validation assumes you have a normal layout, with the button image in the upper left corner and no scaling. If you need to scale the image, you must save the scaled bitmap for validation. But if you can use an unscaled image, you should do so as it will look better.

Notice how I am creating the correct parameter MouseEventArgs

for the control below, so that you can also access the button or mouse location.

Also note that it is easier to use an event MouseClick

instead of an event Click

because it already has the mouse location.

If you need / need to use an event Click

, you can skip creation EventArgs

as it has no meaningful data; just release e

from the click ..



This is how the event could have started 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..

      

If you want to check for all mouse click events and pass each one to the parent, you have to code them all.

Let's first look at the order of events on MSDN

  • MouseDown event.
  • Click an event.
  • MouseClick
  • MouseUp event.

So, we need to start with MouseDown

. We can execute the test in a helper function hitTest

, so we can reuse it .:

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;
}

      

We now code all four events. We hitTest

only need to call it once, and we pass a simple, unmodified parameter e

in the event Click

:

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
}

      

Of course, you also need to encode all four events for yourParent

.

+2


source







All Articles