检测 TWebBrowser 文档中的活动元素何时发生变化

2024-04-29

是否有任何我可以挂钩的事件来检测网页上的活动元素何时发生变化?例如,当用户聚焦编辑框时。

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


这并不是对您的问题的完整答案,但希望能帮助您完成大部分工作。

(对于通过类似的 q 到达这里的未来读者:

  • 假设您有一个用于自动化/Com 服务器的类型库导入单元,例如 SHDocVw、MSHTML 或 MS Word 的类型库导入单元。有时,Delphi 的类型库导入器会向它生成的 Delphi TObject 后代包装器添加事件支持,例如 TWebBrowser、OnNavigateComplete 等的事件。其他时候,它不能或不会生成 Delphi 包装器类,但您仍然可以附加通过多种方法之一连接到服务器对象事件,例如通过创建如下所示的 EventObject,它连接服务器对象的事件和 Delphi 代码中的事件处理程序。

  • 处理接口事件基本上涉及定义一个实现 IDispatch 接口的 Delphi 类,然后将该接口连接到您想要通知其事件的 Ole 或 COM 对象。然后,当接口“后面”的 Ole/COM 中发生事件时,它会像您调用 IDispatch 一样调用 IDispatch。您对事件通知的处理完全取决于您;下面的代码将它们传递给 TForm1 的方法。 )

