English 中文(简体)
避免产生例外情形
原标题:Avoid that SetFocus raises an Exception

我正在以一个巨大的遗产源代码开展工作,其中许多地方都呼吁使用<代码>Setfocus,但有时,如果控制明显或无法进行,则检查。

由于时间有限,而且源码巨大,我决定,我想忽略这些错误,因为重点(就我们而言)不是关键特征。 提出的例外将导致完全失败,而缺失的焦点只是一个光学问题。

我目前的计划如下:

  1. 我设立了一个单位,配备一个班级助手:

    type TWinControlEx = class helper for TWinControl procedure SetFocusSafe; end;

    procedure TWinControlEx.SetFocusSafe; begin if CanFocus then SetFocus; end;

  2. 我将该股纳入每个单位,使用“SetFocus”(我将使用全球代码搜索)

  3. I replace every .SetFocus with .SetFocusSafe

问题在于: 如果有可能,我想避免这些同事意外使用SetFocus,或忘记把班轮包括在内。

Which other options do I have?

The best case would be if there is a technique/hack to make SetFocus not raising an exception. (Without recompiling the VCL)

最佳回答

Just su the TWinControl.Setfocus 方法:

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.
问题回答

或者

  TWinControlEx = class helper for TWinControl
    procedure SetFocus; reintroduce;
  end;

......

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;

My answer below does not answer DIRECTLY your question, but it is still relevant because you rely on CanFocus. CanFocus returns a lie. You should not rely on it. The documentation is also wrong. More exactly, CanFocus can return True even if the control is not focusable. In this case, an exception will be raised. PS: Under Lazarus CanFocus works properly.

So, you will have to write a new CanFocus that tests not only the state of the current control but ALL its parents. You will end up with a recursive call. Only then you can write a new SetFocus that really works:

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

本条中的充分编码和解释:Setfocus-is-broken-in-Delphi

(SO 规则规定,我必须宣布我附属于该网站,以便:把我的网站带上)


理由:

J provided a nice answer, but PERSONALLY I don t like class helpers because if you have more than one class helper for the same class, then only one will be used - which one is determined (almost randomly) by the order of the units in the "uses" clause. Accidentally change the order of the units in the "uses" and you accidentally change the behavior of your program! I don t like this amount of randomness in a programming language. Until Emba comes with a stable solution, I won t use Class Helpers.





相关问题
determining the character set to use

my delphi 2009 app has a basic translation system that uses GNUGetText. i had used some win API calls to prepare the fonts. i thought it was working correctly until recently when someone from Malta ...

Help with strange Delphi 5 IDE problems

Ok, I m going nuts here. For the last (almost) four years, I ve been putting up with some extremely bad behavior from my Delphi 5 IDE. Problems include: Seemingly random errors in coride50.bpl ...

How to write a Remote DataModule to run on a linux server?

i would like to know if there are any solution to do this. Does anyone? The big picture: I want to access data over the web, using my delphi thin clients. But i´would like to keep my server/service ...

How convert string to integer in Oxygene

In Delphi, there is a function StrToInt() that converts a string to an integer value; there is also IntToStr(), which does the reverse. These functions doesn t appear to be part of Oxygene, and I can ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签