Question Not getting mouse click event from a transparent picturebox

mfwoo

Member
Joined
Nov 2, 2020
Messages
7
Programming Experience
10+
I have a picturebox with transparent background (orange rectangle) on top of another picturebox with the keyboard background. How can I get mouseclick event return from the smaller transparent picturebox.
Please help.

1604577383043.png
 
Solution
PointsOnScreen.gif
You could also do it using points. I've created something for you to help you get the locations of the buttons in your picture. Just run the code, and hover with precision to get the values of the x/y positions of each button. Unlike Skydiver's example I used a Dictionary of Tuple Points. These values will have to be hard-coded into the dictionary at runtime. Then you can use the MouseUp event to capture the mouse position from the MouseEventArgs. And while I didn't do it all for you. What would be the fun in that? You need to compare the click event coordinates and see if they are inside the radius of one of your keys. Then you can return the key from the dictionary which is the key you pressed.

Drop this into your partial...
First of all, why are you using transparent picture boxes to do hit testing?
 
First of all, why are you using transparent picture boxes to do hit testing?
The client already provided the design and layout of the keyboard for the touch screen for the self service machine. I was thinking to overlay those individual keys with a transparent pictureboxes or labels and then hook up the mouse click event to get which key that the user touched.

Looking forward forward any other suggestion.
 
Last edited:
Just have list of rectangles and "keys" something like:
C#:
class KeyRect
{
    public string Key { get; set; }
    public Rectangle Rect { get; set; }
}
:
List<KeyRect> _keys = new List<KeyRect>()
    {
        new KeyRect() { "Delete", new Rectangle(150, 5, 40, 20) },
        new KeyRect() { "A", new Rectangle(10, 75, 10, 10) },
        :
    }

Then you when you get a mouse down or click event, you iterate over the list checking to see if the location of the mouse is inside a rectangle. Obviously with your odd shape "Enter" key, you'll need to have two or more rectangles to do the hit testing.
 
PointsOnScreen.gif
You could also do it using points. I've created something for you to help you get the locations of the buttons in your picture. Just run the code, and hover with precision to get the values of the x/y positions of each button. Unlike Skydiver's example I used a Dictionary of Tuple Points. These values will have to be hard-coded into the dictionary at runtime. Then you can use the MouseUp event to capture the mouse position from the MouseEventArgs. And while I didn't do it all for you. What would be the fun in that? You need to compare the click event coordinates and see if they are inside the radius of one of your keys. Then you can return the key from the dictionary which is the key you pressed.

Drop this into your partial forms class :
C#:
        public Dictionary<string, Tuple<Point, Point>> Key_Positions = new Dictionary<string, Tuple<Point, Point>>();
Put this in your form shown event :
FormShown:
        private void Form1_Shown(object sender, EventArgs e)
        {
            // These : new Point(50, 30), cover from the left of the form to left side of number 1 (50). Top of the form to top of the number 1 is (30).
            // These : new Point(120, 80), cover from the left of the form to right side of number 1 (120). Top of the form to bottom of the number 1 is (80).
            Key_Positions.Add("1", Tuple.Create(new Point(50, 30), new Point(120, 80)));
            /* Add your custom MouseMove and MouseUpEvents */
            pictureBox1.MouseMove += PictureBox1_MouseMove;
            pictureBox1.MouseUp += PictureBox1_MouseUp;
        }
Your mouse move event will look like this :
MouseMove Event:
        private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            label1.Location = e.Location;
            label1.Text = e.Location.ToString();
            /* This will move the label away from the actual position so not to prvent clicking the picture box. Otherwise the label will block your click. */
            label1.Location = new Point(e.Location.X + 20, e.Location.Y + 10);
        }
