« SaveDialogを拡張してコントロールを追加する(その2) | トップページ | SaveDialogを拡張してコントロールを追加する(その3:補足) »

2018.01.29

SaveDialogを拡張してコントロールを追加する(その3:完結編)

Delphiで出来ないとあんまり意味がないんですけどね。と言っていましたが、ついに情報を見つけました。
情報元はMSDNのIFileDialogCustomize::GetSelectedControlItem method、stackoverflowのAdd a IFileDialogCustomize PushButton Eventです。

結論から言いますと、今までノーマークだったコンポーネントパレット[Vista Dialog]のTFielOpenDialogとTFileSaveDialogが答えでした。これらのコンポーネントはWindows Vistaで変更されたファイルダイアログをサポートするためのもののようですが、追加するラベルの文字色も青色になる等、前の記事で書いたC#でCommonOpenFileDialogを使用する場合と同じような感じになるようです。
それにしても、Windows7以降ではコンポーネントパレット[Dialogs]にあるTOpenDialogとTSaveDialogを使用しても同じダイアログボックスが表示されるため、通常はVista DIalogを使用する機会はないものと思われます(私も今まで使ったことがありませんでした)。

で、コントロールの追加の仕方ですが、Delphi標準のファイルダイアログコンポーネントにはないOnExecuteイベントにコントロールを追加する処理を書いて、Executeした後にそれらのコントロールのステータスを確認する処理を追加すれは良いようです。尚、ボタン等の動作イベントを発生するコントロールを追加して、ファイルダイアログが開いたままの状態でそれらのイベントを処理する場合には、OnExecuteでイベント処理を追加して処理させることが出来るようです。一応stackoverflowのQ&Aに記載されているTMyFileDialogEventsユニットを追加していますが、サンプルでは使用していませんのできちんと動作するのかどうかは不明です。

以下がサンプルソースコードになります。

unit DialogTestUnit;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls, ShlObj;

type
TForm1 = class(TForm)
Button1: TButton;
FileSaveDialog1: TFileSaveDialog;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FileSaveDialog1Execute(Sender: TObject);
private
{ Private 宣言 }
Fdc: IFileDialogCustomize;
public
{ Public 宣言 }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

uses
MyFileDialogEvents;

var
FileDialog: IFileDialog = nil;
MyEvents: IFileDialogEvents = nil;
MyEventsCookie: DWORD = 0;

const
dwIDCtl = 19000;

procedure TForm1.FileSaveDialog1Execute(Sender: TObject);
var
fdevt: IFileDialogEvents;
cookie: DWORD;
begin
inherited;

// IFileDialogCustomizeをサポートするかどうか問い合わせる
if Supports(FileSaveDialog1.Dialog, IFileDialogCustomize, Fdc) then
begin
// 返されたFileSaveDialog1のIFileDialogCustomizeインターフェイスに対して
// コントロールを追加する
//
// AddTextでラベルを追加すると文字が青色になることとComboBoxとのレイアウト
// が思うようにならないため、StartVisualGroupでラベルと追加する(色はグレーだけど)
Fdc.StartVisualGroup(dwIDCtl, PWideChar('文字コードセット:'));
Fdc.AddComboBox(dwIDCtl + 1);
Fdc.AddControlItem(dwIDCtl + 1, 0, 'Shift-JIS'); // ComboBoxにアイテムを追加する
Fdc.AddControlItem(dwIDCtl + 1, 1, 'JIS');
Fdc.AddControlItem(dwIDCtl + 1, 2, 'EUC-JP');
Fdc.AddControlItem(dwIDCtl + 1, 3, 'Unicode(Little Endian)');
Fdc.AddControlItem(dwIDCtl + 1, 4, 'Unicode(Big Endian)');
Fdc.AddControlItem(dwIDCtl + 1, 5, 'UTF-8');
Fdc.AddControlItem(dwIDCtl + 1, 6, 'UTF-8N');
Fdc.SetSelectedControlItem(dwIDCtl + 1, 0); // 0番目を選択
Fdc.EndVisualGroup;

