TEdgeBrowser(WebView2)でタブブラウザを作る
Delphi 12.1でTEdgeBrowser(WebView2)を使い、複数タブを持つWebブラウザを構築する方法を紹介します。
ユーザーがリンクをクリックした際に「新しいウィンドウで開く」イベントを検出し、別タブで表示する処理を中心に、タブの追加・削除、ページタイトルの取得、ナビゲーション制御(戻る・進む・更新)、UserAgentの設定、キャッシュ管理など、実用的な機能をサンプルコード付きで解説しています。
WebView2Loader.dllの配置方法や、Delphi環境での構築手順も網羅しています。
(1)はじめに
Windows10の場合はMicrosoft WebView2 ランタイムのインストールを以下のURLを参照してインストールしてください。
https://mam-mam.net/delphi/tedgebrowser.html
「WebView2Loader.dll」は
https://mam-mam.net/delphi/tedgebrowser.html
を参照してください。
(2)プロジェクトの作成とフォームの設計
Delphi IDEを起動し、「ファイル」⇒「Windows VCLアプリケーション -Delphi」をクリックします
フォームに TPanel × 1個をドラッグ&ドロップで配置し、その上(Panel1の中)に TButton 1個をドラッグ&ドロップで配置します。
TPageControl × 1個 をドラッグ&ドロップで配置します。
(3)ソースコードの記述
IDEを「コード」に切り替えて、以下ソースコードをコピー&ペーストします。
IDEを「デザイン」に切り替えてオブジェクトインスペクタのイベントプロパティに、
Form1.OnCreate に FormCreate を設定
Button1.OnClick に Button1Click を設定します。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.ExtCtrls,
Winapi.WebView2, Winapi.ActiveX, Vcl.Edge, Vcl.StdCtrls{, Vcl.StdCtrls};
type
TForm1 = class(TForm)
PageControl1: TPageControl;
Panel1: TPanel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
CacheDir:String;
procedure CreateNewTab(url:string='');
procedure UrlKeyPress(Sender: TObject; var Key: Char);
procedure BackButton(Sender: TObject);
procedure ForwardButton(Sender: TObject);
procedure RefreshButton(Sender: TObject);
procedure NavigationStarting(Sender: TCustomEdgeBrowser;
Args: TNavigationStartingEventArgs);
procedure NewWindowRequested(Sender: TCustomEdgeBrowser;
Args: TNewWindowRequestedEventArgs);
procedure DocumentTitleChanged(Sender: TCustomEdgeBrowser;
const ADocumentTitle: string);
procedure PageControlMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure DeleteTag(idx:Integer);
public
{ Public 宣言 }
end;
var
Form1: TForm1;
const
UserAgent:String=
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '+
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.6998.36 Safari/537.36';
implementation
{$R *.dfm}
uses System.IOUtils;
{ TForm1 }
procedure TForm1.BackButton(Sender: TObject);
var w:TEdgeBrowser;
begin
w:=TEdgeBrowser(TTabSheet(TButton(Sender).parent.parent).Controls[2]);
if w.CanGoBack then w.GoBack;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateNewTab();
end;
procedure TForm1.CreateNewTab(url:string='');
var ts:TTabSheet;
p:TPanel;
e:TEdit;
b:TButton;
w:TEdgeBrowser;
begin
ts:=TTabSheet.Create(self);
ts.PageControl:=PageControl1;
PageControl1.TabIndex:=PageControl1.PageCount-1;
p:=TPanel.Create(self);
p.Parent:=ts;
p.Align:=alTop;
p.Height:=50;
e:=TEdit.Create(self);
e.Parent:=p;
e.OnKeyPress:=UrlKeyPress;
e.Align:=alTop;
if url<>'' then e.Text:=url;
p:=TPanel.Create(self);
p.Parent:=ts;
p.Height:=50;
p.Top:=51;
p.Align:=alTop;
b:=TButton.Create(self);
b.Parent:=p;
b.Caption:='←';
b.Width:=40;
b.Align:=alLeft;
b.OnClick:=BackButton;
b:=TButton.Create(self);
b.Parent:=p;
b.Caption:='→';
b.Width:=40;
b.Left:=41;
b.Align:=alLeft;
b.OnClick:=ForwardButton;
b:=TButton.Create(self);
b.Parent:=p;
b.Caption:='Refresh';
b.Width:=100;
b.Left:=81;
b.Align:=alLeft;
b.OnClick:=RefreshButton;
w:=TEdgeBrowser.Create(self);
w.Align:=alCLient;
w.Parent:=ts;
w.UserDataFolder:=CacheDir;
w.OnDocumentTitleChanged:=DocumentTitleChanged;
//WebViewが(非同期で)作成されるまで待つ
if not w.WebViewCreated then
begin
w.CreateWebView;
while not w.WebViewCreated do
begin
Application.ProcessMessages;
Sleep(100);
end;
end;
ICoreWebView2Settings2(w.SettingsInterface).Set_UserAgent(
PWideChar(@UserAgent[1])
);
w.OnNavigationStarting:=NavigationStarting;
w.OnNewWindowRequested:=NewWindowRequested;
if url='' then
w.Navigate('https://www.google.co.jp')
else
w.Navigate(url);
end;
procedure TForm1.DeleteTag(idx: Integer);
var tb:TTabSheet;
begin
tb:=PageControl1.Pages[idx];
tb.controls[2].Free;
TPanel(tb.controls[1]).controls[2].Free;
TPanel(tb.controls[1]).controls[1].Free;
TPanel(tb.controls[1]).controls[0].Free;
tb.controls[1].Free;
TPanel(tb.controls[0]).controls[0].Free;
tb.controls[0].Free;
tb.Free;
end;
procedure TForm1.DocumentTitleChanged(Sender: TCustomEdgeBrowser;
const ADocumentTitle: string);
begin
TTabSheet(TEdgeBrowser(Sender).Parent).Caption:=
Chr(9746)+ADocumentTitle.Substring(0,10);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
//ブラウザキャッシュのディレクトリ
CacheDir:=ExtractFilePath(Application.ExeName)+'cache';
//必要であればブラウザキャッシュを削除
if DirectoryExists(CacheDir) then
TDirectory.Delete(CacheDir, True);
PageControl1.OnMouseDown:=PageControlMouseDown;
Button1.Align:=alLeft;
Button1.Font.Height:=-20;
Button1.Width:=128;
Panel1.Caption:='';
Panel1.Height:=64;
Panel1.Align:=alTop;
Button1.Caption:='タブを追加';
PageControl1.Align:=alClient;
CreateNewTab();
self.Font.Size:=12;
end;
procedure TForm1.ForwardButton(Sender: TObject);
var w:TEdgeBrowser;
begin
w:=TEdgeBrowser(TTabSheet(TButton(Sender).parent.parent).Controls[2]);
if w.CanGoForward then w.GoForward;
end;
procedure TForm1.NavigationStarting(Sender: TCustomEdgeBrowser;
Args: TNavigationStartingEventArgs);
var puri:PChar;
uri:String;
begin
Args.ArgsInterface.Get_uri(puri);
uri:=puri;
TEdit(TPanel(TTabSheet(TEdgeBrowser(Sender).Parent).Controls[0]).Controls[0]).Text
:=uri;
uri:=StringReplace(uri,'http://','',[]);
uri:=StringReplace(uri,'https://','',[]);
TTabSheet(TEdgeBrowser(Sender).Parent).Caption:=Chr(9746)+uri.substring(0,10);
end;
procedure TForm1.NewWindowRequested(Sender: TCustomEdgeBrowser;
Args: TNewWindowRequestedEventArgs);
var puri:PChar;
begin
Args.ArgsInterface.Set_Handled(-1);
Args.ArgsInterface.Get_uri(puri);
TThread.CreateAnonymousThread(
procedure
begin
TThread.Synchronize(nil,
procedure
begin
CreateNewTab(puri);
end);
end).Start;
end;
procedure TForm1.PageControlMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
TabIndex: Integer;
TabCaption: string;
ClickedCharIndex: Integer;
TextWidth, TextStart, i: Integer;
TabRect: TRect;
begin
// クリック位置からタブのインデックスを取得
TabIndex := PageControl1.IndexOfTabAt(X, Y);
if TabIndex <> -1 then
begin
TabCaption := PageControl1.Pages[TabIndex].Caption;
// タブの矩形を取得
TabRect := PageControl1.TabRect(TabIndex);
// テキストの幅と開始位置を計算(中央揃えの場合)
TextWidth := PageControl1.Canvas.TextWidth(TabCaption);
TextStart := TabRect.Left + (TabRect.Width - TextWidth) div 2;
// クリック位置から文字インデックスを計算
ClickedCharIndex := -1;
for i := 1 to Length(TabCaption) do
begin
if X <= TextStart + PageControl1.Canvas.TextWidth(Copy(TabCaption, 1, i)) then
begin
ClickedCharIndex := i;
Break;
end;
end;
if ClickedCharIndex <> -1 then
begin
if TabCaption[ClickedCharIndex]=Chr(9746) then
DeleteTag(TabIndex);
end;
end;
end;
procedure TForm1.RefreshButton(Sender: TObject);
var w:TEdgeBrowser;
begin
w:=TEdgeBrowser(TTabSheet(TButton(Sender).parent.parent).Controls[2]);
w.Refresh;
end;
procedure TForm1.UrlKeyPress(Sender: TObject; var Key: Char);
var w:TEdgeBrowser;
begin
if Key=#13 then
begin
w:=TEdgeBrowser(TTabSheet(TEdit(Sender).parent.parent).Controls[2]);
w.Navigate(TEdit(Sender).Text);
end;
end;
end.
(4)「WebView2Loader.dll」ファイルを実行ファイルと同じフォルダ内にコピーする
「ファイル」⇒「すべて保存」でプロジェクトフォルダを作成して、ユニットとプロジェクトファイルを保存します。
「C:\Program Files (x86)\Embarcadero\Studio\23.0\Redist\win32\WebView2Loader.dll」
「C:\Program Files (x86)\Embarcadero\Studio\23.0\Redist\win64\WebView2Loader.dll」
ファイルを、実行ファイルと同じフォルダ内(プロジェクト保存フォルダ\Win32\Debug)にコピーします
| (A)「Debug」ビルトで 「Windows 32ビット」 |
プロジェクト保存フォルダ\Win32\Debug |
| (B)「Debug」ビルトで 「Windows 64ビット」 |
プロジェクト保存フォルダ\Win64\Debug |
| (C)「Release」ビルトで 「Windows 32ビット」 |
プロジェクト保存フォルダ\Win32\Release |
| (D)「Release」ビルトで 「Windows 64ビット」 |
プロジェクト保存フォルダ\Win64\Release |
(5)実行する
IDEから「実行」⇒「実行」をクリックしてコンパイル&実行します。
「タブを追加」ボタンをクリックするとタブが増えます。
☒ を押すとタブが削除されます。
<a href="***" target="_blank">をクリックした場合は新しいタブが生成されて表示されます。
リンクを右クリックして「リンクを新しいウィンドウで開く」を押した場合も新しいタブが生成されて表示されます。
