WebBrowser SinkEvents 和 DesignMode =“on”

发布于 2024-12-23 18:08:37 字数 4544 浏览 3 评论 0原文

Zarko Gajic 在以下文章和演示中演示了如何在鼠标移到 TWebBrowser 文档上时获取超链接的 url: http://delphi.about.com/od/vclusing/a/wbsinkevents.htm 此演示运行良好,直到 WebBrowser 设置为 designmode = 'on',然后 OnMouseMove 事件不会执行。能否增强演示,以便在 DesignMode = 'on' 时执行 OnMouseMove 事件?如果没有,是否有不同的方法来创建 Document.OnMouseMove 事件?我正在使用 Delphi 2010。

[编辑] 请求更多代码,因此这里是实现

procedure TForm1.DesignMode1Click( Sender: TObject );
var
  iDocument: MSHTML.IHTMLDocument2;
begin
  if Assigned( WebBrowser1 ) then
  begin
    iDocument := htmlDoc; //( WebBrowser1.Document as IHTMLDocument2 );
    if Assigned( iDocument ) then
    begin
      if DesignMode1.Checked then
        iDocument.DesignMode := 'On'
      else
        iDocument.DesignMode := 'Off';
      WebBrowser1.Refresh2;
    end;
  end;
end;

procedure TForm1.Document_OnMouseOver;
var
  element: IHTMLElement;
begin
  if htmlDoc = nil then
    Exit;

  element := htmlDoc.parentWindow.event.srcElement;

  elementInfo.Clear;

  if LowerCase( element.tagName ) = 'a' then
  begin
    elementInfo.Lines.Add( 'LINK info...' );
    elementInfo.Lines.Add( Format( 'HREF : %s', [ element.getAttribute( 'href', 0 ) ] ) );
  end
  else if LowerCase( element.tagName ) = 'img' then
  begin
    elementInfo.Lines.Add( 'IMAGE info...' );
    elementInfo.Lines.Add( Format( 'SRC : %s', [ element.getAttribute( 'src', 0 ) ] ) );
  end
  else
  begin
    elementInfo.Lines.Add( Format( 'TAG : %s', [ element.tagName ] ) );
  end;
end; (* Document_OnMouseOver *)

procedure TForm1.FormCreate( Sender: TObject );
begin
  WebBrowser1.Navigate( 'http://delphi.about.com' );
  elementInfo.Clear;
  elementInfo.Lines.Add( 'Move your mouse over the document...' );
end; (* FormCreate *)

procedure TForm1.WebBrowser1BeforeNavigate2( ASender: TObject; const pDisp: IDispatch;
  var URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool );
begin
  htmlDoc := nil;
end; (* WebBrowser1BeforeNavigate2 *)

procedure TForm1.WebBrowser1DocumentComplete( ASender: TObject; const pDisp: IDispatch; var URL: OleVariant );

begin
  if Assigned( WebBrowser1.Document ) then
  begin
    htmlDoc := WebBrowser1.Document as IHTMLDocument2;
    htmlDoc.onmouseover := ( TEventObject.Create( Document_OnMouseOver ) as IDispatch );
  end;
end; (* WebBrowser1DocumentComplete *)

{ TEventObject }

constructor TEventObject.Create( const OnEvent: TObjectProcedure );
begin
  inherited Create;
  FOnEvent := OnEvent;
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 ( DispID = DISPID_VALUE ) then
  begin
    if Assigned( FOnEvent ) then
      FOnEvent;
    Result := S_OK;
  end
  else
    Result := E_NOTIMPL;
end;

end.

[修复] 我发现将 webbrowser 设置为设计模式后,WebBrowser1DocumentComplete 未执行,因此我更改了 DesignMode1Click 并解决了问题。我发布此内容是为了其他人也可以看到此内容:

procedure TForm1.DesignMode1Click( Sender: TObject );
begin
  // the following is unsafe because you may click on the
  // check box even if you don't have any page navigated
  -- htmlDoc := WebBrowser1.Document as IHTMLDocument2;

  // htmlDoc will be assigned from the OnDocumentComplete
  // fired by Navigate procedure
  if Assigned( htmlDoc ) then
  begin
    if DesignMode1.Checked then
      htmlDoc.DesignMode := 'On'
    else
      htmlDoc.DesignMode := 'Off';

    // switching to design mode takes some time and if there 
    // are some pages which doesn't fire OnDocumentComplete 
    // event when you are switching to design mode, like
    // http://delphi.about.com do, then I would wait for 
    // web browser to be ready
    while WebBrowser1.ReadyState < READYSTATE_COMPLETE do
      Application.ProcessMessages;

    // release the previous "document instance"
    htmlDoc := nil;
    // assign the new one and attach the event
    htmlDoc := WebBrowser1.Document as IHTMLDocument2;
    htmlDoc.OnMouseOver := ( TEventObject.Create( Document_OnMouseOver ) as IDispatch );
  end;
