C++Builderで、ファイルのドロップ(Drop)に対応するで、C++Builderでファイルのドロップ(Drop)に対応するアプリケーションの作成方法について説明しました。この記事では、メインフォーム全体を対象にしたファイルのDrop処理の説明をしています。
メインフォームや、ダイアログ上にあるコンポーネントに対してのみ、ドロップ処理を行いたい場合があるかと思います。それを実現するには、どのようにすれば良いでしょうか?
この記事では、C++Builderでコンポーネントに対してのファイルのドロップ処理について説明します。
ドロップされたマウス位置を利用する
この手法では、ドロップされたマウス位置を利用して、特定のコンポーネント上でのみドロップされたファイル名(またはフォルダ名)を取得します。
この手法ですが、フォーム上にマウスカーソルが来たときに、対象のコンポーネント以外の場所でもマウスカーソルの表示がドロップ用のマウスカーソルになってしまうという欠点があります。
プロジェクトの準備
C++Builderで、初めてのプロジェクト作成でも説明しました、SDIアプリケーションをベースに説明します。メインフォームには、TMemoとTEditを2つ配置します。このプロジェクトはC++Builder 12で作成しています。
フォームでドロップを受け入れる処理及び、WM_DROPFILESメッセージの処理の実装は、記事「C++Builderで、初めてのプロジェクト作成」と同様の処理となりますのでそちらを参照してください。
コンポーネント | name | 用途 |
---|---|---|
TMemo | Memo1 | 確認用のメッセージ表示 |
TEdit | EdFileName | ファイル名確認用 |
TEdit | EdFolderName | フォルダ名確認用 |
WMDropFiles関数
WM_DROPFILESメッセージを処理する、WMDropFiles関数について説明します。
ドロップされたマウス位置が、EdFileName、EdFolderName 上の時に、ドロップされた最初のファイル名/フォルダ名をエディト内に表示しています。
ドロップされたマウス位置は、DragQueryPoint関数で取得し、そのマウス位置が、コンポーネント上かどうかを、ChkContains関数でチェックを行っています。
void __fastcall TSDIAppForm::WMDropFiles(TWMDropFiles MSG)
{
// Dropされたファイル情報の取得
TCHAR FileName[MAX_PATH + 1];
String fname = "";
TPoint DropPos;
int DragNo = DragQueryFile((HDROP)MSG.Drop, 0xFFFFFFFF, nullptr, 0);
if( DragNo != 0 )
{ // 最初のデータを取得
DragQueryFile((HDROP)MSG.Drop, 0, FileName, sizeof(FileName)/sizeof(_TCHAR));
fname = FileName;
// Dropされたファイル情報の取得
DragQueryPoint((HDROP)MSG.Drop, &DropPos);
if(ChkContains(EdFileName, DropPos)) // EdFolderへのDrop
{
if(TFile::Exists(fname))
{
EdFileName->Text = fname;
}
} else if(ChkContains(EdFolderName, DropPos)) {
if( TDirectory::Exists(fname) )
{
EdFolderName->Text = fname;
} else if( TFile::Exists(fname) ) {
// ファイルがDropさっれたら、そのフォルダ名の取得し格納する
fname = TPath::GetDirectoryName(fname);
EdFolderName->Text = fname;
}
}
}
// Memo1->Lines->Add("WMDropFiles");
}
ChkContains関数
ChkContains関数は、posがwedit内かどうかをチェックします。wedit内にあれば、trueを返します。
bool __fastcall TSDIAppForm::ChkContains(TEdit *wedit, TPoint pos)
{
int dummy;
TRect rect(0,0, 0, 0);
rect.Left = wedit->Left + Panel1->Left;
rect.Top = wedit->Top + Panel1->Top;
rect.Right = rect.Left + wedit->Width;
rect.Bottom = rect.Top + wedit->Height;
// 大小のチェック
if(rect.Left > rect.Right)
{
dummy = rect.Left;
rect.Left = rect.Right;
rect.Right = dummy;
}
if(rect.Top > rect.Bottom)
{
dummy = rect.Top;
rect.Top = rect.Bottom;
rect.Bottom = dummy;
}
if (( (rect.Left <= pos.x) && (pos.x <= rect.Right) ) &&
((rect.Top <= pos.y) && (pos.y <= rect.Bottom)))
{
return true;
} else {
return false;
}
}
TFileDropコンポーネント使用する
TFileDropコンポーネントは、昔から使用しているコンポーネントですが、残念ながらWIN32でしか動作しませんでした。WIN64でもコンパイルは通るのですが、実行時にエラーとなってしまいます。使い方は非常に簡単ですので、32ビット版のアプリケーションを作成するのであれば、使用方法は非常に簡単ですのでお勧めです。
ここでは、コンポーネントのインストール方法については説明を省略させていただきます。
コンポーネントとの紐付け
コンポーネントと紐付けるには、TFileDropコンポーネントの「DropControl」プロパティを使用します。
手順:
- コンポーネントパレットからTFileDropコンポーネント選択し、メインフォームにドロップします。
- FileDrop1を選択し、そのオブジェクトインスペクタのプロパティの「DropControl」の箇所で、紐付けたいコンポーネントを選択します。以下の画像では、EdFileName(TEdit)を選択しています。
WM_DROPFILESメッセージの処理
ファイルをドロップた時に発生する、WM_DROPFILESメッセージを処理するイベント関数を作成します。
手順:
- TFileDropコンポーネントのオブジェクトインスペクタのイベントの、「OnDrop」箇所をダブルクリックします。
これで、EdFileName(TEdit)コンポーネントのWM_DROPFILESを処理するイベント関数が追加されます。
主なプロパティ
TFileDropコンポーネントの主なプロパティは、以下の通りです。
Dropされたファイル名/フォルダ名を取得するには、FileCount、Filesプロパティを使用します。
プロパティ | 型 | 説明 |
---|---|---|
EnableDrop | bool | コンポーネントの有効/無効 |
DropControl | Vcl::Controls::TWinControl* | 紐付けるコンポーネント |
Files | System::Classes::TStrings* | Dropされたファイル名/フォルダ名を格納するTStrings |
FileCount | int | Dropされたファイル名/フォルダ名の数 |
OnDropイベント関数
OnDropイベント関数の参考例を、以下に示します。FileCountプロパティでDropされたファイルの数を取得し、Filesプロパティを使用してそのファイル名を取得し、Memo1(TMemo)に表示しています。
void __fastcall TSDIAppForm::FileDrop1Drop(TObject *Sender)
{
if(FileDrop1->FileCount)
{
for(int i=0;i<FileDrop1->FileCount;i++)
{
Memo1->Lines->Add(FileDrop1->Files->Strings[i]);
}
}
}
入手先
コンポネントのソースファイルは、以下のHPから入手できます。最新版は、V1.1のようです。
Drop Files Component を使用する
TFileDropコンポーネントが、残念ながらWIN64に対応していないため、WIN64でも利用可能なコンポーネントを探しました。その結果、「Drop Files Component」 を見つけました。このコンポーネントは、WIN32,WIN64の両方に対応しています。
「Drop Files Component」の特徴は、ファイル名のみ、フォルダ名のみのドロップにもタイプしている点と、ファイルのフィルター機能にも対応している点です。それから、ドロップする対象別に、3つのコンポーネントが用意されている点です。
Drop Files Component のインストール時の注意事項
単純に、パッケージプロジェクトにソースファイルを追加してインストールしようすると、以下のエラーが出てコンパイルに失敗しました(WIN32)。色々と調べたところ、Delphi ソースに設計時パッケージが含まれているのが原因でした。以下にその対応方法ついて説明します。
[DCC 致命的エラー] PJDropFilesDsgn.pas(41): F2613 ユニット ‘DesignIntf’ が見つかりません。
インストールに必要なファイル
Drop Files Component をインストールには、以下の4つのファイルが必要です。PJDropFilesDsgn.pas,PJDropFilesDsgn.dfm が、設計時パッケージ(property editors)用のファイルです。
ファイル | 説明 |
---|---|
PJDropFiles.pas | component source code. |
PJDropFiles.dcr | component palette glyphs. |
PJDropFilesDsgn.pas | property editors and component registration source code. |
PJDropFilesDsgn.dfm | property editor form. |
「’DesignIntf’ が見つかりません。」という、エラーへの対応方法
Embacaderoから、Delphi ソースを含んだ設計時パッケージをコンパイルするときの対応方法の情報が公開されていました。
対応手順
- C++Builder パッケージ プロジェクトで、プロジェクト > オプション… > Delphi コンパイラ > その他のオプション を開き、追加オプション フィールドに -LUDesignIDE を追加します。
2. C++Builder パッケージ プロジェクトに、designide.bpi を追加します。
designide.bpi ファイルは、C++Builderをインストールした以下のフォルダにあります。(デフォルト状態でインストールした場合の)
C:\Program Files (x86)\Embarcadero\Studio\23.0\lib\win32\release\designide.bpi
これで、WIN32でコンパイルが通ります。
詳細は、以下のURLを参照してください。
WIN64での対応
もう一つの注意点として、WIN64では設計時パッケージは不要ですので、(あると、コンパイルが通らない)
- PJDropFilesDsgn.pas をコンパイル対象から外す
- designide.bpi リンクしない
とする必要があります。
Drop Files Component 内の各コンポーネント
Drop Files Components には、Windows エクスプローラーからのドラッグ アンド ドロップをサポートする 3 つのコンポーネントと、ドロップされたファイルをフィルター処理できる補助コンポーネントが含まれています。
コンポーネント | 説明 |
---|---|
TPJDropFiles | クライアント領域または子コントロールのクライアント領域にドラッグ アンド ドロップされたファイルをキャッチするコンテナー コントロール |
TPFormDropFiles | エクスプローラーからコンポーネントを含むフォームにドラッグ アンド ドロップされたファイルをキャッチする非ビジュアル コンポーネント。 |
TPJCtrlDropFiles | エクスプローラーから関連するコントロールにドラッグ アンド ドロップされたファイルをキャッチする非ビジュアル コンポーネント。 |
TPJExtFileFilter | 拡張子に応じてファイルをフィルタリングするファイル フィルタ コンポーネント。 |
TPJWildCardFileFilte | DOS スタイルのワイルドカードに従ってファイルをフィルタリングするファイル フィルタ コンポーネント。 |
TPJDropFiles, TPFormDropFiles, TPJCtrlDropFiles コンポーネント
TPJDropFiles, TPFormDropFiles, TPJCtrlDropFile コンポーネントについて説明します。
相違点
TPJDropFiles, TPFormDropFiles, TPJCtrlDropFiles コンポーネントの違いは、ドロップする対象が異なる点です。プロパティ等、ほぼ同じように使用できます。
コンポーネント | ドロップの対象 |
---|---|
TPJDropFiles | TPJDropFiles のクライアント領域または子コントロールのクライアント領域 |
TPFormDropFiles | コンポーネントを含むフォーム全体 |
TPJCtrlDropFiles | DropControl に設定したコンポーネントのクライアント領域 |
TPJCtrlDropFilesのプロパティ
TPJCtrlDropFilesの主なプロパティの一覧です。
プロパティ | 型 | 説明 |
---|---|---|
Count | int | コンポーネントの有効/無効 |
Files[] | System::UnicodeString | Dropされたファイル名/フォルダ名を格納する |
FileName | System::UnicodeString | Dropされたファイル名/フォルダ名 |
IsFolder[] | bool | ドロップされたのが、フォルダ名かどうか? |
DropPoint | System::Types::TPoint | Dropされたマウス位置 |
ManagedControl | Vcl::Controls::TWinControl* | 紐付けられているコンポーネント |
Enabled | bool | コンポーネントの有効/無効 |
Filter | TPJFileFilter* | フィルタ(TPJExtFileFilter,TPJWildCardFileFilte) |
Options | TPJDropFilesOptions | オプション設定(dfoIncFolders, dfoIncFiles, dfoRecurseFolders) |
TPJDropFiles, TPFormDropFilesもほぼ同じプロパティを持っています。TPJCtrlDropFiles のみ、ManagedControlを使用して、ドロップする対象のコンポーネントを設定します。
TPJCtrlDropFilesのプロパティの設定例
PJCtrlDropFilesのオブジェクトインスペクタの設定例です。
プロパティを以下のように設定しています。Options プロパティを使用すると、フォルダ名のみ、ファイル名のみを取得する(受け入れる)事ができるようになります。
- ManagedControl
- EdFileName(TEdit) に紐付けています。
- Options
- dfoIncFolders: フォルダ名を取得するかどうか
- dfoIncFiles: ファイル名を取得するかどうか
- dfoRecurseFolders: リソースフォルダを取得するかどうか
- Filter
- PJExtFileFilter1(TPJExtFileFilter) を設定しています。
Options プロパティをコードで設定する場合は、以下のように行います。
PJCtrlDropFiles1->Options = PJCtrlDropFiles1->Options >> TPJDropFilesOption::dfoIncFolders;
PJCtrlDropFiles1->Options = PJCtrlDropFiles1->Options >> TPJDropFilesOption::dfoIncFiles;
PJCtrlDropFiles1->Options = PJCtrlDropFiles1->Options >> TPJDropFilesOption::dfoRecurseFolders;
// set
PJCtrlDropFiles1->Options = PJCtrlDropFiles1->Options << TPJDropFilesOption::dfoIncFiles;
TPJExtFileFilter コンポーネント
TPJExtFileFilterコンポーネントは、拡張子に基づいてファイルをフィルタリングします。
TPJExtFileFilterの主なプロパティ
プロパティ | 型 | 説明 |
---|---|---|
Extensions | System::UnicodeString | 指定された拡張子のないファイルをフィルターで除外します。 |
Style | TPJExtFileFilterStyle | フィルターが適用されるファイルのタイプを決定します。 |
プロパティの設定方法
- Extensions
- 受け入れる拡張子を指定します.。(例:”.htm;.html;.shtml”)
- Style
- fsFilterFilesOnly, fsFilterFoldersOnly, fsAll のどれかを設定します。
プロパティの設定例
- Extensions
- “.cpp;.h,.hpp” をセット
- Style
- fsFilterFilesOnly をセット
しています。
Extensions プロパティは、エディト用のダイアログから入力することもできます。
TPJWildCardFileFilte コンポーネント
このプロパティは、ワイルドカード文字列を用いてファイルをフィルタリングします。
TPJWildCardFileFilteの主なプロパティ
プロパティ | 型 | 説明 |
---|---|---|
WildCard | String | ワイルドカード文字列を指定します。 |
プロパティの設定例
- WildCard プロパティに、”*.h*” をセットしています。
WM_DROPFILESメッセージの処理
3つのコンポーネント、TPJDropFiles, TPFormDropFiles, TPJCtrlDropFiles は、すべてWMDropFilesイベント関数を使用して、WM_DROPFILESメッセージの処理を行います。
イベント | 説明 |
---|---|
WMDropFiles | ファイルがDropされた時に呼ばれるイベント関数 |
コード例
PJCtrlDropFiles1 の、WMDropFilesイベント関数のコード例です。
Dropされたのが、フォルダでなければMome1(TMemo)にファイル名を表示します。
void __fastcall TSDIAppForm::PJCtrlDropFiles1DropFiles(TObject *Sender)
{
int count = PJCtrlDropFiles1->Count;
for(int i=0;i<count;i++)
{
if(!PJCtrlDropFiles1->IsFolder[i])
{
Memo1->Lines->Add(PJCtrlDropFiles1->Files[i]);
}
}
}
ライセンス(MPL-2)
Drop Files Componentのライセンスは、MPL-2(the Mozilla Public License v2.0.)です。
以下のHPの情報から、Drop Files Component使用したアプリケーションのソースコードの公開は、不要のようです。
入手先
コンポネントのソースファイルは、以下のHPから入手できます。最新版は、V5.0.5のようです。
参考URL
以下のHPも参考にしてくだい。
- とほほのライセンス入門
とほほのライセンス入門より、一部抜粋させていただいた表データです。ライセンス条件を解りやすく表にまとめてくれています。