How to change focus on buttons up, down, left and right relative to the button that is selected?

后端 未结 2 1398
萌比男神i
萌比男神i 2020-12-12 02:09

I\'m new in programming.

I don\'t know how to explain well!!.

How can i make my WinForms application understand the button location, for example imagine a nu

2条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-12 02:44

    You can add your Buttons to a TableLayoutPanel, so each Button's position is determined by the TableLayoutPanel's (Column:Row) coordinates.

    • Create a TableLayoutPanel (in the below, named tlpButtons) with enough Rows and Columns to contain your Buttons. You can add/remove Rows and Column at run-time, if needed.
    • Select all your Buttons and subscribe to the PreviewKeyDown, using the PropertyGrid in the Form Designer, so that you have just one event handler for all your Buttons (in this code, the event handler is named buttons_PreviewKeyDown).
    • When the Key.Up or Keys.Down are pressed, the PreviewKeyDown handler of the Buttons is invoked. The sender argument references the control that triggered the event, so we cast sender to Control (since only a Control type reference is needed, we don't use any property specific to a derived type, like Button)
    • If we handle the Key pressed, we have to set IsInputKey, otherwise the event is passed on to the control and processed (causing the normal selection to trigger)
    • The TableLayoutPanel's GetPositionFromControl() returns the Row/Column position of this Control.
    • We just set the Row value ± 1, depending on what cursor Key has been pressed (while checking whether the new value is in the [0 : RowsCount] range).
      The GetControlFromPosition() method returns the reference of the control in the new position: we use this reference to set the current ActiveControl.

    This is the result:


    Note:
    the buttons_PreviewKeyDown event handler is the same for all Buttons/Controls.
    tlpButtons is the name of the TableLayoutControl used as container for the Buttons/Controls

    Updated to also work with a Numeric Pad when either active or inactive.

    private void buttons_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        var btn = sender as Control;
        var pos = tlpButtons.GetPositionFromControl(btn);
        bool moveFocus = false;
    
        switch (e.KeyCode) {
            case Keys.NumPad8:
            case Keys.Up:
                pos.Row = (pos.Row > 0) ? pos.Row - 1 : tlpButtons.RowCount - 1;
                moveFocus = true;
                break;
            case Keys.NumPad2:
            case Keys.Down:
                pos.Row = (pos.Row < (tlpButtons.RowCount - 1)) ? pos.Row + 1 : 0;
                moveFocus = true;
                break;
            case Keys.NumPad4:
                if (pos.Column > 0) {
                    pos.Column -= 1;
                }
                else {
                    pos.Column = tlpButtons.ColumnCount - 1;
                    pos.Row = pos.Row > 0 ? pos.Row - 1 : tlpButtons.RowCount - 1;
                }
                moveFocus = true;
                break;
            case Keys.NumPad6:
                if (pos.Column < (tlpButtons.ColumnCount - 1)) {
                    pos.Column += 1;
                }
                else {
                    pos.Column = 0;
                    pos.Row = (pos.Row < tlpButtons.RowCount - 1) ? pos.Row + 1 : 0;
                }
                moveFocus = true;
                break;
        }
        if (moveFocus) {
            e.IsInputKey = true;
            var ctrl = tlpButtons.GetControlFromPosition(pos.Column, pos.Row);
            if (ctrl != null) this.ActiveControl = ctrl;
        }
    }
    

提交回复
热议问题