end;

Zarko Gajic demonstrates how to get the url of a hyperlink when the mouse moves over a TWebBrowser Document in the following article and demo:
http://delphi.about.com/od/vclusing/a/wbsinkevents.htm
This demo works well until the WebBrowser is set to designmode = 'on', then the OnMouseMove event does not execute. Can the demo be enhanced so that the OnMouseMove event is executed when DesignMode = 'on'? If not is there a different way to create a Document.OnMouseMove event? I am using Delphi 2010.

[Edit] More code was requested so here is implementation

procedure TForm1.DesignMode1Click( Sender: TObject );
var
  iDocument: MSHTML.IHTMLDocument2;
begin
  if Assigned( WebBrowser1 ) then
  begin
    iDocument := htmlDoc; //( WebBrowser1.Document as IHTMLDocument2 );
    if Assigned( iDocument ) then
    begin
      if DesignMode1.Checked then
        iDocument.DesignMode := 'On'
      else
        iDocument.DesignMode := 'Off';
      WebBrowser1.Refresh2;
    end;
  end;
end;

procedure TForm1.Document_OnMouseOver;
var
  element: IHTMLElement;
begin
  if htmlDoc = nil then
    Exit;

  element := htmlDoc.parentWindow.event.srcElement;

  elementInfo.Clear;

  if LowerCase( element.tagName ) = 'a' then
  begin
    elementInfo.Lines.Add( 'LINK info...' );
    elementInfo.Lines.Add( Format( 'HREF : %s', [ element.getAttribute( 'href', 0 ) ] ) );
  end
  else if LowerCase( element.tagName ) = 'img' then
  begin
    elementInfo.Lines.Add( 'IMAGE info...' );
    elementInfo.Lines.Add( Format( 'SRC : %s', [ element.getAttribute( 'src', 0 ) ] ) );
  end
  else
  begin
    elementInfo.Lines.Add( Format( 'TAG : %s', [ element.tagName ] ) );
  end;
end; (* Document_OnMouseOver *)

procedure TForm1.FormCreate( Sender: TObject );
begin
  WebBrowser1.Navigate( 'http://delphi.about.com' );
  elementInfo.Clear;
  elementInfo.Lines.Add( 'Move your mouse over the document...' );
end; (* FormCreate *)

procedure TForm1.WebBrowser1BeforeNavigate2( ASender: TObject; const pDisp: IDispatch;
  var URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool );
begin
  htmlDoc := nil;
end; (* WebBrowser1BeforeNavigate2 *)

procedure TForm1.WebBrowser1DocumentComplete( ASender: TObject; const pDisp: IDispatch; var URL: OleVariant );

begin
  if Assigned( WebBrowser1.Document ) then
  begin
    htmlDoc := WebBrowser1.Document as IHTMLDocument2;
    htmlDoc.onmouseover := ( TEventObject.Create( Document_OnMouseOver ) as IDispatch );
  end;
end; (* WebBrowser1DocumentComplete *)

{ TEventObject }

constructor TEventObject.Create( const OnEvent: TObjectProcedure );
begin
  inherited Create;
  FOnEvent := OnEvent;
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 ( DispID = DISPID_VALUE ) then
  begin
    if Assigned( FOnEvent ) then
      FOnEvent;
    Result := S_OK;
  end
  else
    Result := E_NOTIMPL;
end;

end.

[Fix]
I figured out that WebBrowser1DocumentComplete was not executed after setting webbrowser to designmode so I changed DesignMode1Click and it fixed the problem. I post this so others may see this as well:

procedure TForm1.DesignMode1Click( Sender: TObject );
begin
  // the following is unsafe because you may click on the
  // check box even if you don't have any page navigated
  -- htmlDoc := WebBrowser1.Document as IHTMLDocument2;

  // htmlDoc will be assigned from the OnDocumentComplete
  // fired by Navigate procedure
  if Assigned( htmlDoc ) then
  begin
    if DesignMode1.Checked then
      htmlDoc.DesignMode := 'On'
    else
      htmlDoc.DesignMode := 'Off';

    // switching to design mode takes some time and if there 
    // are some pages which doesn't fire OnDocumentComplete 
    // event when you are switching to design mode, like
    // http://delphi.about.com do, then I would wait for 
    // web browser to be ready
    while WebBrowser1.ReadyState < READYSTATE_COMPLETE do
      Application.ProcessMessages;

    // release the previous "document instance"
    htmlDoc := nil;
    // assign the new one and attach the event
    htmlDoc := WebBrowser1.Document as IHTMLDocument2;
    htmlDoc.OnMouseOver := ( TEventObject.Create( Document_OnMouseOver ) as IDispatch );
  end;
end;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文