下面的 EventObject 与 TeamB 的 Deborah Pate 于 2003 年 11 月在 Borland NG 上发布的事件密切相关(她的网站上有一个关于使用 Delphi 进行自动化的非常好的部分 -http://www.djpate.freeserve.co.uk/Automation.htm 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, ExcepInfo,
  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, %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 在进入sameINPUT 框,每次使用不同的 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;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

检测 TWebBrowser 文档中的活动元素何时发生变化 的相关文章

  • 如何读取注册表项的默认值

    我有一个 Delphi XE2 项目来使用注册表项进行某些操作 所以我定义了以下代码 procedure TMainForm BitBtn01Click Sender TObject var RegistryEntry TRegistry
  • 从delphi应用程序调用.net4.0 com服务器后出现错误异常

    我们正在将代码库从 BDS2006 迁移到 Rad Studio XE 我们发现了一些非常奇怪的行为 如果我们在从 Net4 0 中实现的 COM 服务器创建一些对象后进行无效的浮点运算 即除以零 我们不会没有得到正常异常 即 EDivis
  • 我需要避免尝试更新连接到 TSQLQuery 的 Delphi TClientDataset 中的非物理字段

    概要 我的代码正在尝试更新 Delphi XE 中的非物理字段TClientDataset 连接到TSQLQuery以其SQL属性集 作为运行时的结果创建Open命令 我有一个TClientDataset连接到一个TDatasetProvi
  • 如何追踪“地址 00000000”的访问违规

    我知道如何创建 map 文件来在错误消息包含实际地址时跟踪访问冲突错误 但是如果错误消息说怎么办 Access violation at address 00000000 Read of address 00000000 我从哪里开始寻找这
  • 如何向标准集合编辑器添加图标?

    我有一个自定义控件 它利用TCollection and TCollectionItem 在集合编辑器中 我想向每个列表项添加图标 该列表项由内部TImageList 在其父组件内 集合项本身代表图标 我想在这个编辑器中显示相应的图标 如何
  • 如何将数据库查询的行转换为 XML 文件?

    我正在开发一个 Delphi 应用程序 该应用程序需要从一段工作中获取行并将其转换为单个 XML 文件 以便上传到第三方 Web 服务 有没有可用的组件或库可以做到这一点 如果不是 那么构建 DB2XML 转换器的最佳代码方法是什么 我注意
  • 当 Delphi 处于覆盖模式时,如何更改它的光标形状?

    当使用 Delphi 的任何版本时 我有时会碰巧按下插入键并打开覆盖模式 这通常是一个很大的麻烦 并且您进入覆盖模式的唯一指示是编辑器底部的小文本 当使用其他程序 首先想到的是 Notepad 时 当您处于插入模式时 文本光标是 当您处于覆
  • FreePascal x64 上系统单元函数的汇编调用

    我有一些 Delphi 汇编代码 可以在 Win32 Win64 和 OSX 32 上编译并正常工作 XE2 但是 由于我需要它在 Linux 上工作 所以我一直在考虑编译它的 FPC 版本 到目前为止 Win32 64 Linux32 6
  • 在Delphi 7中,为什么我可以给const赋值?

    我将一些 Delphi 代码从一个项目复制到另一个项目 发现它在新项目中无法编译 但在旧项目中可以编译 代码看起来像这样 procedure TForm1 CalculateGP const Price money 0 begin Pric
  • Delphi 流畅的界面

    使用上有什么优点和缺点流畅的界面 http en wikipedia org wiki Fluent interface在德尔福 流畅的界面应该会增加可读性 但我对此有点怀疑one包含很多链式方法的长 LOC 是否存在编译器问题 是否存在任
  • 如何使用 Gmail 的 SMTP 和 Indy 10 发送电子邮件?

    我正在使用 Delphi 2009 和 svn 中最新的 Indy 10 通过 SMTP 发送电子邮件 但它不适用于 Gmail Google Apps 托管域 当我尝试发送电子邮件时 我收到 必须首先发出 STARTTLS 命令 我尝试用
  • 如何使 StringGrid 的列适合网格的宽度?

    我已经寻找解决方案很长时间了 但没有任何运气 有谁知道一个简单的方法来做到这一点 例如 我想拉伸网格的第二列以适应网格的宽度 Use the ColWidths财产 像这样 with StringGrid1 do ColWidths 1 C
  • 如何从该 JAVA 文件中提取 Delphi 类以与 Android 一起使用?

    我的Delphi XE7项目需要与FTDI FT311 Android 配件芯片 http www ftdichip com Products ICs FT311D html 他们帮助提供了一个 Android 演示 其中包括他们的 JAV
  • 使用 PutBlock 并将字节数组全部设置为零的 EIPHTTPProtocolExceptionPeer 异常

    使用 Delphi XE2 Update 3 我在将零字节块上传到 Azure 时遇到问题 当我说零字节时 我指的是每个元素设置为零的字节数组 不是零长度 例如 var ConInfo TAzureConnectionInfo RespIn
  • 从其可执行文件的路径获取服务名称

    我有一个可执行文件的路径 它是一个正在运行的服务应用程序 例如 C Program Files x86 Someapp somesvc exe 我想停止并启动它 为此我想我需要获取服务的名称 如下所示 this https stackove
  • 如何读取和更改 TEdit 控件的值?

    我有一个表格TForm1有 5TEdit and 2 TBitBtn 我还需要该程序 以便在输入数字数据后Edit1 and Edit2 on BitBtn1Click Edit1 and Edit2值将被求和并显示在Edit3 你想做这样
  • Delphi 的内存分析工具?

    我建立了一个项目并运行它 然后在 Process Explorer 中查看它 结果发现它在启动时使用的 RAM 比我想象的要多 5 倍 现在 如果我的程序运行得太慢 我会将其连接到分析器并让它告诉我什么正在使用我的所有周期 有没有类似的工具
  • 如果加载 dll 找不到依赖项,有什么方法可以捕获错误吗?

    我正在编写一个 Windows 32 位程序 可以使用多个可能的 dll 之一 所以它尝试依次加载每个 dll 使用SysUtils SafeLoadLibrary如果加载成功 它就会使用该 dll 不幸的是 其中一些 dll 静态链接到其
  • 如何在按键时识别 unicode 键?

    我的应用程序使用 unicode 字符 并且我有几个文本字段 我想限制用户输入特殊字符 例如 begin if not Key in a z A Z 0 9 13 8 then Key 0 if Key 13 then bOk Click
  • Delphi:现场记录应用程序错误

    使用 Delphi 7 我想知道是否有一个免费组件可以在我的应用程序在远程站点运行时收集诊断信息并帮助我调试错误报告 也许它会记录每个选择的菜单项 单击的控件 文本输入等 也许它只是在崩溃时转储堆栈 也许它还有其他作用 我不介意添加代码 例

随机推荐

  • 在 python matplotlib 中格式化损坏的 y 轴

    我正在 matplotlib 中处理一个 相当复杂的 条形图 它包含来自多个源的摘要数据 每个源都沿 x 轴标记 y 轴上有一系列结果 许多结果都是异常值 我尝试使用断开的 y 轴来显示这些结果 而不会使用以下组合来扭曲整个图表这个方法 h
  • 使用 Javascript OAuth 2.0 SDK 更新签名请求

    随着新的 Javascript SDK 和 OAuth 2 0 的发布 我想知道是否可以在不重定向用户的情况下更新 SignedRequest 和 authtoken 因此我使用了以下方法 基本上 这是我的应用程序的一种保持活动状态的方法
  • jquery 是否有 .toggle() 的替代方案[重复]

    这个问题在这里已经有答案了 目前根据 Jquerysite http api jquery com category deprecated deprecated 1 8 toggle 在 1 8 版本后已被弃用 那么有没有 toggle 的
  • Windows 消息

    我需要发送带有自定义 ID 的自定义 Windows 消息 其他应用程序将侦听该消息 Windows 是否为内部消息保留任何预定义的消息 ID 范围 如 SQL Server 那样 内部消息最多为 50 000 The 文档 https m
  • Mysql:磁盘已满错误

    我的 mysql 服务器有一些问题 120310 6 55 36 ERROR usr libexec mysqld Disk is full writing virtual cdrs MYD Errcode 28 Waiting for s
  • Git 责备文件中的作者列表

    有没有办法找到在 repo 中编辑 java 文件中的类的作者列表git blame 作者列表必须是唯一的 我尝试使用以下命令 但它没有删除重复项 并且每行输出中都有 作者 一词 不需要对输出进行排序 但我希望获得没有任何重复的输出 git
  • std::vector 错误 C2582:“operator =”函数在以下位置不可用

    我使用简单的向量push back到类型A的对象 并收到此错误 这是我的代码 class A public A int a int b int c include A h std vector a vec objects new std v
  • 数据映射器和连接池逻辑

    所以我尝试在 Rails 3 2 8 应用程序中使用 datamapper 我有一个config initializers dm rb我加载的地方database yml hash YAML load File new database y
  • fgets 和 fread 之间的区别

    我有以下代码 include
  • iOS - 支持 iPad 和 iPhone,无需使用笔尖

    我正在尝试编写一个应用程序而不使用nib 一切我都会以编程方式完成 现在的问题是 我该如何支持两者iPad and iPhone 显然 我不能这样做 if UIDevice currentDevice userInterfaceIdiom
  • 是否有一种仅使用极坐标来查找附近点的算法?

    假设我有一个点向量作为极坐标 假设其中一个点充当探针 我想找到一定距离内的所有其他点 是否有一种算法可以在不将它们转换为笛卡尔形式的情况下执行此操作 您正在寻找极坐标的距离 你可以在这里找到公式link http math ucsd edu
  • webpack-dev-server 中的代理 websockets 连接

    是否可以在 webpack 开发服务器中代理 websocket 连接 我知道如何将常规 HTTP 请求代理到另一个后端 但它不适用于 websockets 大概是因为代理配置中的目标以 http 开头 webpack dev server
  • 如何使用 php 将文本区域中的链接转换为链接元素?

    我正在创建一个脚本 它包含一个发布脚本 但我希望用户直接从其他任何地方复制链接 当他们发布链接文本时 链接文本应自动将链接转换为链接元素 a 例如 Ask this on http stackoverflow com now 成为 Ask
  • iOS 6 UITabBarController 支持当前 UINavigationcontroller 的方向

    我有一个 iPhone 应用程序正在更新到 iOS 6 但存在旋转问题 我有一个UITabBarController与 16UINavigationCotrollers 大多数子视图可以纵向或横向工作 但其中一些只能纵向 在 iOS 6 中
  • 如何创建不带 (to) 部分的 mailto: 链接

    如何正确构建没有该部分的 mailto 链接 mailto email protected cdn cgi l email protection 我不需要地址 只想通过mailto填写后面的参数 是的你可以 mailto body tisb
  • 我可以替换
    元素的展开图标 (▶) 吗?

    我用
  • Q-learning 和价值迭代有什么区别?

    Q learning 与强化学习中的值迭代有何不同 我知道 Q learning 是无模型的 训练样本是过渡 s a s r 但是 既然我们知道 Q 学习中的转换和每个转换的奖励 那么它与基于模型的学习不一样吗 在基于模型的学习中 我们知道
  • 为什么呼叫会话不起作用? (代码点火器 3)

    我的配置是这样的 config sess driver database select database driver config sess save path ci sessions name of the mysql table co
  • 为 C# 和 C++ 应用程序编写 DLL

    我需要编写几个 DLL 它们都可以从 C 应用程序和 C 应用程序访问 最初 我认为通过用 C 编写 DLL 并从 C 和 C 应用程序链接到它们可以节省时间 精力 这种方法明智吗 还是应该使用 C 编写 DLL 我的建议是在您最舒服的地方
  • 检测 TWebBrowser 文档中的活动元素何时发生变化

    是否有任何我可以挂钩的事件来检测网页上的活动元素何时发生变化 例如 当用户聚焦编辑框时 我知道我可以检查计时器中的活动元素 但如果可能的话我宁愿避免这种情况 这并不是对您的问题的完整答案 但希望能帮助您完成大部分工作 对于通过类似的 q 到