Take note of the last line in the above code. It's important you leave that there when you want to click numbers. Otherwise the label will be placed in front of your cursor and your click events will be registered on your label rather than your picturebox. Leaving that line of code at the end non-commented does not effect the location printed to the labels Text property. Next you will want your MouseDown event for your picturebox :
Code:
        private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            foreach (var kp in from KeyValuePair<string, Tuple<Point, Point>> kp in Key_Positions
                               let X_Pos1 = e.Location.X >= kp.Value.Item1.X/* is Greater than 50 */
                               let X_Pos2 = e.Location.X <= kp.Value.Item2.X/* is Less than 30 */
                               let x_Pos3 = e.Location.Y >= kp.Value.Item1.Y/* is Gtreater than 30 */
                               let x_Pos4 = e.Location.Y <= kp.Value.Item2.Y/* is Less than 80 */
                               select kp)
            {
                if (e.Location.X >= kp.Value.Item1.X && e.Location.X <= kp.Value.Item2.X &&
                    e.Location.Y >= kp.Value.Item1.Y && e.Location.Y <= kp.Value.Item2.Y)
                {
                    Debug.WriteLine("You clicked 1");
                }
                else
                {
                    Debug.WriteLine("1 was not clicked");
                }
            }
        }
As I said; I didn't do everything for you. What you need to do next is narrow down using a Where() clause in the linq expression where the selected values correlate to not greater than and not less than that of the points of each key. Similarly to how I wrote the logic for the if statement on line 10 to 18 using e.Location of the x/y coordinates for where the number 1 key was clicked and so on for each and every other key on your image. While I understand you haven't a choice in this design, I would just like to point out that this is a horrible project and even worse, is that your client wants it done in Winforms, when they should be requesting it be done in WPF so you can obtain the benefits of speed and performance offered up by using WPF. And at a second look at @Skydiver's post above, if you prefer the way he is recommending, it would take little effort to edit this code to suit your needs. Hope this quick post helps you out. By the time you are finished, you should have :
Full Example:
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public Dictionary<string, Tuple<Point, Point>> Key_Positions = new Dictionary<string, Tuple<Point, Point>>();       
        private void Form1_Shown(object sender, EventArgs e)
        {
            // These : new Point(50, 30), cover from the left of the form to left side of number 1 (50). Top of the form to top of the number 1 is (30).
            // These : new Point(120, 80), cover from the left of the form to right side of number 1 (120). Top of the form to bottom of the number 1 is (80).
            Key_Positions.Add("1", Tuple.Create(new Point(50, 30), new Point(120, 80)));
            /* Add your custom MouseMove and MouseUpEvents */
            pictureBox1.MouseMove += PictureBox1_MouseMove;
            pictureBox1.MouseUp += PictureBox1_MouseUp;
        }
        private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            label1.Location = e.Location;
            label1.Text = e.Location.ToString();
            /* This will move the label away from the actual position so not to prvent clicking the picture box. Otherwise the label will block your click. */
            label1.Location = new Point(e.Location.X + 20, e.Location.Y + 10);
        }


        private void PictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            foreach (var kp in from KeyValuePair<string, Tuple<Point, Point>> kp in Key_Positions
                               let X_Pos1 = e.Location.X >= kp.Value.Item1.X/* is Greater than 50 */
                               let X_Pos2 = e.Location.X <= kp.Value.Item2.X/* is Less than 30 */
                               let x_Pos3 = e.Location.Y >= kp.Value.Item1.Y/* is Gtreater than 30 */
                               let x_Pos4 = e.Location.Y <= kp.Value.Item2.Y/* is Less than 80 */
                               select kp)
            {
                if (e.Location.X >= kp.Value.Item1.X && e.Location.X <= kp.Value.Item2.X &&
                    e.Location.Y >= kp.Value.Item1.Y && e.Location.Y <= kp.Value.Item2.Y)
                {
                    Debug.WriteLine("You clicked 1");
                }
                else
                {
                    Debug.WriteLine("1 was not clicked");
                }
            }
        }
    }
 
Solution
Using rectangles would be better all round. I just wanted to propose a different take using specific points as coordinates for each button on the image. But for that enter button, you might be better using points rather than rectangles.
 
Back
Top Bottom