delphi – 检测TWebBrowser文档中的活动元素何时更改

前端之家收集整理的这篇文章主要介绍了delphi – 检测TWebBrowser文档中的活动元素何时更改前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
是否有任何可以挂钩的事件来检测网页上的活动元素何时发生变化?例如,当用户聚焦编辑框时.

我知道我可以检查计时器中的活动元素,但如果可能的话我宁愿避免这种情况.

解决方法

这不是 – 完全 – 你的q的完整答案,但希望能在那里得到你的大部分.

(对于通过类似问题到达此处的未来读者:

>假设您有自动/ Com服务器的类型库导入单元,如SHDocVw,MSHTML或MS Word.有时,Delphi的类型库导入器为它生成的Delphi TObject-descendant包装器添加事件支持,比如TWebBrowser,OnNavigateComplete等的事件.有时它不能或不会生成Delphi包装类,但你仍然可以附加通过多种方法之一对服务器对象事件,例如通过创建如下所示的EventObject,它连接服务器对象的事件和Delphi代码中的事件处理程序.
>处理接口事件基本上涉及定义Delphi类,该类实现IDispatch接口,然后将该接口连接到要通知其事件的Ole或COM对象.然后,当Ole / COM“后面”接口发生事件时,它会调用您的IDispatch,就像调用它一样.您对事件通知的处理完全取决于您;下面的代码将它们传递给TForm1的方法.
)

下面的EventObject紧密基于2003年11月由TeamB的Deborah Pate在Borland NGs中发布的一个(她在她的网站上有一个关于使用Delphi-http://www.djpate.freeserve.co.uk/Automation.htm进行自动化的非常好的部分).该对象非常通用,因为它不仅限于处理任何特定Ole / COM对象的事件.

//  The following code is intended to illustrate methods of detecting that the
//  active element in an Html page has changed.  See the comments in the AnEvent
//  procedure about how exactly to detect such a change.
//
//  The code also illustrates how to handle a single event,e.g. onbeforeeditfocus
//  of an Events objects such as HtmlDocumentEvents or HtmlDocumentEvents2 (see MSHTML.Pas)
//  or all the events the events interface contains.


type

  TInvokeEvent = procedure(Sender : TObject; DispIP : Integer) of Object;

  TEventObject = class(TInterfacedObject,IDispatch)
  private
    FOnEvent: TInvokeEvent;
    FSinkAllEvents : Boolean;
  protected
    function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
    function GetTypeInfo(Index,LocaleID: Integer; out TypeInfo): HResult; stdcall;
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount,LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult,ExcepInfo,ArgErr: Pointer): HResult; stdcall;
  public
    constructor Create(const AnEvent : TInvokeEvent; SinkAll : Boolean);
    property OnEvent: TInvokeEvent read FOnEvent write FOnEvent;
    property SinkAllEvents: Boolean read FSinkAllEvents;
  end;

type
  TForm1 = class(TForm)
  [ ... ]
  private
    { Private declarations }
    procedure AnEvent(Sender : TObject; DispID : Integer);
    procedure AnotherEvent(Sender : TObject; DispID : Integer);
  public
    { Public declarations }
    Doc : IHtmlDocument3;
    DocEvent,DocEvent2: OleVariant;
    Cookie : Longint;
    CPC : IConnectionPointContainer;
    Sink : IConnectionPoint;
    PrvActiveElement : IHTMLElement;
    Events : Integer;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TEventObject.Create(const AnEvent: TInvokeEvent; SinkAll : Boolean);
begin
  inherited Create;
  FOnEvent := AnEvent;
  FSinkAllEvents := SinkAll;
end;

function TEventObject.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  NameCount,LocaleID: Integer; DispIDs: Pointer): HResult;
begin
  Result := E_NOTIMPL;
end;

function TEventObject.GetTypeInfo(Index,LocaleID: Integer;
  out TypeInfo): HResult;
begin
  Result := E_NOTIMPL;
end;

function TEventObject.GetTypeInfoCount(out Count: Integer): HResult;
begin
  Result := E_NOTIMPL;
