2024/06/03 電子書籍「電子書籍出版・技術文書作成を劇的に加速!秀丸エディタ + Markdown + Pandocの驚異」を出版

コンポーネントへのファイルのドロップに対応するには

C++Builder

C++Builderで、ファイルのドロップ(Drop)に対応するで、C++Builderでファイルのドロップ(Drop)に対応するアプリケーションの作成方法について説明しました。この記事では、メインフォーム全体を対象にしたファイルのDrop処理の説明をしています。

メインフォームや、ダイアログ上にあるコンポーネントに対してのみ、ドロップ処理を行いたい場合があるかと思います。それを実現するには、どのようにすれば良いでしょうか?

この記事では、C++Builderでコンポーネントに対してのファイルのドロップ処理について説明します。

ドロップされたマウス位置を利用する

この手法では、ドロップされたマウス位置を利用して、特定のコンポーネント上でのみドロップされたファイル名(またはフォルダ名)を取得します。

この手法ですが、フォーム上にマウスカーソルが来たときに、対象のコンポーネント以外の場所でもマウスカーソルの表示がドロップ用のマウスカーソルになってしまうという欠点があります。

プロジェクトの準備

C++Builderで、初めてのプロジェクト作成でも説明しました、SDIアプリケーションをベースに説明します。メインフォームには、TMemoとTEditを2つ配置します。このプロジェクトはC++Builder 12で作成しています。

フォームでドロップを受け入れる処理及び、WM_DROPFILESメッセージの処理の実装は、記事「C++Builderで、初めてのプロジェクト作成」と同様の処理となりますのでそちらを参照してください。

コンポーネントname用途
TMemoMemo1確認用のメッセージ表示
TEditEdFileNameファイル名確認用
TEditEdFolderNameフォルダ名確認用
追加するコンポーンと

プロジェクトファイルは、以下からダウンロードできます。

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」プロパティを使用します。

手順:

  1. コンポーネントパレットからTFileDropコンポーネント選択し、メインフォームにドロップします。
  2. FileDrop1を選択し、そのオブジェクトインスペクタのプロパティの「DropControl」の箇所で、紐付けたいコンポーネントを選択します。以下の画像では、EdFileName(TEdit)を選択しています。

WM_DROPFILESメッセージの処理

ファイルをドロップた時に発生する、WM_DROPFILESメッセージを処理するイベント関数を作成します。

手順:

  1. TFileDropコンポーネントのオブジェクトインスペクタのイベントの、「OnDrop」箇所をダブルクリックします。

これで、EdFileName(TEdit)コンポーネントのWM_DROPFILESを処理するイベント関数が追加されます。

主なプロパティ

TFileDropコンポーネントの主なプロパティは、以下の通りです。

Dropされたファイル名/フォルダ名を取得するには、FileCountFilesプロパティを使用します。

プロパティ説明
EnableDropboolコンポーネントの有効/無効
DropControlVcl::Controls::TWinControl*紐付けるコンポーネント
FilesSystem::Classes::TStrings*Dropされたファイル名/フォルダ名を格納するTStrings
FileCountintDropされたファイル名/フォルダ名の数
TFileDropコンポーネントの主なプロパティ

 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.pascomponent source code.
PJDropFiles.dcrcomponent palette glyphs.
PJDropFilesDsgn.pasproperty editors and component registration source code.
PJDropFilesDsgn.dfmproperty editor form.
インストールに必要なファイル

「’DesignIntf’ が見つかりません。」という、エラーへの対応方法

Embacaderoから、Delphi ソースを含んだ設計時パッケージをコンパイルするときの対応方法の情報が公開されていました。

対応手順

  1. 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を参照してください。

Delphi ソースを含んだ C++ 設計時パッケージをコンパイルする - RAD Studio

WIN64での対応

もう一つの注意点として、WIN64では設計時パッケージは不要ですので、(あると、コンパイルが通らない)

  • PJDropFilesDsgn.pas をコンパイル対象から外す
  • designide.bpi リンクしない

とする必要があります。

Drop Files Component 内の各コンポーネント

