The following code, without an OnKeyUp handler, does what you seem to want
type
TMyDBGrid = class(TDBGrid);
procedure TForm1.DBGrid1KeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
begin
if Key = VK_Tab then begin
Key := 0;
if ssShift in Shift then
DBGrid1.SelectedIndex := DBGrid1.SelectedIndex + 1
else begin
if TMyDBGrid(DBGrid1).Col = 1 then begin
// The following goes to the rightmost cell in the next row
// if the focus is already on the leftmost column, as specified
// in the original version of the q
DBGrid1.DataSource.DataSet.Next;
TMyDbGrid(DBGrid1).Col := DBGrid1.Columns.Count;
end
else
DBGrid1.SelectedIndex := DBGrid1.SelectedIndex - 1;
end;
end;
end;
Update In a comment to this, you asked for a fuller implementation. Here it is:
procedure TForm1.DBGrid1KeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
procedure TabForwards;
begin
if TMyDBGrid(DBGrid1).Col = DBGrid1.Columns.Count then begin
DBGrid1.DataSource.DataSet.Next;
if DBGrid1.DataSource.DataSet.Eof then
DBGrid1.DataSource.DataSet.Append;
TMyDbGrid(DBGrid1).Col := 1;
end
else
DBGrid1.SelectedIndex := DBGrid1.SelectedIndex + 1;
end;
procedure TabBackwards;
begin
if DBGrid1.DataSource.DataSet.State = dsInsert then begin
DBGrid1.DataSource.DataSet.Cancel;
Exit;
end;
if TMyDBGrid(DBGrid1).Row = 1 then begin
if TMyDBGrid(DBGrid1).Col = 1 then
TMyDBGrid(DBGrid1).Col := DBGrid1.Columns.Count
else
DBGrid1.SelectedIndex := DBGrid1.SelectedIndex - 1;
end
else begin
if TMyDBGrid(DBGrid1).Col = 1 then begin
DBGrid1.DataSource.DataSet.Prior;
TMyDbGrid(DBGrid1).Col := DBGrid1.Columns.Count;
end
else
DBGrid1.SelectedIndex := DBGrid1.SelectedIndex - 1;
end;
end;
begin
Caption := IntToStr(TMyDbGrid(DBGrid1).RowCount);
if cbNormal.Checked then
Exit;
if Key = VK_Tab then begin
Key := 0;
if ssShift in Shift then
TabForwards
else
TabBackwards;
end;
end;
Notice that this uses TabForwards
and TabBackwards
sub-procedures and effectively reverses the roles of Tab and Shift Tab. The reason for this is because it separates thinking, and talking, about the movement behaviour from the key combination which produces it, which I found easier easier to code and to describe what the movement behaviour actually is.
With Tab and Shift Tab behaving as standard, this is how the DBGrid behaves:
- Tabbing forwards
If the cursor is in the New Record row, focus move to the next cell in the row until it reaches the RH column, then it wraps to the first column.
Otherwise, focus moves to the next cell in the current row until it reaches the RH column, then it wraps to the first column of the next row, if there is one, otherwise it calls Append on the grid’s Dataset, and moves to the first column of the New Record row.
In the New Record row, pressing the Tab Backwards key abandons the new record.
- Tabbing backwards
If the cursor is in the New Record row, the new record is abandoned. Otherwise, focus moves to the prior cell in the current row until it reaches the LH column, then it wraps to the RH column of the prior row. Once it reaches the LH column of the first row, it wraps to the RH column in that row.
That is what the second example does.
This does not, however, do what you said in your comment
when I reach last cell in DBgrid, the tab key (not shift-Tab) need to open new record.
and this is why:
Your way, the behaviour of the grid in response to the Tab key is different in the last cell compared with every other one. In the other cells, Tab will move left and wrap upwards to the prior row, whereas in the last cell it will move downwards. That would puzzle me as a user. Anyway, if that’s really what you want, you can rearrange the second example to behave that way.
When you use Tab and Shift Tab in the normal way, the behaviour is as follows:
8
solved Focus cells in reverse order for any utility don’t support RTL [closed]