Fdc.StartVisualGroup(dwIDCtl + 2, PWideChar('改行コード:'));
Fdc.AddComboBox(dwIDCtl + 3);
Fdc.AddControlItem(dwIDCtl + 3, 0, 'CR+LF'); // ComboBoxにアイテムを追加する
Fdc.AddControlItem(dwIDCtl + 3, 1, 'CR');
Fdc.AddControlItem(dwIDCtl + 3, 2, 'LF');
Fdc.SetSelectedControlItem(dwIDCtl + 3, 0); // 0番目を選択
Fdc.EndVisualGroup;

// イベントを登録(ボタンが押された等のイベントを処理しない場合は以下の登録は
// しなくても良いようだ)
fdevt := TMyFileDialogEvents.Create;
if Succeeded(FileSaveDialog1.Dialog.Advise(fdevt, cookie)) then
begin
FileDialog := FileSaveDialog1.Dialog;
MyEvents := fdevt;
MyEventsCookie := cookie;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
id1, id2: DWORD;
s1, s2: string;
begin
FileDialog := nil;
MyEvents := nil;
MyEventsCookie := 0;

if FileSaveDialog1.Execute then
begin
// dwIDCtl + 1のComboBoxのItemIndexを取得する
Fdc.GetSelectedControlItem(dwIDCtl + 1, id1);
// dwIDCtl + 3のComboBoxのItemIndexを取得する
Fdc.GetSelectedControlItem(dwIDCtl + 3, id2);
case id1 of
0: s1 := 'Shift-JIS';
1: s1 := 'JIS';
2: s1 := 'EUC-JP';
3: s1 := 'Unicode(Little Endian)';
4: s1 := 'Unicode(Big Endian)';
5: s1 := 'UTF-8';
6: s1 := 'UTF-8N';
end;
case id2 of
0: s2 := 'CR+LF';
1: s2 := 'CR';
2: s2 := 'LF';
end;
Label1.Caption := s1 + ' (' + s2 + ')';
if (FileDialog <> nil) and (MyEventsCookie <> 0) then
FileDialog.Unadvise(MyEventsCookie);
FileDialog := nil;
MyEvents := nil;
MyEventsCookie := 0;
end;
end;

end.



「SaveDialogを拡張してコントロールを追加する」の最初の記事ではテンプレートを用いた拡張を行うため、TSaveDialogを継承したコンポーネントにしましたが、今回の例ではTFileSaveDialogの標準イベントOnExecuteにコントロールを追加するための処理を追加するだけですので、わざわざコンポーネント化する必要もないのかと思いました。
それにしても、C#ではNuGetでパッケージライブラリを追加する必要があったのですが、Delphiでは標準の状態でファイルダイアログを拡張することが出来ちゃいましたと言う事でした。
まぁ、ラベルテキストの文字色が青色だったり、追加するコントロールのレイアウトをうまく設定出来なかったりと、何かもっとやり方があるのではないかと思ったりもするのですが、これで(私としては)機能的には充分なので取り敢えずは完結で良いかなと思った次第です。

テキストをAddTextで追加した場合・・・文字が青色になり、ComboBoxがその下に配置される。
Dialog2

テキストをStartVisualGroupで追加し、ComboBox追加後にEndVisualGroupした場合・・・文字色は灰色となり、ComboBoxはその右側に配置される。
Dialog1


まぁ、お好みなのでしょうが、個人的には後の例の方がイメージに合うかなという感じです。

#追加情報や違ったやり方があるよという方は、コメントに書き込んでいただけると嬉しいです。
#て言いますか、Mr. X-RAYさんの所のダイアログ関連でまとめてくれないかな(他力本願)・・・


サンプルプロジェク「FileDialogTest.zip」をダウンロード

|

« SaveDialogを拡張してコントロールを追加する(その2) | トップページ | SaveDialogを拡張してコントロールを追加する(その3:補足) »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/22406/66335725

この記事へのトラックバック一覧です: SaveDialogを拡張してコントロールを追加する(その3:完結編):

« SaveDialogを拡張してコントロールを追加する(その2) | トップページ | SaveDialogを拡張してコントロールを追加する(その3:補足) »