Drop Files Components には、Windows エクスプローラーからのドラッグ アンド ドロップをサポートする 3 つのコンポーネントと、ドロップされたファイルをフィルター処理できる補助コンポーネントが含まれています。

コンポーネント説明
TPJDropFilesクライアント領域または子コントロールのクライアント領域にドラッグ アンド ドロップされたファイルをキャッチするコンテナー コントロール
TPFormDropFilesエクスプローラーからコンポーネントを含むフォームにドラッグ アンド ドロップされたファイルをキャッチする非ビジュアル コンポーネント。
TPJCtrlDropFilesエクスプローラーから関連するコントロールにドラッグ アンド ドロップされたファイルをキャッチする非ビジュアル コンポーネント。
TPJExtFileFilter拡張子に応じてファイルをフィルタリングするファイル フィルタ コンポーネント。
TPJWildCardFileFilteDOS スタイルのワイルドカードに従ってファイルをフィルタリングするファイル フィルタ コンポーネント。
Drop Files Component 内の各コンポーネント

TPJDropFiles, TPFormDropFiles, TPJCtrlDropFiles コンポーネント

TPJDropFiles, TPFormDropFiles, TPJCtrlDropFile コンポーネントについて説明します。

相違点

TPJDropFiles, TPFormDropFiles, TPJCtrlDropFiles コンポーネントの違いは、ドロップする対象が異なる点です。プロパティ等、ほぼ同じように使用できます。

コンポーネントドロップの対象
TPJDropFilesTPJDropFiles のクライアント領域または子コントロールのクライアント領域
TPFormDropFilesコンポーネントを含むフォーム全体
TPJCtrlDropFilesDropControl に設定したコンポーネントのクライアント領域
ドロップの対処

TPJCtrlDropFilesのプロパティ

TPJCtrlDropFilesの主なプロパティの一覧です。

プロパティ説明
Countintコンポーネントの有効/無効
Files[]System::UnicodeStringDropされたファイル名/フォルダ名を格納する
FileNameSystem::UnicodeStringDropされたファイル名/フォルダ名
IsFolder[]boolドロップされたのが、フォルダ名かどうか?
DropPointSystem::Types::TPointDropされたマウス位置
ManagedControlVcl::Controls::TWinControl*紐付けられているコンポーネント
Enabledboolコンポーネントの有効/無効
FilterTPJFileFilter*フィルタ(TPJExtFileFilter,TPJWildCardFileFilte)
OptionsTPJDropFilesOptionsオプション設定(dfoIncFolders, dfoIncFiles, dfoRecurseFolders)
TPJCtrlDropFilesの主なプロパティ

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の主なプロパティ

プロパティ説明
ExtensionsSystem::UnicodeString指定された拡張子のないファイルをフィルターで除外します。
StyleTPJExtFileFilterStyleフィルターが適用されるファイルのタイプを決定します。
主なプロパティ

プロパティの設定方法

  • Extensions
    • 受け入れる拡張子を指定します.。(例:”.htm;.html;.shtml”)
  • Style
    • fsFilterFilesOnly, fsFilterFoldersOnly, fsAll のどれかを設定します。

プロパティの設定例

  • Extensions
    • “.cpp;.h,.hpp” をセット
  • Style
    • fsFilterFilesOnly をセット

しています。

Extensions プロパティは、エディト用のダイアログから入力することもできます。

TPJWildCardFileFilte コンポーネント

このプロパティは、ワイルドカード文字列を用いてファイルをフィルタリングします。

TPJWildCardFileFilteの主なプロパティ

プロパティ説明
WildCardStringワイルドカード文字列を指定します。
主なプロパティ

プロパティの設定例

  • 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も参考にしてくだい。

DragQueryPoint 関数 (shellapi.h) - Win32 apps
ドラッグ アンド ドロップ操作中にファイルがドロップされた時点でのマウス ポインターの位置を取得します。

  • とほほのライセンス入門

とほほのライセンス入門より、一部抜粋させていただいた表データです。ライセンス条件を解りやすく表にまとめてくれています。

とほほのライセンス入門 - とほほのWWW入門
タイトルとURLをコピーしました