我一直在搜索,一般的答案似乎已经放置了
SomeEdit2.setFocus;
在SomeEdit1.OnExit事件中。我试过这个(使用Delphi Xe5,为iOS开发),它会导致应用程序崩溃。该应用程序不会抛出错误,它只是空白和崩溃。我已尝试将相同的代码放在其他事件中,但它不能按预期工作。例如,当放置在SomeEdit1.OnChange事件中时,当用户在虚拟键盘上点击“完成”时 - 焦点切换到所需的控件,但键盘不显示并停止正常工作。
当用户点击虚拟键盘上提供的“完成”按钮时,在控件之间更改焦点的正确方法是什么?
答案 0 :(得分:4)
您无法将VCL-Control行为与FMX-Control行为进行比较,因为有时它们表现不同 - 它们不应该,但它们不同。
在VCL中,您有一个OnExit
事件,它在焦点离开控件后立即发生。所以这是一个OnAfterExit
事件。
在FMX中,OnExit
事件在焦点消失之前触发。所以这是OnBeforeExit
。
procedure TControl.DoExit;
begin
if FIsFocused then
begin
try
if CanFocus and Assigned(FOnExit) then
FOnExit(Self);
FIsFocused := False;
现在,这与您当前的问题有什么关系?
如果您将焦点设置为OnExit
事件中的另一个控件,则会调用当前活动控件DoExit
方法,该方法会调用OnExit
事件,并且您有一个完美的圆圈。
所以你有几个选项来解决这个问题
最佳解决方案是创建错误报告并让emba修复此错误。
已经有错误报告117752出于同样的原因。所以我发布了解决方案作为评论。
FMX.Controls.pas
将FMX.Controls
复制到项目源目录中并修补错误代码(只需一行)
procedure TControl.DoExit;
begin
if FIsFocused then
begin
try
FIsFocused := False; // thats the place to be, before firering OnExit event
if CanFocus and Assigned(FOnExit) then
FOnExit(Self);
//FIsFocused := False; <-- buggy here
SetFocus
来控制要在OnExit
中设置焦点,您需要做更多工作,因为将焦点更改为下一个控件的消息已经排队。您必须确保焦点更改为所需控件,>>已经排队的焦点更改消息。最简单的方法是使用计时器。
以下是一个示例FMX表单,其中包含3个编辑控件,每个表单都有OnExit
个事件
unit MainForm;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
FMX.Edit;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
EnsureActiveControl_Timer: TTimer;
procedure EnsureActiveControl_TimerTimer(Sender: TObject);
procedure Edit1Exit(Sender: TObject);
procedure Edit2Exit(Sender: TObject);
procedure Edit3Exit(Sender: TObject);
private
// locks the NextActiveControl property to prevent changes while performing the timer event
FTimerSwitchInProgress: Boolean;
FNextActiveControl: TControl;
procedure SetNextActiveControl(const Value: TControl);
protected
property NextActiveControl: TControl read FNextActiveControl write SetNextActiveControl;
public
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Edit1Exit(Sender: TObject);
begin
NextActiveControl := Edit3;
end;
procedure TForm1.Edit2Exit(Sender: TObject);
begin
NextActiveControl := Edit1;
end;
procedure TForm1.Edit3Exit(Sender: TObject);
begin
NextActiveControl := Edit2;
end;
procedure TForm1.EnsureActiveControl_TimerTimer(Sender: TObject);
begin
EnsureActiveControl_Timer.Enabled := False;
FTimerSwitchInProgress := True;
try
if (Self.ActiveControl <> NextActiveControl) and NextActiveControl.CanFocus then
NextActiveControl.SetFocus;
finally
FTimerSwitchInProgress := False;
end;
end;
procedure TForm1.SetNextActiveControl(const Value: TControl);
begin
if FTimerSwitchInProgress
or (FNextActiveControl = Value)
or (Assigned(Value) and not Value.CanFocus)
or (Self.ActiveControl = Value)
then
Exit;
FNextActiveControl := Value;
EnsureActiveControl_Timer.Enabled := Assigned(FNextActiveControl);
end;
end.