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.
source to share
You have two options:
-
Use
Button
withRegion
. -
Use
Button
withBackgroundImage
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
.
source to share