问题
I have several textboxes
, i want the cursor to move from one textbox
to another using arrow keys.
how can i do that?
it looks like this, also the tap moves vertically which is weird.
Thanks.
回答1:
You can override the form's ProcessCmdKey function, and handle the key press and focusing on text boxes in it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TextBoxes
{
public partial class Form1 : Form
{
List<TextBox[]> _textBoxes;
public Form1()
{
InitializeComponent();
//Getting a 2 dimentional structure to hold textboxes
this._textBoxes= new List<TextBox[]>();
TextBox[] row1 = new TextBox[4];
row1[0] = textBox1;
row1[1] = textBox2;
row1[2] = textBox3;
row1[3] = textBox4;
TextBox[] row2 = new TextBox[4];
row2[0] = textBox5;
row2[1] = textBox6;
row2[2] = textBox7;
row2[3] = textBox8;
TextBox[] row3 = new TextBox[4];
row3[0] = textBox9;
row3[1] = textBox10;
row3[2] = textBox11;
row3[3] = textBox12;
TextBox[] row4 = new TextBox[4];
row4[0] = textBox13;
row4[1] = textBox14;
row4[2] = textBox15;
row4[3] = textBox16;
this._textBoxes.Add(row1);
this._textBoxes.Add(row2);
this._textBoxes.Add(row3);
this._textBoxes.Add(row4);
}
/// <summary>
/// Processes a command key.
/// </summary>
/// <param name="msg">A <see cref="T:System.Windows.Forms.Message"/>, passed by reference, that represents the Win32 message to process.</param>
/// <param name="keyData">One of the <see cref="T:System.Windows.Forms.Keys"/> values that represents the key to process.</param>
/// <returns>
/// true if the keystroke was processed and consumed by the control; otherwise, false to allow further processing.
/// </returns>
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
//A key was pressed!
Control activeCtrl = this.ActiveControl;
TextBox txb = activeCtrl as TextBox;
//Handle it only if it was sent when a textbox was focused
if (txb != null)
{
int row;
int column;
//find out which text box is currently active
this.GetTextBoxIndexes(txb, out row, out column);
//change indexes according to key stroke
if (keyData == Keys.Up)
{
row--;
}
else if (keyData == Keys.Down)
{
row++;
}
else if (keyData == Keys.Left)
{
column--;
}
else if (keyData == Keys.Right)
{
column++;
}
//Make sure we are not in negative / out of ranfe index
row = Math.Abs(row + 4) % 4;
column = Math.Abs(column + 4) % 4;
//focus requested text box
TextBox slected = this._textBoxes[row][column];
slected.Focus();
}
//don't forget not to break the chain...
return base.ProcessCmdKey(ref msg, keyData);
}
/// <summary>
/// Gets the text box indexes.
/// </summary>
/// <param name="txb">The texbox.</param>
/// <param name="row">The out row index.</param>
/// <param name="column">The out column index.</param>
private void GetTextBoxIndexes(TextBox txb, out int row, out int column)
{
row = -1;
column = -1;
for (int rowIdx = 0; rowIdx < this._textBoxes.Count; rowIdx++)
{
TextBox[] currRow = this._textBoxes[rowIdx];
for (int colIdx = 0; colIdx < currRow.Length; colIdx++)
{
TextBox currTextBox = this._textBoxes[rowIdx][colIdx];
if (currTextBox.Equals(txb))
{
row = rowIdx;
column = colIdx;
return;
}
}
}
}
}
}
回答2:
The following solution works if there is some text in the text boxes.
First create a KeyDown event handler:
private void textBoxLeft_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.Right))
{
e.Handled = true;
//SendKeys.Send("{TAB}");
textBoxRight.Focus();
}
}
private void textBoxRight_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.Equals(Keys.Left))
{
e.Handled = true;
//SendKeys.Send("+{TAB}");
textBoxLeft.Focus();
}
}
回答3:
Just made this off the top of my head creatively. This will give you exactly what you want.
Step 1 create a TableLayoutPanel and make the columns 4 and the rows 5. Delete all your original text boxes and Step 2 add this to your code.
TextBox[] text = new TextBox[20]; //these are your new textboxes
private void Form1_Load(object sender, EventArgs e)
{
for(int i=0; i<text.Length;i++) text[i] = new TextBox() {Text="0"}; //initialize each textbox
tableLayoutPanel1.Controls.AddRange(text); //add textboxes to the tablelayoutpanel
for(int i = 0; i<tableLayoutPanel1.Controls.Count;i++) //add everything in the tablelayoutpanel to the same keydown event
tableLayoutPanel1.Controls[i].KeyDown+=new KeyEventHandler(tableLayoutPanel1_KeyDown);
}
void tableLayoutPanel1_KeyDown(object sender, KeyEventArgs e)
{ // this moves the box focus up down left or right
if (e.KeyData == Keys.Left)
for (int i = 0; i < text.Length; i++)
{
if (sender.Equals(text[i]))
{ text[i - 1 < 0 ? text.Length - 1 : i - 1].Focus(); break; }
}
else if (e.KeyData == Keys.Right)
for (int i = 0; i < text.Length; i++)
{
if (sender.Equals(text[i]))
{ text[i + 1 > text.Length - 1 ? 0 : i + 1].Focus(); break; }
}
else if (e.KeyData == Keys.Up)
for (int i = 0; i < text.Length; i++)
{
if (sender.Equals(text[i]))
{ text[i - 4 < 0 ? i - 4 + text.Length : i - 4].Focus(); break; }
}
else if (e.KeyData == Keys.Down)
for (int i = 0; i < text.Length; i++)
{
if (sender.Equals(text[i]))
{ text[i + 4 > text.Length - 1 ? i + 4 - text.Length : i + 4].Focus(); break; }
}
}
This will allow you to navigate up down left right with the arrow keys and it will fix your issue with the tab so tab will now go right and shift+tab will go back. Additionally this solution is nice because if you go up or down it will cycle back around as you would intuitively expect. Also if you are feeling zesty you can move diagonally now.
回答4:
Try handling the keypress event
→,← can force tab,shift+tab key press respectively.
Just a rough idea, as I have never tried this.
来源:https://stackoverflow.com/questions/16909291/how-to-move-the-cursor-between-textboxes-using-arrows