如何使FMX TStringGrid空白单元格重新获取焦点?
问题场景
我使用FMX的TStringGrid控件,包含三列:
- 列1:
TStringColumn - 列2:
TCurrencyColumn - 列3:包含"One""Two""Three"选项的
TPopupColumn
已为控件添加OnEditingDone事件,当列1内容为空时弹出提示。控件Options.Tabs属性设为True,但当列1空白时按Tab键切换到列2,触发错误提示后,OnEditingDone事件里的SelectCell无法将焦点重新设置回空白单元格。
(演示效果:
)
现有代码示例:
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;
关键说明
- 延迟执行:
TThread.Queue将匿名函数放入主线程消息队列末尾,等当前Tab触发的焦点切换逻辑执行完毕后再运行,确保你的设置不会被覆盖。 - 焦点与编辑状态:除了
SelectCell,额外调用SetFocus确保控件本身获得焦点,再设置EditorMode := True直接进入编辑状态,优化用户操作流程。
另外也可以通过OnKeyDown拦截Tab键,但这种方式需要处理Shift+Tab反向切换等边界情况,延迟执行的方式更简洁可靠。
内容的提问来源于stack exchange,提问作者Michael Riley - AKA Gunny
相关产品推荐
相关产品推荐