end;

function TEventObject.Invoke(DispID: Integer; const IID: TGUID;
  LocaleID: Integer; Flags: Word; var Params; VarResult,ArgErr: Pointer): HResult;
begin
  if SinkAllEvents then begin
    if Assigned(FOnEvent) then
      FOnEvent(Self,DispID);
    Result := S_OK;
  end
  else begin
    if (Dispid = DISPID_VALUE) then begin
      if Assigned(FOnEvent) then
        FOnEvent(Self,DispID);
      Result := S_OK;
    end
    else Result := E_NOTIMPL;
  end;
end;

procedure TForm1.AnEvent(Sender : TObject; DispID : Integer);
var
  Doc2 : IHTMLDocument2;
  E : IHTMLElement;
begin
  Inc(Events);
  Doc.QueryInterface(IHTMLDocument2,Doc2);
  E := Doc2.activeElement;

  //  NB: When an <INPUT> text edit is receiving focus,the following code is triggered twice
  //  or more with different values of Pointer(Doc2.activeElement).  So,"(E <> PrvActiveElement)"
  //  doesn't seem a very effective test that the active element has changed.  However,//  testing E's Name,ID,etc should provide a useful test.

  if (E <> Nil) and (E <> PrvActiveElement) and E.isTextEdit then begin
    if PrvActiveElement <> Nil then
      PrvActiveElement := E;
      Caption := Format('Something happened: Element Tagname: %s,Name: %s,%d,%p',[E.TagName,E.GetAttribute('Name',0),DispID,Events,Pointer(Doc2.activeElement)]);
  end;
end;

procedure TForm1.AnotherEvent(Sender : TObject; DispID : Integer);
begin
  Caption := Format('Something else happened: %d',[DispID]);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile('D:\aaad7\html\postdata.htm');
end;

procedure TForm1.btnLoadClick(Sender: TObject);
var
  V : OleVariant;
  Doc2 : IHtmlDocument2;
begin
  WebBrowser1.Navigate('about:blank');
  Doc := WebBrowser1.Document as IHTMLDocument3;
  Doc.QueryInterface(IHTMLDocument2,Doc2);
  V := VarArrayCreate([0,0],varVariant);
  V[0] := Memo1.Lines.Text;
  try
    Doc2.Write(PSafeArray(TVarData(v).VArray));
  finally
    Doc2.Close;
  end;

  DocEvent := TEventObject.Create(Self.AnEvent,cbSinkAll.Checked) as IDispatch;

  if cbsinkAll.Checked then begin
    CPC := Doc2 as IConnectionPointContainer;
    Assert(CPC <> Nil);
    OleCheck(CPC.FindConnectionPoint(HTMLDocumentEvents,Sink));
    OleCheck((Sink as IConnectionPoint).Advise(DocEvent,Cookie));
  end
  else
    Doc.onbeforeeditfocus := DocEvent;
end;

请注意TForm1.AnEvent中的注释.如果选中cbSinkAll复选框
并在具有多个INPUT框的页面上运行代码,您会注意到AnEvent在进入同一个INPUT框时会多次触发,每次都有不同的Doc2.ActiveElement值.我不确定为什么会这样,但它确实意味着比较当前
具有先前值的Doc2.ActiveElement属性的值无法有效检测更改
专注于Html页面.但是,比较元素的属性,例如,它的名称或ID似乎提供了可靠的检查.

两个警告:

>在Deborah Pate的原始代码中,她将以前的事件处理程序(如果有的话)保存到OleVariant中,以便以后可以恢复它.
>如果要连续连接到多个Html页面的事件,则应该释放它们之间的EventObject.

[从MSHTML.Pas中提取]

HTMLDocumentEvents = dispinterface
    ['{3050F260-98B5-11CF-BB82-00AA00BDCE0B}']
    function  onhelp: WordBool; dispid -2147418102;
    [...]
    procedure onbeforeeditfocus; dispid 1027;
  end;

猜你在找的Delphi相关文章