日本Delphi振興会 | Delphiはじめて物語 | Delphiつれづれ記 | Delphiリンク互助会 | Delphiアクセサリ |
Delphi壁の穴
その一:Delphiを覗く
ここではDelphiを使うときに問題になる事柄やコーディングのTIPSをご紹介します。
目次
ア)\Delphi 2.0\Binに、「_appdiet.exe」がない。
キー: HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Delphi\2.0
自分でレジストリをいじりたくない方は、Setupプログラムソース(2KB)をダウンロードして下さい。
あなたの使っているDelphiのバージョンは、2.01にアップデートされています。上記ア)-3を実行して下さい。
より詳しくは「WinHelp」をキーワードにしてDelphiヘルプで探して下さい。
常駐させているときは、フォームとタスクバーを表示させないのが普通なので、その方法を以下に示します。
Delphi2では立ち上げたときに一瞬タスクバーが見えてしまいますが、Delphi3では改善されて見えなくなりました。
この関数を応用すれば、文字をいろいろと変換できます。以下の例は、全角カタカナをひらがなにします。
使えるフォント名は、Screen.Fontで得ることが出来ます。フォントサイズはあらかじめItemsプロパティに入れておいてください。
次に、private宣言のところに
最後に、Memo1のOnKeyDown/OnKeyUp/OnMouseDown/OnMemoChangeの各イベントハンドラに GetLinePos を書きます。例えば、
OnKeyDownはキーを連続して押したときに、OnKeyUpはキーを一回押したときに、OnMouseDownはマウスでMemoのカーソルを動かしたときに、OnMemoChangeはファイルを読み込んだときに、それぞれ発生して行数と列数を表示します。
※ちなみに、Undoさせた後、もう一度UndoさせるとRedoになります。
ダイアログが出ると思います。実行ファイルのサイズもとても小さくなっています。
調子が悪い場合はnilの代わりに「Self」を使ってみてください。
<使用例>
SetLinkでネスケのバージョンに注意して下さい。とりあえず'NSShell'を試して、だめだったら'Netscape'を試せばよいでしょう。
上記の全ソース(findfile.lzh)を置いておきますので、使って下さい(Delphi3で作成)。
あまりにも簡単に出来たので作った本人も驚いてしまいました。つまり、ActiveXもDelphiにかかればただのコンポーネントと同じ、普通のクラスと同様に扱えると言うことです。だからわざわざF1Bookをフォームに乗せなくとも、プロジェクトファイル内でCreateすることが可能なわけですね。
<配布方法>
Fomula Oneについては、販売元サイトにより詳しく載っています。
Delphi壁の穴
システムを覗く
レジストリを覗く
アプリケーションを覗く
一番上へ
・おすすめヘルプ
DelphiのCD-ROMには役に立つヘルプが入っています。使ってみて下さい。
Delphi2のAPIヘルプは、あろう事か英語で書かれています。これはBorlandが悪いのではなく、Microsoftが日本語化しなかったためです。Api32wh.hlpは、WinNT/Win32用のヘルプですが、Win95と共通する部分が多くあって、しかも日本語で書かれています。
英語ですが、Borlandに寄せられた質問とその回答集です。結構たくさんの質問があるので、ひとつぐらいは「お、これは!」と思えるようなものもあるでしょう。
Delphi3のAPIヘルプは、あろう事か英語で書かれています。これはBorlandが悪いのではなく、Microsoftが日本語化しなかったためです。Win32.hlpは、WinNT/Win32用のヘルプですが、Win95と共通する部分が多くあって、しかも日本語で書かれています。また、Delphi2を持っている場合は上記 Api32wh.hlp を同一フォルダに入れておけば、「グループ」ボタンが使えるようになります。
・「アドレス...に対する読み込み違反が起こりました」by Delphi2
Delphi 2.0を終了させたとき、上記のようなエラーが出ることがあります。これは、Internet Explorer3.0をインストールしていると起こります。これを回避する方法は二通りあります。
イ)\Delphi 2.0\Binに、「_appdiet.exe」がある。
これで、Delphiのバージョンは2.01にアップデートされました。
名前:Debug stub
値: "_APPDIET.EXE"
・Delphi3で "Ole2" ユニットを使う
Delphi3でフリーのコンポーネントを使おうとすると "Ole2" ユニットがないと怒られることがあります。Delphi3ではOLEの機能は全て "ActiveX" ユニットへ変わったためです。ではどうするか。実はOle2ユニットは Lib\Delphi2 フォルダの中にあるのですが、ライブラリパスが通っていないためにエラーになってしまったのです。ライブラリパスを通すには、メニューから[ツール-環境オプション-ライブラリ-ライブラリパス]に上記パスを書いておきます。なお、Delphi2のOle2ユニットを流用することは出来ません。
・アプリケーションからヘルプを実行させる
実行ファイル名とヘルプファイル名が同じで、同一の場所にあるならば、
Application.HelpFile:=ChangeFileExt(ParamStr(0),'.hlp');
目次の表示には、Delphi 1.0で、HELP_CONTENTSを使っていましたが、CNTファイルを使うには、HELP_FINDERを使います。
Application.HelpCommand(HELP_FINDER,0);
Application.HelpCommand(HELP_KEY,0);
Application.HelpCommand(HELP_CONTEXT,10004);
第二引数に表示したいページのコンテキスト番号を指定します。
フォームのBorderIconsプロパティで、biMaximizeとbiMinimizeをFalseに、biHelpをTrueにします。
そうしたら、各コンポーネントにあるHelpContextプロパティに、表示したいヘルプのコンテキスト番号を割り当てます。
Application.HelpCommand(HELP_CONTEXTPOPUP,10004);
procedure TForm1.FormDestroy(Sender: TObject);
begin
Application.HelpCommand(HELP_QUIT,0);
end;
・タスクトレイに常駐させるときフォームとタスクバーを表示させない。
タスクトレイにアイコンを描画するコンポーネントを手に入れるには、
Application.ShowMainForm:=False; {フォーム非表示}
ShowWindow(Application.Handle,SW_HIDE); {タスクバー非表示}
・半角カナを全角カナにしたり、アルファベット小文字を大文字にする。
Delphi 2.0 CD-ROMにあるJstrm.pas(作:村松 真氏)を使います。場所は、Extras\Programs\Jstrmです。ない場合は作者のホームページからダウンロードして下さい。その中にある関数「JUniCase」は、小文字を大文字にそろえる、全角アルファベットや記号,数字を半角にする、半角カタカナを全角カタカナにする、という機能があります。
function ConvKanaHira( const source: string ): string;
var
P: PChar;
i, len: integer;
wc : WORD;
begin
P := PChar( source );
len := length( source );
i := 1;
Result := '';
repeat
{全角文字ならば}
if IsDBCSLeadByte( BYTE( p^ ) ) then begin
wc := ( BYTE(p^) shl 8 ) or Byte( (p + 1)^ );
case wc of
{ァ-ミ --> ぁ-み}
$8340..$837E: Result := Result + #$82+Char(wc-$A1);
{ム-ワ --> む-わ}
$8380..$838F: Result := Result + #$82+Char(wc-$A2);
{ヰ --> うぃ}
$8390: Result := Result + #$82+#$A4+#$82+#$A1;
{ヱ --> うぇ}
$8391: Result := Result + #$82+#$A4+#$82+#$A5;
{ヲ-ン --> を-ん}
$8392..$8393: Result := Result + #$82+Char(wc-$A2);
{ヴ --> う゛}
$8394: Result := Result + #$82+#$A4+#$81+#$8B;
else Result := Result + p^ + (p + 1)^;
end;
Inc( p );
Inc( i );
end
{半角文字}
else begin
Result := Result + p^;
end;
Inc( p );
Inc( i );
until i > len;
end;
{#ENDIF}
・Posを使って大文字と小文字の区別なしに文字列検索。
Posは大文字と小文字を区別して文字列を検索します。大文字と小文字を区別しないで検索させるには、簡単にいえば、大文字を小文字に変えてやればいいのです。以下に作成した関数を示します。
{大文字と小文字の区別なしに文字列検索}
function PosText(SubStr,S:string):integer;
begin
SubStr:=AnsiLowerCase(SubStr);
S:=AnsiLowerCase(S);
Result:=Pos(SubStr,S);
end;
・フォントの種類と大きさをコンボボックスで変える。
ワープロソフトのように、コンボボックスでフォントの種類と大きさを変えられるようにします。例としてフォントの種類の方をcobFontName、大きさをcobFontSizeとし、Memoを使います。
{コンボボックスの初期値}
procedure TForm1.FormCreate(Sender: TObject);
begin
{使えるフォント名をコンボボックスに入れる}
cobFontName.Items:=Screen.Fonts;
{Memo1のフォント情報をコンボボックスに指定する。}
cobFontName.Text:=Memo1.Font.Name;
cobFontSize.Text:=IntToStr(Memo.Font.Size);
end;
{フォント名変更-ドロップダウンリストを使う場合}
procedure TfrmMemo.cobFontNameClick(Sender: TObject);
begin
Memo.Font.Name:=cobFontName.Text;
end;
{フォント名変更-直接フォント名を書く場合}
procedure TfrmMemo.cobFontNameKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
Memo.Font.Name:=cobFontName.Text;
end;
{フォントサイズ変更-ドロップダウンリストを使う場合}
procedure TfrmMemo.cobFontSizeClick(Sender: TObject);
begin
Memo.Font.Size:=StrToInt(cobFontSize.Text);
end;
{フォントサイズ変更-直接フォントサイズを書く場合}
procedure TfrmMemo.cobFontSizeKeyPress(Sender: TObject; var Key: Char);
begin
if key=#13 then
Memo.Font.Size:=StrToInt(cobFontSize.Text);
end;
フォントの指定には、ドロップダウンリストを使う場合とコンボボックスに直接書く場合があるので、イベントも2種類必要です。OnChangeイベントではないことに注意してください。
・Memoで、先頭行/最終行/指定行へ移動する。
Delphi1と2/3で方法が違います。
{先頭行へ}
procedure TForm1.Button1Click(Sender: TObject);
begin
with Memo1 do
begin
{1行目にスクロール}
Perform(WM_VSCROLL,SB_THUMBTRACK,0); {0が一行目を指す}
SelStart:=0; {カーソルを一番先頭に移動}
SetFocus;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
with Memo1 do
begin
LastLine:=Perform(EM_GETLINECOUNT,0,0); {全行数を得る}
Perform(WM_VSCROLL,SB_THUMBTRACK,LastLine-1); {最終行にスクロール}
SelStart:=Perform(EM_LINEINDEX,LastLine-1,0); {カーソルを最終行に移動}
SetFocus;
end;
end;
行の指定にEdit1を使います。
procedure TForm1.Button3Click(Sender: TObject);
var
ToLine:integer;
begin
with Memo1 do
begin
ToLine:=IntToStr(Edit1.Text);
Perform(WM_VSCROLL,SB_THUMBTRACK,ToLine-1); {指定行にスクロール}
SelStart:=Perform(EM_LINEINDEX,ToLine,0); {カーソルを指定行に移動}
SetFocus;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
NowLine:integer;
begin
with Memo1 do
begin
NowLine:=Perform(EM_LINEFROMCHAR,SelStart,0); {カーソルのある行数を得る}
{先頭行へスクロール}
Perform(EM_LINESCROLL,0,-NowLine); {マイナスが重要}
SelStart:=0;
SetFocus;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
NowLine,LastLine:integer;
begin
with Memo do
begin
NowLine:=Perform(EM_LINEFROMCHAR,SelStart,0);
LastLine:=Perform(EM_GETLINECOUNT,0,0);
Perform(EM_LINESCROLL,0,LastLine-NowLine);
SelStart:=Perform(EM_LINEINDEX,LastLine-1,0);
end;
end;
指定行をEdit1で指定します。
procedure TForm1.Button3Click(Sender: TObject);
var
NowLine,ToLine:integer;
begin
with Memo do
begin
NowLine:=Perform(EM_LINEFROMCHAR,SelStart,0);
ToLine:=StrToInt(Edit1.Text);
Perform(EM_LINESCROLL,0,ToLine-NowLine);
SelStart:=Perform(EM_LINEINDEX,ToLine-1,0);
end;
end;
・Memoで、現在行数/列数を得る。
まず、現在行数と列数を計算する手続きを作成し、StatusBar1に表示させるようにします。{行数と列数を計算}
procedure TForm1.GetLinePos;
var
CurPos,Line,LinePos,LineCount:Integer;
begin
with Memo1 do
begin
CurPos:=SelStart;
Line:=Perform(EM_LINEFROMCHAR, CurPos, 0);
LinePos:=Perform(EM_LINEINDEX, Line, 0);
LineCount:=Perform(EM_GETLINECOUNT,0,0);
StatusBar.Panels[0].Text:=Format('%d行%d列目 (全%d行)',
[Line+1,(CurPos-LinePos)+1,LineCount]);
end;
end;
private
{ Private 宣言 }
procedure GetLinePos;
と書き加えます。
procedure TfrmMemo.MemoKeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
GetLinePos;
end;
・Memoで、アンドゥさせる。
WindowsAPIの EM_UNDO を使います。
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo.Perform(EM_UNDO,0,0);
end;
・フォームを使わない小さなアプリケーションを作る。
Delphiは、フォームだけのアプリケーションでも150KB程度の大きさになってしまいますが、フォームを使わなければ、10〜50KB前後にサイズを押さえられます。また、フォームの代わりにダイアログリソースを使う方法がTezzorieAppで紹介されています。
あと、uses節にはWindowsしかありませんが、IntToStrを使いたかったら
SysUtilsを追加する必要がありますし、レジストリ操作にはRegistry,
TStringListにはClasses、SendMessageにはMessagesなど、やりたいこと
によってuses節へ追加してください。ただし、Dialogsを加えてはいけません。サイズが100KBを越えてしまいます。ダイアログはあくまでも MessageBox を使うようにしてください。
program Project1;
uses
Windows;
{$R *.RES}
begin
end.
program Project1;
uses
Windows;
{$R *.RES}
const
Msg='ダイアログが音と一緒に出ます。';
Title='ダイアログの実験'
begin
MessageBox(GetForegroundWindow,PChar(Msg),PChar(Title),MB_OK or MB_ICONINFORMATION);
end.
function Test:integer;
begin
{コード}
end;
procedure Test2;
begin
{コード}
end;
var
Result:integer;
begin
Test2;
Result:=Test;
end.
こんな感じです。また、Test2からTestを呼ぶことは出来ますが、逆にTestからTest2を呼ぶことは出来ません。つまり、下から上は呼び出せるが、上から下は呼び出せません。
・メニューに独自のショートカットを割り当てる。
TextToShortCutを使います。例えば、Menu1に「Ctrl+Shift+A」を割り当てるには
Menu1.ShortCut:=TextToShortCut('Ctrl+Shift+A');
・SetFocusの注意事項。
SetFocusは、あるコンポーネントへフォーカスを当てるときに使いますが、使い方を間違えるとエラーが出ます。
ListBox1.SetForcus;
ListBox1.ItemIndex:=0;
とすれば、一番上の項目が反転表示されます。
・SenderのないprocedureからSenderを持つprocedureを呼ぶ。
自作の手続き(procedure)を作った場合に、そこからButton1Clickなどを呼び出そうとすると、Senderを引数に渡す必要があります( Button1Click(Sender); のように)。
しかし、自作の手続きにわざわざ使う必要のないSender引数を付けるのもスマートではありません。これを回避するには、引数に「nil」を使うとうまくいきます。
(略)
private
{ Private 宣言 }
NoSender;
(略)
{Senderを引数に持つ手続き}
procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.Color:=clRed;
end;
{Senderを引数に持たない自作の手続き}
procedure TForm1.NoSender;
begin
{Button1Clickを呼び出す}
ButtonlClick(nil); {Senderの代わりにnilを引数に渡せばよい}
end;
・2バイトの16進数を10進数に変換する
Delphiには16進数を10進数にする関数「StrToInt」がありますが、これは漢字などの2バイト16進数を変換してくれません。というわけで汎用の 16進数 -> 10進数関数を作ってみました。
{16進数を10進数に変換}
function HexToInt(Hex:string):integer;
const
ErrorMsg='桁数が2桁か4桁ではありません。';
var
High,Low:string;
begin
Result:=-1;
if Copy(Hex,1,1)='$' then Delete(Hex,1,1);
High:='';
Low:='';
case Length(Hex) of
0: Exit;
2: Low:=Hex;
4: begin
High:=Copy(Hex,1,2);
Low:=Copy(Hex,3,2);
end;
else
raise EConvertError.Create(ErrorMsg); {例外を生成}
end;
Result:=StrToInt('$'+High)*256+StrToInt('$'+Low);
end;
・フォームが表示し終わった時のイベントを取得する。
フォームを表示しているときに起こるイベントには「OnCreate」「OnShow」「OnActivate」などがありますが、表示し終わったときのイベントがありません。これを取得するには「CMShowingChanged」メッセージをトラップします。
(略)
private
{ Private 宣言 }
procedure CMShowingChanged(var Msg:TMessage);message CM_SHOWINGCHANGED;
(略)
procedure TForm1.CMShowingChanged(var Msg:TMessage);
begin
inherited; {通常の CMShowingChagenedをまず実行}
if Visible then
begin
Update; {完全に描画}
//この中にやりたいことを書いていく
end;
end;
・特定のコンポーネントを使ってフォームをドラッグする。
例えば Imageコンポーネントをドラッグするとフォームもドラッグするように動作させるには、OnMouseDownに以下のように書きます。
{ドラッグしてフォームを移動}
procedure TForm1.Image1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if ssLeft in Shift then
begin
ReleaseCapture;
SendMessage (Handle, WM_SYSCOMMAND, SC_MOVE or 2, 0);
Image1.Perform(WM_LBUTTONUP,0,MakeLParam(X,Y));
end;
end;
・コンボボックスに項目を重複せずに追加する。
コンボボックスに項目を追加するとき、すでに追加した項目については再度追加したくないことはありませんか。例えばコンボボックスに履歴機能を付けるときに必要になると思います。
with Combobox1 do
if Items.IndexOf(Text)=-1 then
Items.Add(Text);
「IndexOf」は、かっこ内の文字列が項目の何番目にあるのかを調べるメソッドです。もし該当する項目がなければ「-1」を返します。この機能を利用してすでに項目があるのかを調べているわけです。
・任意のキーを押したらTabキーと同じ挙動にする。
普通はTabキーでコンポーネント間を移動するのですが、これと同じ動作をさせるには、
//その1 SendMessage(Handle, WM_NEXTDLGCTL, 0, 0);
//その2 SelectNext((Sender as TWinControl),True,True);
//その3 Keybd_event(VK_TAB, 0, 0, 0);
方法は3通りあります。その1はウィンドウハンドルを利用して次または前に進みます。その2はDelphiの手続きで、進む先のコンポーネントの種類を制限できたりします。その3はずばりTabキーをソフトウェア的に押す方法で、「Shift+Enter」での逆移動が何のコードも書かずに出来ます。一番きちんと動くやつをどうぞ。
{Enterキーでタブ移動}
procedure TForm1.DBEdit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key=#13 then //Enterキーが押されたら
begin
Key:=#0; //キー入力を無効にし
Keybd_event(VK_TAB,0,0,0) //Tabキーを発生させる。
end;
end;
{上下キーでタブ移動}
procedure TForm1.DBEdit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
case Key of
//下矢印キー
VK_DOWN : begin
Key:=0;
SelectNext((Sender as TWinControl),True,True);
end;
//上矢印キー
VK_UP : begin
Key:=0;
SelectNext((Sender as TWinControl),False,True);
end;
end;
end;
・PageControlで実行時にTabを作り、さらにその上にRichEditを作る
DelphiのIDEにあるエディタはタブ管理されていて、しかもアプリケーションの実行時にタブとエディタ部分を作成しています。それと同じ事をする方法をご紹介します。ちょっとここでは書ききれないのでサンプルプログラムを作りました。ダウンロード(pagecrt.lzh/3KB)して参考にして下さい。
・IEのURLを入力するコンボボックスのように自動的にアドレス入力をさせたい
IEのアドレス入力欄に入力すると、今までの履歴を参照して自動的に入力してくれます。それを行う方法をご紹介します。TComboBoxのOnKeyUpイベントに書くだけなので結構簡単です。
procedure TForm1.ComboBox1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
const
DefUrl: array[0..3] of string =
('http://','file:///','ftp://','res://');
var
i,k,j: integer;
TempLength: integer;
TypedUrl,Address: string;
DefFlag: boolean;
begin
//スキップさせるキー
case Key of
VK_LEFT..VK_DOWN: Exit; //矢印キー
VK_BACK..VK_CLEAR: Exit; //削除キー
VK_SHIFT..VK_MENU: Exit; //Ctrl,Shift,Alt
end;
//小文字にしておく
TypedUrl:=AnsiLowerCase(Combobox1.Text);
{http:// などの場合}
//IEは、一番最初に「h」と入れると「http://」を、
//「f」と入れると「files:///」を返すので、まずは
//それを調べる。「DefUrl」に定数を追加すれば
//好きなだけ自動入力する項目を増やせる。
DefFlag:=False;
for j:=0 to High(DefUrl) do
begin
if AnsiPos(TypedUrl,DefUrl[j])=1 then
begin
TempLength:=Length(TypedUrl);
Combobox1.Text:=DefUrl[j];
Combobox1.SelStart:=TempLength;
Combobox1.SelLength:=Length(Combobox1.Text)-TempLength;
DefFlag:=True;
Break;
end;
end;
if DefFlag then Exit;
{それ以外}
//ここが自動入力のメイン。
//IEは自動入力をとりあえずスラッシュまで行う。
//例えば「http://home.att.ne.jp/red/takeone/」の
//場合は、まず「home.att.ne.jp/」まで、次に「red/」を
//自動入力していく。
//また、大文字と小文字の区別は行わない。履歴の方が小文字
//なのに大文字で入力した場合は、実際の入力が採用される。
for i:=0 to Combobox1.Items.Count-1 do
begin
if AnsiPos(TypedUrl,AnsiLowerCase(Combobox1.Items[i]))=1 then
begin
Address:=Combobox1.Items[i];
TempLength:=Length(TypedUrl);
//スラッシュごとに自動入力
for k:=TempLength to Length(Address) do
begin
if (Copy(Address,k,1)='/') or
(Copy(Address,k,1)='\') then //\はローカル用
begin
Address:=Copy(Combobox1.Items[i],1,k);
Break;
end;
end;
//IEは、履歴が小文字なのに大文字で入力したとき
//(または反対)は、実際の入力を採用する。
//もし、履歴の方を採用したい場合は、下記の2行を
//削って3行目を使えばよい。
Delete(Address,1,Length(TypedUrl));
Combobox1.Text:=Combobox1.Text+Address;
//Combobox1.Text:=Address; //履歴の方を採用する
Combobox1.SelStart:=TempLength;
Combobox1.SelLength:=Length(Combobox1.Text)-TempLength;
Break;
end;
end;
end;
この方法はURL入力以外でも流用できますので、広く使ってみて下さい。
・DDEでブラウザにHTMLファイルを開かせる
DDEを使うにはブラウザをサーバー、自分のアプリをクライアントにします。そのためには、DDEClientConvコンポーネントを使用します。下記例では分かりやすいように動的に作成してますが、設計時にコンポーネントを利用した方が簡単です。IEでの例を示します。
procedure TForm1.Button1Click(Sender: TObject);
const
HtmlFileName='D:\index.htm';
HtmlApplication='C:\Program Files\Internet Explorer\iexplore.exe';
var
DdeClientConv: TDdeClientConv;
Macro: string;
begin
DdeClientConv:=TDdeClientConv.Create(Self);
with DdeClientConv do
begin
try
//ブラウザが起動していないときはここで指定したアプリを起動します。
ServiceApplication:=HtmlApplication;
//IEだと、'IExplore'です。
//ネスケだと、3.xでは 'Netscape'、4.xだと 'NSShell'です。
if SetLink('IExplore','WWW_OpenURL') then
begin
//IEだと '"file://%s",,-1,,,,,'です。
//ネスケだと '"%s"'ですが、どっちでも大丈夫みたいです。
Macro:=Format('"file://%s",,-1,,,,,',[HtmlFileName]);
if not ExecuteMacro(PChar(Macro),True) then
ShowMessage('表示できませんでした。');
CloseLink;
end
else
ShowMessage('接続できませんでした。');
finally
Free;
end;
end;
end;
・タイトルバーをダブルクリックしたときにイベントを発生させたい
これはFormのOnDblClickでは取得できません。なぜならタイトルバーは「非クライアント(Non-Client)領域」だからです。フォームをよく見て下さい。格子状の点々が打ってある領域がクライアント領域です。フォームのプロパティで「ClientHeight/ClientWidth」で指定される領域ですね。しかし、タイトルバーやフォームの大きさを変えられる枠の部分、メニューには格子が付いてません。そこが非クライアント領域です。OnDblClickが受け入れるイベントはクライアント領域内だけです。
非クライアント領域でイベントを発生させたい場合、WindowsAPIの「WM_NCLBUTTONDBLCLK」ウィンドウメッセージをトラップしてこちらで捕まえ、イベントの代わりとします。
(略)
private
{ Private 宣言 }
procedure WMNCLBUTTONDBLCLK(var msg: TWMNCLBUTTONDBLCLK); message WM_NCLBUTTONDBLCLK;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{非クライアント領域で起こったダブルクリックを捕捉}
procedure TForm1.WMNCLBUTTONDBLCLK(var msg:TWMNCLBUTTONDBLCLK);
begin
if msg.HitTest=HTCAPTION then //タイトルバーで起こったならば
ShowMessage('タイトルバーがダブルクリックされました。');
inherited; //トラップ終了
end;
・サブフォルダにあるファイルまで検索したい
あるフォルダ以下にあるファイル全てをサブフォルダも含めて検索したい場合があります。こういうときは、普通なら再帰処理という方法を使って検索するのですが、今回はよりDelphiらしくTStringListを2つ使った検索ルーチンをご紹介しましょう。
フォームに、Button,ListBox,DirectoryListBox,Labelを一つずつ配置して下さい。
{メインルーチン}
procedure TForm1.Button1Click(Sender: TObject);
{検索ルーチン}
procedure FindFiles(FindPath:string; var DirList, FileList: TStringList);
var
SearchRec: TSearchRec;
Found: integer;
begin
if Copy(FindPath,Length(FindPath),1)='\' then
Delete(FindPath,Length(FindPath),1);
Found:=FindFirst(FindPath+'\'+'*.*',faAnyFile,SearchRec);
while Found=0 do
begin
if (SearchRec.Name<>'.') and (SearchRec.Name<>'..') then
begin
if (SearchRec.Attr and faDirectory>0) then
DirList.Add(FindPath+'\'+SearchRec.Name)
else
FileList.Add(FindPath+'\'+SearchRec.Name);
end;
Found:=FindNext(SearchRec);
end;
FindClose(SearchRec);
end;
var
i: integer;
DirList,FileList: TStringList;
begin
{いろいろ初期化}
ListBox1.Items.Clear;
//検索用テンポラリStringList
DirList:=TStringList.Create; //ディレクトリ用
FileList:=TStringList.Create; //ファイル用
try
{ファイルの検索開始}
Label1.Caption:='検索中...';
Application.ProcessMessages;
//第一階層の検索
FindFiles(DirectoryListBox1.Directory,DirList,FileList);
//サブフォルダありの場合
if DirList.Count>0 then
begin
i:=0;
repeat
FindFiles(DirList[i],DirList,FileList);
Inc(i);
until i=DirList.Count;
end;
{結果表示}
Label1.Caption:='ソート中...';
Application.ProcessMessages;
FileList.Sort; //検索結果のソート
ListBox1.Items.Assign(FileList);
Label1.Caption:=Format('ファイル数:%d フォルダ数:%d',[FileList.Count,DirList.Count]);
{StringList開放}
finally
DirList.Free;
FileList.Free;
end;
end;
一番の特徴は、StringListを2つ使っていることです。DirListにはサブフォルダのリストが蓄積され、FileListにはファイル名がフルパスで蓄積されていきます。これの良いところは、TStringListを使っているのでコンポーネントとの親和性が高い(TListBox,TListView,TMemoなど)、DirListとFileListの2つのリストが得られるため、フォルダの処理とファイルの処理を別個に行うことが出来る、という点です。
FindFilesルーチンでDirListに収集されたサブフォルダの情報が、再度FindFilesルーチンに送られてサブフォルダ内のファイルを検索します。本来の再帰ではないのですが、DirListを使うことで再帰風の処理をしています。
・TListViewをReportにした時にサブ項目の実行時追加方法
TListViewのViewStyleプロパティをvsReport、つまり詳細表示にした場合、項目をプログラム的に追加する方法をご紹介します。
フォームにListViewとボタンを用意し、Columnsに「ファイル名」「サイズ」「日時」を追加し、ボタンのOnClickイベントに以下のように記述してください。
procedure TForm1.Button1Click(Sender: TObject);
var
SearchRec: TSearchRec;
Found: integer;
ListItem: TListItem;
begin
//ファイル検索開始
Found:=FindFirst(ExtractFilePath(Application.ExeName)+'*.*',faAnyFile,SearchRec);
if Found=0 then
begin
try
while Found=0 do
begin
{ListViewに項目を追加}
with ListView1 do
begin
//項目追加
ListItem:=Items.Add;
//新規項目のキャプション
ListItem.Caption:=SearchRec.Name;
//項目のサブ項目を追加していく
ListItem.SubItems.Add(IntToStr(SearchRec.Size));
ListItem.SubItems.Add(DateTimeToStr(FileDateToDateTime(SearchRec.Time)));
end;
//次を検索
Found:=FindNext(SearchRec);
end;
finally
//検索終了
FindClose(SearchRec);
end;
end;
end;
いかがでしょう。実行ファイルのあるフォルダ内のファイルがすべてListViewに表示されたと思います。検索方法に関してはここでは触れません。
<図説>vsReportのListView
・TF1BookのFomula One Workbook Desinerだけを呼び出すアプリを作る方法
Delphi3から付いてくるActiveXコンポーネントに「TF1Book」があります。このコンポーネントは、Excelのような表計算機能を提供しています。そして、TF1Bookには「Fomula One Workbook Desiner」が内蔵されています。本来の使い方は設計時にF1Bookのデザインを変更するためのものですが、その出来映えはサンプルアプリケーションとして立派に機能するものです。
Workbook Desinerは、TF1Bookを右クリックして出てくるメニューから起動するのですが、今回はそれを呼び出すだけのアプリケーションを作ってみます。
program Project1;
uses
Windows,
Vcf1;
{$R *.RES}
var
F1Book: TF1Book;
begin
F1Book:=TF1Book.Create(nil);
with F1Book do
begin
try
LaunchDesigner; //デザイナ起動
finally
Free;
end;
end;
end.
F1BookはActiveXなので、他のパソコンで使うには本体であるOCXを一緒に配布しなければなりません。さらに、ActiveXなので、レジストリに登録しなければなりません。
ヘルプによれば以下の通りである。
これらはすべてSystemフォルダへ投入する。DLLに関してはすでに存在している可能性があるので、そのときはコピーしなくていいでしょう。
ライセンスフリーだそうなので、ガンガン配りましょう!
Systemフォルダへのパスは適宜変えること。
Delphi壁の穴 | システムを覗く | レジストリを覗く | アプリケーションを覗く |
リンクは日本Delphi振興会から張ってください。