Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Как переместить курсор в ячейку в StringGrid в Delphi и Pascal

Delphi , Компоненты и Классы , TStringGrid и TDrawGrid

 

Проблема перемещения курсора в StringGrid

Многие разработчики, работающие с компонентом TStringGrid в Delphi и Lazarus, сталкиваются с проблемой программного перемещения курсора в нужную ячейку после завершения редактирования. Как показывает обсуждение на форуме, пользователь bowlofpetunias хотел переместить курсор в ячейку с неверными данными, чтобы пользователь мог их исправить, но столкнулся с трудностями.

Анализ исходного кода

В представленном коде используется метод GoToColRow, который пытается установить позицию курсора:

Procedure TForm1.GoToColRow(col, row : integer);
begin
  stringgrid1.Col := col;
  stringgrid1.Row := row;
  col := stringgrid1.Col;
  row := stringgrid1.Row;
end;

Однако этот код не работает как ожидается, потому что сразу после события OnEditingDone StringGrid автоматически перемещает курсор в зависимости от действий пользователя (например, при нажатии Enter или стрелок).

Решение с использованием таймера

Как правильно заметил Handoko, для корректной работы необходимо добавить небольшую задержку перед перемещением курсора. Это можно реализовать с помощью компонента TTimer:

procedure TForm1.StringGrid1EditingDone(Sender: TObject);
var
  bng: real;
  acol, arow, code: integer;
begin
  StaticText1.Caption := '';
  acol := stringgrid1.Col;
  arow := stringgrid1.Row;

  Val(stringgrid1.Cells[acol, arow], bng, code);
  if bng > 360 then
  begin
    Windows.beep(500, 200);
    StaticText1.Caption := '... illegal value';

    // Устанавливаем таймер для отложенного перемещения
    Timer1.Interval := 100; // небольшая задержка
    Timer1.Tag := acol * 1000 + arow; // сохраняем координаты в Tag
    Timer1.OnTimer := @TimerMoveToCell;
    Timer1.Enabled := True;
  end;
end;

procedure TForm1.TimerMoveToCell(Sender: TObject);
var
  col, row: Integer;
begin
  Timer1.Enabled := False;

  // Извлекаем координаты из Tag
  col := Timer1.Tag div 1000;
  row := Timer1.Tag mod 1000;

  // Перемещаем курсор
  StringGrid1.Col := col;
  StringGrid1.Row := row;
  StringGrid1.SetFocus;
end;

Альтернативное решение без таймера

Если вы не хотите использовать таймер, можно попробовать перенаправить фокус через очередь сообщений:

procedure TForm1.StringGrid1EditingDone(Sender: TObject);
var
  bng: real;
  acol, arow, code: integer;
begin
  StaticText1.Caption := '';
  acol := stringgrid1.Col;
  arow := stringgrid1.Row;

  Val(stringgrid1.Cells[acol, arow], bng, code);
  if bng > 360 then
  begin
    Windows.beep(500, 200);
    StaticText1.Caption := '... illegal value';

    // Отложенное перемещение через очередь сообщений
    Application.QueueAsyncCall(@MoveToCellAsync, acol * 1000 + arow);
  end;
end;

procedure TForm1.MoveToCellAsync(Data: PtrInt);
var
  col, row: Integer;
begin
  col := Data div 1000;
  row := Data mod 1000;

  StringGrid1.Col := col;
  StringGrid1.Row := row;
  StringGrid1.SetFocus;
end;

Дополнительные советы по работе с StringGrid

  1. Проверка ввода данных:
procedure TForm1.StringGrid1ValidateEntry(sender: TObject; aCol, aRow: Integer;
  const OldValue: string; var NewValue: String);
var
  val: Double;
  code: Integer;
begin
  if TryStrToFloat(NewValue, val) then
  begin
    if (val > 360) then
    begin
      MessageDlg('Значение не может превышать 360', mtError, [mbOK], 0);
      NewValue := OldValue;
    end;
  end
  else
  begin
    MessageDlg('Введите числовое значение', mtError, [mbOK], 0);
    NewValue := OldValue;
  end;
end;
  1. Настройка свойств StringGrid:
procedure TForm1.FormCreate(Sender: TObject);
begin
  StringGrid1.Options := StringGrid1.Options + [goEditing, goAlwaysShowEditor];
  StringGrid1.FixedCols := 1;
  StringGrid1.FixedRows := 1;
end;
  1. Автоматический переход к следующей ячейке:
procedure TForm1.StringGrid1KeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then // Enter
  begin
    if StringGrid1.Col < StringGrid1.ColCount - 1 then
      StringGrid1.Col := StringGrid1.Col + 1
    else if StringGrid1.Row < StringGrid1.RowCount - 1 then
    begin
      StringGrid1.Col := 1;
      StringGrid1.Row := StringGrid1.Row + 1;
    end;
    Key := #0;
  end;
end;

Заключение

Проблема перемещения курсора в StringGrid после редактирования решается добавлением небольшой задержки перед установкой позиции. Это можно реализовать как через TTimer, так и через очередь сообщений Application.QueueAsyncCall. Выбор метода зависит от ваших предпочтений и конкретных требований приложения.

Для более надежной валидации данных рекомендуется использовать событие OnValidateEntry, которое позволяет проверять ввод непосредственно во время редактирования ячейки.

Создано по материалам из источника по ссылке.

Контекст описывает решение проблемы программного перемещения курсора в нужную ячейку компонента StringGrid в Delphi и Pascal с использованием таймера или очереди сообщений после завершения редактирования.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: TStringGrid и TDrawGrid ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-06-24 01:21:13/0.0056600570678711/0