HTMLブラウザをFormの代替に


ジョナさん  2006-01-16 06:02:26  No: 19646

思いつきなのですが、
・InternetExplolerでローカルのhtmlファイルを表示し、
・そのhtml上のリンクとかボタンをクリックして、
・Delphiでクリックイベントにうまくリンクさせて動作させる
つまり、Formの設計をIEで代替するような事はできないでしょうか?

※そんなん簡単やろ!などと言わず道筋をお教え願えませんでしょうか。
よろしくお願いします。


にしの  2006-01-16 10:41:20  No: 19647

何をやらせたいのかによって、CGIなのか、ActiveXコントロールなのか、別の手段が必要(たとえばプロトコルの実装)なのかが違います。
いずれにしても、HTMLブラウザのクリックなどでDelphiプログラムが(クライアント上で)動く、としたら、セキュリティに関しても考慮すべきです。


もちKiri  2006-01-17 02:27:06  No: 19648

>Delphiでクリックイベントにうまくリンクさせて動作させる
こういうことでしょうか?↓

{
参考:
TEventDelegator
http://www.effie.co.il/default.asp?sec=printview&topic=delphiasp&lang=he

Bubble Power: Internet Explorer 4.0 におけるイベント処理
http://www.microsoft.com/japan/msdn/web/ie/ie40/ie4event.asp

Handling Events in Visual Basic Applications
http://msdn.microsoft.com/workshop/browser/webbrowser/tutorials/forward.asp

TieAutomationコンポーネント
http://www33.ocn.ne.jp/~takoyakusi/delphi/InternetProg.html
}

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ieAutomation, SHDocVw_TLB, MSHTML_TLB;

//-----------------------------------------------------------------------------

type
  TCallbackMethod = procedure of object;
  
  TEventDelegator = class(TInterfacedObject, IDispatch)
  private
    FOwner : TObject;
    FCallback: TCallbackMethod;
  protected
    { IDispatch }
    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(AOwner:TObject; Callback :TCallbackMethod);
  end;

//-----------------------------------------------------------------------------

type
  TForm1 = class(TForm)
    ieAuto: TieAutomation;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure ieAutoDocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ieAutoQuit(Sender: TObject);
  private
    { Private 宣言 }
    procedure IE_AttachEvevt;
    procedure Some_Procedure1;
    procedure Some_Procedure2;
    procedure Some_Procedure3;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//-----------------------------------------------------------------------------

constructor TEventDelegator.Create(AOwner:TObject; Callback:TCallbackMethod);
begin
  inherited Create;
  FOwner := AOwner;
  FCallback := Callback;
end;

function TEventDelegator.GetTypeInfoCount(out Count: Integer): HRESULT;
begin
// Skeleton implementation
  Count  := 0;
  Result := S_OK;
end;

function TEventDelegator.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HRESULT;
begin
// Skeleton implementation
  Result := E_NOTIMPL;
end;

function TEventDelegator.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT;
begin
// Skeleton implementation
  Result := E_NOTIMPL;
end;

function TEventDelegator.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT;
begin
  try
    FCallback;
  except
  end;
  Result := S_OK;
end;

//-----------------------------------------------------------------------------

procedure TForm1.Some_Procedure1;
var
  oDoc2: IHTMLDocument2;
  oWindow: IHTMLWindow2;
  oEle: IHTMLElement;
begin
  Windows.Beep(3000, 100);
  Button1.Caption := 'Some_Procedure1 was called.';
  oDoc2 := ieAuto.ieObject.Document as IHTMLDocument2;
  oWindow := oDoc2.parentWindow;
  oEle := oWindow.event.srcElement;
  oEle.innerText := 'Some_Procedure1 was called.';
end;

procedure TForm1.Some_Procedure2;
var
  oDoc: IHTMLDocument2;
  oWindow: IHTMLWindow2;
  oEle: IHTMLElement;
begin
  oDoc := ieAuto.ieObject.Document as IHTMLDocument2;
  oWindow := oDoc.parentWindow;
  oEle := oWindow.event.srcElement;
  oEle.style.backgroundColor := 'Gray';
end;

procedure TForm1.Some_Procedure3;
var
  oDoc: IHTMLDocument2;
  oWindow: IHTMLWindow2;
  oEle: IHTMLElement;
begin
  oDoc := ieAuto.ieObject.Document as IHTMLDocument2;
  oWindow := oDoc.parentWindow;
  oEle := oWindow.event.srcElement;
  oEle.style.backgroundColor := '';
end;

//-----------------------------------------------------------------------------

// ブラウザオープン
procedure TForm1.Button1Click(Sender: TObject);
begin
  ieAuto.IeOpen;
end;

