首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi TWebBrowser 程式設計完全指南:核心技巧與常見問題解決

     編輯:Delphi

從 Delphi 3 開始引入 TWebBrowser 元件,早期以 ActiveX 控制項形式出現,需手動匯入;到了 Delphi 4.0 和 5.0,它已封裝完 shdocvw.dll,直接出現在「Internet」元件面板中,使用更為便捷。然而,許多開發者吐槽 Delphi 的幫助文件不夠完善,加上 TWebBrowser 本質上是 Microsoft 的技術,MSDN 雖資料龐大卻缺乏明確入口,查找起來往往讓人感到「非常複雜、複雜非常」。本文整理了實戰經驗與網路收集的範例,旨在為有意深入 TWebBrowser 開發的朋友提供實用參考。

一、初始化與終止化:解決 OLE 錯誤的關鍵

在呼叫 ExecWB 等方法時,常遇到「嘗試啟動未註冊的丟失目標」或「OLE 物件未註冊」錯誤,或是操作無效果(如無法複製網頁內容到剪貼簿)。這通常是因為 TWebBrowser 是嵌入式 OLE 物件,而非純 VCL 控制項,必須正確初始化與終止化 OLE 環境。

解決方法:在專案檔(.dpr)的 initialization 與 finalization 區塊加入以下程式碼:

initialization
  OleInitialize(nil);
finalization
  try
    OleUninitialize;
  except
  end;

放置於主視窗所有程式碼之後、end. 之前。這能有效避免 OLE 相關錯誤,確保元件正常運作。

二、善用 EmptyParam 簡化 Navigate 呼叫

Delphi 5 中 Navigate 方法多重載,後幾個參數皆為 var OleVariant,傳統寫法需宣告暫存變數:

var t: OleVariant;
begin
  WebBrowser1.Navigate(Edit1.Text, t, t, t, t);
end;

實際上可直接使用系統內建的 EmptyParam(一個公用的 Variant 空變數,勿賦值):

WebBrowser1.Navigate(Edit1.Text, EmptyParam, EmptyParam, EmptyParam, EmptyParam);

雖程式碼稍長,但免去每次宣告變數的麻煩。若僅需基本導航,直接呼叫 WebBrowser1.Navigate(Edit1.Text) 即可。

三、常用命令操作:ExecWB 與 QueryStatusWB 實戰

ExecWB 同樣多重載,透過 OLECMDID 執行各種瀏覽器命令:

  • 開啟對話框:ExecWB(OLECMDID_OPEN, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);(IE5.0 不支援)
  • 另存新檔:ExecWB(OLECMDID_SAVEAS, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);
  • 列印、預覽、頁面設定:
    ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);
    if QueryStatusWB(OLECMDID_PRINTPREVIEW) = 3 then
      ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);
    ExecWB(OLECMDID_PAGESETUP, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);
    
  • 剪貼簿操作(剪下、複製、貼上、全選):這些命令不僅對編輯框有效,對網頁非編輯區文字同樣生效。判斷命令是否可用有兩種方式:
    // 方式 A:使用 TWebBrowser 的 QueryStatusWB
    if (QueryStatusWB(OLECMDID_COPY) = OLECMDF_ENABLED) or (OLECMDF_SUPPORTED) then
      ExecWB(OLECMDID_COPY, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);
    
    // 方式 B:使用 IHTMLDocument2 的 QueryCommandEnabled
    var Doc: IHTMLDocument2;
    begin
      Doc := WebBrowser1.Document as IHTMLDocument2;
      if Doc.QueryCommandEnabled('Copy') then
        Doc.ExecCommand('Copy', False, EmptyParam);
    end;
    

四、字體大小控制:讀取與設定縮放等級

對應 IE「檢視」→「文字大小」的五個等級(0~4 對應最小~最大):

讀取目前縮放等級:

var t: OleVariant;
begin
  WebBrowser1.ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, EmptyParam, t);
  case t of
    4: Largest.Checked := True;
    3: Larger.Checked := True;
    2: Middle.Checked := True;
    1: Small.Checked := True;
    0: Smallest.Checked := True;
  end;
end;

設定縮放等級:

Largest.Checked := False; Larger.Checked := False; Middle.Checked := False;
Small.Checked := False; Smallest.Checked := False;
TMenuItem(Sender).Checked := True;
t := TMenuItem(Sender).Tag; // 0~4
WebBrowser1.ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, t, t);

五、收藏夾操作:新增與整理

使用 IShellUIHelper 介面新增收藏夾簡單但非模態視窗;若需模態效果,可直接呼叫 shdocvw.dll 的 DoAddToFavDlg。以下提供完整實作:

procedure TForm1.AddFavorite(IE: TEmbeddedWB);
procedure CreateUrl(AUrlPath, AUrl: PChar);
var URLfile: TIniFile;
begin
  URLfile := TIniFile.Create(String(AUrlPath));
  URLfile.WriteString('InternetShortcut', 'URL', String(AUrl));
  URLfile.Free;
