首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免SetFocus引发异常

避免SetFocus引发异常
EN

Stack Overflow用户
提问于 2016-12-07 12:03:52
回答 3查看 1.4K关注 0票数 6

我使用的是一个庞大的遗留源代码,其中在许多地方调用了几个SetFocus,但有时缺少检查控件是否可见或启用。

由于时间有限,以及大量的源代码,我决定忽略这些错误,因为焦点(在我们的例子中)不是一个关键的特性。引发的异常将导致完全失败,而缺少焦点只是一个光学问题。

我目前的计划如下:

  1. 我用这样的类助手创建了一个单元: 类型TWinControlEx = TWinControl过程SetFocusSafe的类助手; 过程TWinControlEx.SetFocusSafe;如果CanFocus开始,那么SetFocus;结束;
  2. 我将该单元包含到每个使用".SetFocus“的单元中(我将使用全局代码搜索)
  3. 我用.SetFocusSafe替换所有的.SetFocusSafe

但是有一个问题:如果可能的话,我想避免同事不小心使用.SetFocus,或者忘记包含类保护单元。

我还有其他选择吗?

最好的情况是,如果存在一种使SetFocus不引发异常的技术/黑客。(不重新编译VCL)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-12-07 12:28:11

只需修补TWinControl.SetFocus方法:

代码语言:javascript
复制
unit SetFocusFix;

interface

implementation

uses
  Controls,
  Forms,
  SysUtils,
  Windows;

type
  TWinControlHack = class(TWinControl)
  public
    procedure SetFocus; override;
  end;

procedure TWinControlHack.SetFocus;
var
  Parent: TCustomForm;
begin
  if not CanFocus then Exit;

  Parent := GetParentForm(Self);
  if Parent <> nil then
    Parent.FocusControl(Self)
  else if ParentWindow <> 0 then
    Windows.SetFocus(Handle)
  else
    ValidParentForm(Self);
end;

procedure RedirectFunction(OrgProc, NewProc: Pointer);
type
  TJmpBuffer = packed record
    Jmp: Byte;
    Offset: Integer;
  end;
var
  n: UINT_PTR;
  JmpBuffer: TJmpBuffer;
begin
  JmpBuffer.Jmp := $E9;
  JmpBuffer.Offset := PByte(NewProc) - (PByte(OrgProc) + 5);
  if not WriteProcessMemory(GetCurrentProcess, OrgProc, @JmpBuffer, SizeOf(JmpBuffer), n) then
    RaiseLastOSError;
end;

initialization
  RedirectFunction(@TWinControl.SetFocus, @TWinControlHack.SetFocus);

end.
票数 7
EN

Stack Overflow用户

发布于 2016-12-07 12:31:12

另一个选择

代码语言:javascript
复制
  TWinControlEx = class helper for TWinControl
    procedure SetFocus; reintroduce;
  end;

和..。

代码语言:javascript
复制
procedure TWinControlEx.SetFocus;
var
  Parent: TCustomForm;
begin
  if not CanFocus then Exit;
  Parent := GetParentForm(Self);
  if Parent <> nil then
    Parent.FocusControl(Self)
  else if ParentWindow <> 0 then
    Winapi.Windows.SetFocus(Handle)
  else
    ValidParentForm(Self);
end;
票数 4
EN

Stack Overflow用户

发布于 2020-10-09 18:13:46

下面的答案并不直接回答您的问题,但是它仍然是相关的,因为您依赖于CanFocus。CanFocus回答了一个谎言。你不应该依赖它。文件也是错误的。更确切地说,即使控件不可聚焦,CanFocus也可以返回True。在这种情况下,将引发异常。

所以,用这个代替:

代码语言:javascript
复制
function CanFocus(Control: TWinControl): Boolean;   
begin
 Result:= Control.CanFocus AND Control.Enabled AND Control.Visible;
 if Result
 AND NOT Control.InheritsFrom(TForm)
 then
   { Recursive call:
     This control might be hosted by a panel which could be also invisible/disabled.
     So, we need to check all the parents down the road, until we encounter the parent Form.
     Also see: GetParentForm }
   Result:= CanFocus(Control.Parent); { Parent of a control could be nil, but in this case Control.CanFocus will deal with that.}
end;


procedure SetFocus(Control: TWinControl);
begin
 if CanFocus(Control)
 then Control.SetFocus;
end;

PS:在拉撒路下,CanFocus工作正常。

理由:J给出了一个很好的答案,但我不喜欢类助手,因为如果同一个类有一个以上的类助手,那么唯一的类将被使用。这个过程几乎是“通过骰子”:在“使用”子句中单元的顺序决定哪一个助手将申请。我不喜欢编程语言中的这种随机性。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41016976

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档