procedure TForm1.ieAutoDocumentComplete(Sender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
var
  oDoc: IHTMLDocument2;
  sHTML: WideString;
begin
  // 適当なHTML
  // ID,Name などで識別できるようにしておく
  sHTML := '<P>This is some text.</P>';
  sHTML := sHTML + '<P>And here is a button.</P>';
  sHTML := sHTML + '<BUTTON ID="btnMyButton">Click this Button.</BUTTON>';

  oDoc := ieAuto.ieObject.Document as IHTMLDocument2; 
  oDoc.body.innerHTML := sHTML;

  IE_AttachEvevt;
end;

// イベント実装
procedure TForm1.IE_AttachEvevt;
var
  oDoc: IHTMLDocument3;
  oEle: IHTMLElement2;
  oEvent: IDispatch;
begin
  if not Assigned(ieAuto.ieObject) then Exit;

  oDoc := ieAuto.ieObject.Document as IHTMLDocument3;

  // ID で識別
  oEle := oDoc.getElementById('btnMyButton') as IHTMLElement2;
  oEvent := TEventDelegator.Create(Form1, Some_Procedure1);
  oEle.attachEvent('onclick', oEvent);

  // Document すべてに(イベント バブリング)
  oEvent := TEventDelegator.Create(Form1, Some_Procedure2);
  oDoc.attachEvent('onmouseover', oEvent);

  oEvent := TEventDelegator.Create(Form1, Some_Procedure3);
  oDoc.attachEvent('onmouseout', oEvent);

  {onclick, ondblclick,
  onmousedown, onmouseup,
  onmouseover, onmouseout,
  onmousemove,
  onkeydown, onkeyup,
  onkeypress
  ...などなど}
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // フォームを表示しない
  Application.ShowMainForm := False;
  Button1Click(Sender);
end;

// ブラウザとフォームの終了を連動
procedure TForm1.FormDestroy(Sender: TObject);
begin
  ieAuto.IeClose;
end;

procedure TForm1.ieAutoQuit(Sender: TObject);
begin
  Application.Terminate;
end;

end.


ジョナさん  2006-01-17 04:19:12  No: 19649

早速の返答ありがとうございます。にしのさん、もちKiri さん
目的はFormの設計の簡略化です。CGIなどは私の手には余ると思います。

ところで、上記のサンプルコードを試そうとTieAutomationコンポーネントをインストールしようと四苦八苦しています。
(Microsoft Internet ControlsとMicrosoft HTML Object Libraryは取り込みました)

コンパイルの時点でunassignedが未定義の識別子  と言って怒られます。
何が悪いのでしょうか・・・すみませんがもう少し教えてください。よろしくお願いします。


ジョナさん  2006-01-17 04:23:01  No: 19650

uses節にVariantsを追加したらインストールできました。
Helpは見るものです・・・・
それではこれから試したいと思います。


ジョナさん  2006-01-17 04:39:56  No: 19651

惨敗です。
ieAuto.IeOpen  でIEが立ち上がりません。
というか立ち上がると思っているのが間違いなのでしょうか・・
私のやりたい事にすごく近い気がするのですが・・・・


えーと  2006-01-17 05:33:04  No: 19652

> 目的はFormの設計の簡略化です。

Delphi より簡単に Form を設計するって、あり得ないと思うんですが。


HOta  2006-01-17 07:37:22  No: 19653

簡単そうに見えるのは、Delphi.NETでWeb.NETを使うというものでしょうか?(実はすごく。。。。。。)


ジョナさん  2006-01-17 18:44:13  No: 19654

>Delphi より簡単に Form を設計するって、あり得ないと思うんですが。

「用意されたコンポーネントを配置してそれなりのものを作る」場合には、簡便さはDelphiの統合開発環境が勝ります。

しかし、見栄えのよいウインドウを作る  という命題の前にはどうでしょうか?
勿論Delphi は総合プログラミング環境ですから、凡そ欲することのほとんどの事が可能(なはず)ですが、用意されたコンポーネント以上のことをしようとすると、極端に難易度があがりませんか?(え?そうでもない?)

今現在、HTMLは参考ソースが最も多く、しかも「見栄え」に拘ったものが何百万も存在しますし、保守性もよいです。

それを流用できないかなぁと思っているのですが。
(いまだにTieAutomation使えていません。エラソーなことを語るには素人です。すみません)


ジョナさん  2006-01-17 19:02:03  No: 19655

スレ汚しすみません。
上記サンプル、やっと動かせました!!!

ieAutoDocumentCompleteイベントをアタッチできておりませんでした。
あと、visibleプロパティもtrueにしないといけません。

ありがとうございます。いろいろ試行してみます。


にしの  2006-01-17 19:35:21  No: 19656

HTMLは見栄えはよいですが、UIとして考えるとやはり足りない部分がでてきます。
HTMLの中で使えるコンポーネントと、Delphiのコンポーネントを比べても、Delphiのほうが豊富で、カスタマイズも出来ます。
Webシステムなどを作ってみると、いかにHTMLで出来ることが少ないか(実現することが難しいか)がわかるかと思います。
例えば、
Web)ウィンドウの形を変えられない
Delphi)リージョンを使用してウィンドウの形を任意に変えられる

Web)フローティングレイヤーの下にSELECTタグがあるとSELECTタグのほうが上に表示されてしまう。また、フローティングレイヤーはウィンドウの外に出られない。
Delphi)フローティングウィンドウは、全てのコンポーネントの上に表示できるし、ウィンドウの外に出ることもできる。

リージョンを使用する場面は少ないと思いますが、入力系でコンボボックスがあり、その上にレイヤーを表示することなどは多々あるかと思います。
# 例えば、
発送希望日[INPUT TYPE="text"][Button]<-ボタンを押してカレンダー(レイヤー)表示
宛先:都道府県[北海道▼]<-ここはコンボボックス
宛先:住所[INPUT TYPE="text]
こんな感じの入力系で、カレンダーを表示するとレイヤーの上に[北海道▼]が重なって表示されます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加