end;
var
  AddFav: function(Handle: THandle; UrlPath: PChar; UrlPathSize: Cardinal;
    Title: PChar; TitleSize: Cardinal; FavIDLIST: PItemIDList): Bool; stdcall;
  FDoc: IHTMLDocument2;
  UrlPath, url, title: array[0..MAX_PATH] of Char;
  H: HWnd; pidl: PItemIDList; FRetOK: Bool;
begin
  FDoc := IHTMLDocument2(IE.Document);
  if FDoc = nil then Exit;
  StrPCopy(Title, FDoc.Get_title);
  StrPCopy(url, FDoc.Get_url);
  if url <> '' then begin
    H := LoadLibrary('shdocvw.dll');
    if H <> 0 then begin
      SHGetSpecialFolderLocation(0, CSIDL_FAVORITES, pidl);
      AddFav := GetProcAddress(H, 'DoAddToFavDlg');
      if Assigned(AddFav) then
        FRetOK := AddFav(Handle, UrlPath, SizeOf(UrlPath), Title, SizeOf(Title), pidl);
    end;
    FreeLibrary(H);
    if FRetOK then CreateUrl(UrlPath, url);
  end;
end;

整理收藏夾則直接使用 DoOrganizeFavDlg,可指定父視窗句柄實現模態。

六、讓 WebBrowser 取得焦點

TWebBrowser 繼承自 TWinControl 的 SetFocus 無法使內含文件取得焦點,導致快捷鍵失效。解決方法:

procedure TForm1.SetFocusToDoc;
begin
  if WebBrowser1.Document <> nil then
    with WebBrowser1.Application as IOleObject do
      DoVerb(OLEIVERB_UIACTIVATE, nil, WebBrowser1, 0, Handle, GetClientRect);
end;

更簡單的方式:

if WebBrowser1.Document <> nil then
  IHTMLWindow2(IHTMLDocument2(WebBrowser1.Document).ParentWindow).focus;
// 或最簡單:
if WebBrowser1.Document <> nil then
  IHTMLWindow4(WebBrowser1.Document).focus;

判斷文件是否擁有焦點:if IHTMLWindow4(WebBrowser1.Document).hasfocus then ...

七、處理網頁表單的「提交」按鈕

TWebBrowser 不響應 Enter 鍵觸發 Submit 按鈕,且表單 KeyPreview 也捕捉不到按鍵。解決方案:

  1. 使用 SendKeys 發送 Enter 鍵:Delphi 5 光碟 Info\Extras\SendKeys\SndKey32.pas 提供 SendKeys 函數,在文件取得焦點時呼叫 SendKeys('~', True); 即可模擬 Enter。
  2. 在 Application.OnMessage 中轉發鍵盤訊息:參考 EmbeddedWB.pas 實作,攔截 WM_KEYDOWN 等訊息並透過 IOleInPlaceActiveObject.TranslateAccelerator 轉發給瀏覽器。

八、快速取得網頁原始碼與純文字

無需複雜的 IPersistStreamInit 流操作,直接使用 DOM 介面:

// 取得完整 HTML 原始碼(含標籤)
Memo1.Lines.Add(IHTMLDocument2(WebBrowser1.Document).Body.OuterHtml);
// 取得純文字內容(已解析標籤)
Memo1.Lines.Add(IHTMLDocument2(WebBrowser1.Document).Body.OuterText);

九、實作自訂「查找」功能

程式化調用查找對話框:IOleCommandTarget.Exec(OLECMDID_FIND)。若要自行設計查找介面,可操作 IHTMLTxtRange:

var Doc: IHTMLDocument2; TxtRange: IHTMLTxtRange;
begin
  Doc := WebBrowser1.Document as IHTMLDocument2;
  Doc.SelectAll; // 先建立選取範圍
  TxtRange := Doc.Selection.CreateRange as IHTMLTxtRange;
  TxtRange.FindText('搜尋文字', 0, 0);
  TxtRange.Select;
end;

可透過 TxtRange.Get_text 取得目前選取文字。

十、提取網頁所有連結

var doc: IHTMLDocument2; all: IHTMLElementCollection; len, i: Integer; item: OleVariant;
begin
  doc := WebBrowser1.Document as IHTMLDocument2;
  all := doc.Get_links; // 或 doc.Links
  len := all.Length;
  for i := 0 to len - 1 do begin
    item := all.Item(i, EmptyParam);
    Memo1.Lines.Add(item.href);
  end;
end;

十一、動態設定網頁編碼

極簡實作:

procedure SetCharSet(AWebBrowser: TWebBrowser; ACharSet: String);
var RefreshLevel: OleVariant;
begin
  IHTMLDocument2(AWebBrowser.Document).Set_CharSet(ACharSet);
  RefreshLevel := 7; // 註冊表值,說明文件有誤
  AWebBrowser.Refresh2(RefreshLevel);
end;
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved