Home > Software design >  How to interact with mouse in Windows Form
How to interact with mouse in Windows Form

Time:07-13

I have a dictionary of buttons and also an null variable button. When you click on an button from the dictionary, we get the values ​​​​that should be sent to an empty variable.

public static Button selectedfigure=null;
public Dictionary<(int x, int y), Button> _Panels = new Dictionary<(int x, int y), Button>();

public void Fillboard()
{
    for (int x = 0; x < 8; x  )
    {
        for (int y = 0; y < 8; y  )
        {
            _Panels[(x, y)] = new Button()
            {
                Height = 64,
                Width = 64,
                Location = new Point(x * 64, y * 64),
                BackColor = CalculateBackColor(x,y),
                BackgroundImage = CalculateBackimage(x,y)               
            };
            Controls.Add(_Panels[(x, y)]);
        }
    }
}

CodePudding user response:

Your question is about how to interact with Mouse events on your "board". The answer is to subscribe to Mouse events like Click for each control you add. Your code is using a normal Button but will be much simpler if you make a custom class that inherits Button or preferably PictureBox and this way each instance keeps track of its own X-Y, color, and image.

Also, instead of using a Dictionary lookup and setting Location properties yourself, you might try an 8x8 TableLayoutPanel for the board, then iterate all its 8 columns and rows with methods that take column and row as arguments.


The mouse events will now be be subscribed to in the addSquare method.

private void addSquare(int column, int row)
{
    var color = ((column   row) % 2) == 0 ? Color.White : Color.Black;
    var square = new Square
    {
        BackColor = color,
        Column = column,
        Row = row,
        Size = new Size(80, 80),
        Margin = new Padding(0),
        Padding = new Padding(10),
        Anchor = (AnchorStyles)0xf,
        SizeMode = PictureBoxSizeMode.StretchImage,
    };
    tableLayoutPanel.Controls.Add(square, column, row);
    // Hook the mouse events here
    square.Click  = onSquareClicked;
    square.MouseHover  = onSquareMouseHover;
}

Before and after iterating the TableLayoutPanel with addSquare

squares


Changing the value of the enum Piece { None, Black, Red } property can choose an image accordingly.

private void initImage(int column, int row)
{
    var square = (Square)tableLayoutPanel.GetControlFromPosition(column, row);
    switch (row)
    {
        case 0:
        case 1:
            square.Piece = Piece.Black;
            break;
        case 6:
        case 7:
            square.Piece = Piece.Red;
            break;
        default:
            square.Piece = Piece.None;
            break;
    }
}

Before and after iterating the TableLayoutPanel with initImage

pieces


Mouse event handlers are simple now:

private void onSquareClicked(object sender, EventArgs e) =>
    MessageBox.Show($"Clicked: {sender}");

private void onSquareMouseHover(object sender, EventArgs e) =>
    _tt.SetToolTip((Control)sender, sender.ToString());

ToolTip _tt = new ToolTip();

mouse events


The Square class is uncomplicated, just a few lines of code.

class Square : PictureBox // Gives more visual control than Button
{
    public int Column { get; internal set; }
    public int Row { get; internal set; }
    Piece _piece = Piece.None;
    public Piece Piece
    {
        get => _piece;
        set
        {
            if(!Equals(_piece, value))
            {
                _piece = value;
                switch (_piece)
                {
                    case Piece.None:
                        Image = null;
                        break;
                    case Piece.Black:
                        Image = Resources.black;
                        break;
                    case Piece.Red:
                        Image = Resources.red;
                        break;
                }
            }
        }
    }
    public override string ToString() =>
        Piece == Piece.None ? 
            $"Empty {BackColor.Name} square [column:{Column} row:{Row}]" :
            $"{Piece} piece [column:{Column} row:{Row}]";
}

Edited (in response to Jeremy's excellent suggestion)

Where and how to call the methods to initialize the board:

public MainForm()
{
    InitializeComponent();
    // Board is a TableLayoutPanel 8 x 8
    tableLayoutPanel.AutoSize = true;
    tableLayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
    // Add squares
    IterateBoard(addSquare);
    // Add pieces
    IterateBoard(initImage);
}

void IterateBoard(Action<int, int> action)
{
    for (int column = 0; column < 8; column  )
    {
        for (int row = 0; row < 8; row  )
        {
            action(column, row);
        }
    }
}

CodePudding user response:

I don't know exactly which is your problem. I think you need know which button is pressed in your matrix.

You can add the controls in the same way but instead the use of _Panels dictionary, you can use Tag property of button to store a Point with the x,y coordinates:

for (int x = 0; x < 8; x  )
{
    for (int y = 0; y < 8; y  )
    {
        var button = new Button
        {
            Height = 64,
            Width = 64,
            Location = new Point(x * 64, y * 64),
            BackColor = CalculateBackColor(x,y),
            BackgroundImage = CalculateBackimage(x,y),                            
            Tag = new Point(x, y)
        };
        button.Click  = OnButtonClick;
        Controls.Add(button);
    }
}

In the click event handler of the button:

private void OnButtonClick(object sender, EventArgs e)
{
    var button = (Button)sender;
    var point = (Point)button.Tag;
    // Here you have x,y coordinates of clicked button
}
  • Related