You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使FMX TStringGrid空白单元格重新获取焦点?

问题场景

我使用FMX的TStringGrid控件,包含三列:

  • 列1:TStringColumn
  • 列2:TCurrencyColumn
  • 列3:包含"One""Two""Three"选项的TPopupColumn

已为控件添加OnEditingDone事件,当列1内容为空时弹出提示。控件Options.Tabs属性设为True,但当列1空白时按Tab键切换到列2,触发错误提示后,OnEditingDone事件里的SelectCell无法将焦点重新设置回空白单元格。

(演示效果:stringgrid切换标签页演示)

现有代码示例:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Rtti,
  FMX.Grid.Style, FMX.StdCtrls, FMX.Grid, FMX.Controls.Presentation,
  FMX.ScrollBox;

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    StringColumn1: TStringColumn;
    CurrencyColumn1: TCurrencyColumn;
    PopupColumn1: TPopupColumn;
    procedure FormCreate(Sender: TObject);
    procedure StringGrid1EditingDone(Sender: TObject; const ACol,
      ARow: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
begin
  StringGrid1.SelectCell(0,0);
  StringGrid1.SetFocus;
end;

procedure TForm1.StringGrid1EditingDone(Sender: TObject; const ACol,
  ARow: Integer);
begin
  if ACol=0 then
    if StringGrid1.Cells[0,ARow] = '' then
    begin
      ShowMessage('Col 0 Row ' + ARow.ToString+ ' Cannot be blank');
      StringGrid1.SelectCell(0,ARow);
    end;
end;

end.
解决方案

问题核心是OnEditingDone事件触发时机早于Tab键的焦点切换逻辑,你设置的单元格选择会被后续默认操作覆盖。要解决这个问题,需要延迟执行焦点重置操作,让Tab的默认逻辑先完成,再强制拉回焦点。

推荐使用TThread.Queue实现延迟,无需额外控件且能保证在主线程执行,修改OnEditingDone事件代码如下:

procedure TForm1.StringGrid1EditingDone(Sender: TObject; const ACol,
  ARow: Integer);
var
  TargetCol, TargetRow: Integer;
begin
  if ACol = 0 then
    if StringGrid1.Cells[0, ARow] = '' then
    begin
      TargetCol := ACol;
      TargetRow := ARow;
      ShowMessage('Col 0 Row ' + ARow.ToString + ' Cannot be blank');
      // 延迟执行单元格选择,确保Tab的焦点切换逻辑已完成
      TThread.Queue(nil, procedure
        begin
          StringGrid1.SelectCell(TargetCol, TargetRow);
          StringGrid1.SetFocus;
          // 直接进入编辑模式,方便用户输入
          StringGrid1.EditorMode := True;
        end);
    end;
end;

关键说明

  1. 延迟执行:TThread.Queue将匿名函数放入主线程消息队列末尾,等当前Tab触发的焦点切换逻辑执行完毕后再运行,确保你的设置不会被覆盖。
  2. 焦点与编辑状态:除了SelectCell,额外调用SetFocus确保控件本身获得焦点,再设置EditorMode := True直接进入编辑状态,优化用户操作流程。

另外也可以通过OnKeyDown拦截Tab键,但这种方式需要处理Shift+Tab反向切换等边界情况,延迟执行的方式更简洁可靠。


内容的提问来源于stack exchange,提问作者Michael Riley - AKA Gunny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:23:25