VST GUIにおけるドラッグアンドドロップの対応
VST GUIにおいてファイルなどをドラッグアンドドロップで受け取る方法を説明します。
なお、VST GUIの基本的な作成方法として下記をご理解いただいている前提で進めさせていただきます。
ドラッグアンドドロップ受付用のViewクラスの作成
まず、ドラッグアンドドロップ操作を受け付けるためのクラスをCViewクラスとIDropTargetクラスを継承して作成します。
Windowsで「windows.h」を利用している場合、「windows.h」にIDropTargetクラスが定義されているため、VSTGUI::IDropTargetのように名前空間を指定しないとエラーが出る場合があります。
なお、このクラスは背景画像や背景色を設定しないため見た目上は何も表示されないビュー(UI)となるので、必要に応じてsetBackground()などで画像を設定してください。
【guieditor.h】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class CDragAndDropView : public CView , public VSTGUI::IDropTarget // ドラッグアンドドロップ処理を受け取るため、IDropTargetを継承 { public: CDragAndDropView(const CRect& size); // IDropTargetの関数 ---------------------------------------- // ドラッグが開始された際に実施される関数 DragOperation onDragEnter(DragEventData eventData) override; // ドラッグでマウスカーソル移動中に実施される関数 DragOperation onDragMove(DragEventData eventData) override; // ドラッグが中断された際に実施される関数(マウスカーソルがウィンドウの外になったなど) void onDragLeave(DragEventData eventData) override; // ドロップされた際に実施される関数 bool onDrop(DragEventData eventData) override; }; |
【guieditor.cpp】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
CDragAndDropView::CDragAndDropView(const CRect& size) : CView(size) { setDropTarget(this); // このViewをドロップ操作の対象として登録する } // ドラッグが開始された際に実施される関数 DragOperation CDragAndDropView::onDragEnter(DragEventData eventData) { return onDragMove(eventData); } // ドラッグでマウスカーソル移動中に実施される関数 DragOperation CDragAndDropView::onDragMove(DragEventData eventData) { return DragOperation::Move; } // ドラッグが中断された際に実施される関数(マウスカーソルがウィンドウの外になったなど) void CDragAndDropView::onDragLeave(DragEventData eventData) { } // ドロップされた際に実施される関数 bool CDragAndDropView::onDrop(DragEventData eventData) { // ドロップされたデータの数を取得する。 // (複数のファイルなどがドロップされる場合があるので、データの数を取得する。) int count = eventData.drag->getCount(); // ドロップされたファイルの数だけ処理する for (int i = 0; i < count; i++) { char* buffer; // ドロップされたデータ IDataPackage::Type type; // ドロップされたデータの種類 int size = 0; // ドロップされたデータのサイズ // ドロップされたデータを取得する。 // bufferとtypeにそれぞれデータとデータの種類が取得できる。 // データの種類はkFilePath・kText・kBinaryのいずれかになる。 // 戻り値はデータのサイズ。 size = eventData.drag->getData(i, (const void*&)buffer, type); // ここでファイルパスなどを使用してファイルの読込などを行う // 今回は省略 } return true; } |
CDragAndDropViewでは、コンストラクタでsetDropTarget()関数を呼び出し、自分自身をドラッグアンドドロップ操作の対象として登録します。
これで、CDragAndDropView上でドラッグアンドドロップ操作が発生した際にIDropTargetクラスの関数からオーバーライドした各関数が呼び出されるようになります。
1 2 3 4 5 |
CDragAndDropView::CDragAndDropView(const CRect& size) : CView(size) { setDropTarget(this); // このViewをドロップ操作の対象として登録する } |
続いて、IDropTargetクラスの関数からオーバーライドしたonDragEnter()関数、onDragMove()関数、onDragLeave()関数、onDrop()関数の処理を記載します。
onDragEnter()関数は、ドラッグされた状態でマウスカーソルが「CDragAndDropViewの外」から「CDragAndDropViewの上」に入ってきたとき呼び出されます。
引数のDragEventData(後述)にはドラッグの状態(データ内容やカーソル位置など)が保存されていますが、何もすることがなければ、onDragMove()を呼び出して終了します。
1 2 3 4 5 |
// ドラッグが開始された際に実施される関数 DragOperation CDragAndDropView::onDragEnter(DragEventData eventData) { return onDragMove(eventData); } |
onDragMove()関数は、ドラッグされた状態で「CDragAndDropViewの上」を動いた際に呼び出されます。
戻り値のDragOperation型は列挙型で、DragOperation::MoveかDragOperation::Copyを返すようにします。
1 2 3 4 5 |
// ドラッグでマウスカーソル移動中に実施される関数 DragOperation CDragAndDropView::onDragMove(DragEventData eventData) { return DragOperation::Move; } |
DragOperation::MoveとDragOperation::Copyはドラッグ中のマウスカーソルが下記のように変わります。
DragOperation::Moveが左のカーソルでDragOperation::Copyが右のカーソルです。
DragOperation型はDragOperation::Noneも指定できますが、DragOperation::Noneを指定するとドロップできなくなります。
onDragLeave()関数はドラッグされた状態でマウスカーソルが「CDragAndDropViewの上」から「CDragAndDropViewの外」に出たときに呼び出されます。
何もすることがなければ、空の関数にしても問題ありません。
1 2 3 4 |
// ドラッグが中断された際に実施される関数(マウスカーソルがウィンドウの外になったなど) void CDragAndDropView::onDragLeave(DragEventData eventData) { } |
onDrop()関数は実際にファイルなどがドロップされた際に呼び出されます。
引数のDragEventData構造体を使用して必要な情報を取得します。DragEventData構造体は下記となります。
- DragEventData構造体
型 | 変数名 | 概要 |
---|---|---|
IDataPackage* | drag | ドロップするデータが格納されたIDataPackageクラスの変数 |
CPoint | pos | マウスカーソルの位置を示す変数 |
CButtonState | modifiers | マウスボタンの状態を示すCButtonStateクラスの変数 |
onDrop()関数では基本的に引数eventDataのIDataPackage* dragを使います。
IDataPackageクラスはドロップするデータが格納されたクラスで、IDataPackageクラスのgetCount()関数でドラッグ・ドロップされたデータ数を確認し、getData()関数を使用してデータを取得する使い方となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// ドロップされた際に実施される関数 bool CDragAndDropView::onDrop(DragEventData eventData) { // ドロップされたデータの数を取得する。 // (複数のファイルなどがドロップされる場合があるので、データの数を取得する。) int count = eventData.drag->getCount(); // ドロップされたデータ(ファイルなど))の数だけ処理する for (int i = 0; i < count; i++) { char* buffer; // ドロップされたデータ IDataPackage::Type type; // ドロップされたデータの種類 int size = 0; // ドロップされたデータのサイズ // ドロップされたデータを取得する。 // bufferとtypeにそれぞれデータとデータの種類が取得できる。 // データの種類はkFilePath・kText・kBinaryのいずれかになる。 // 戻り値はデータのサイズ。 size = eventData.drag->getData(i, (const void*&)buffer, type); // ここでファイルパスなどを使用してファイルの読込などを行う // 今回は省略 } return true; } |
getData()関数は下記になります。getCount()関数については詳細は割愛します。
- getData()関数
概要 | ドラッグアンドドロップ中のデータを取得する関数 | ||
---|---|---|---|
戻り値 | 型 | 概要 | |
uint32_t | 取得したデータのサイズを返す。 | ||
引数 | 型 | 変数名 | 概要 |
uint32_t | index | ドラッグ・ドロップされたデータの番号。0~getCount()関数の戻り値の範囲で指定します。 | |
const void*& | buffer | データバッファのポインタを格納する変数。 後述する引数typeの値がkFilePath・kTextの場合、ポインタの内容は\0で終端されたUTF-8の文字列となります。 引数typeの値がkBinaryの場合、ポインタの内容はバイナリデータとなります。 データバッファ自体はSDK内部で確保・解放されます。 |
|
Type& | type | データの種類を格納する変数。 データ種類はkFilePath・kText・kBinaryの3種類があります。 |
IDataPackageクラスのメンバー関数は上記のサンプルで示したgetCount()関数、getData()関数以外にもgetDataType()関数、getDataSize()関数がありますが、詳細は割愛します。
データが取得できれば、データに合わせて処理を実施します。今回はデータの処理については省略しております。
VST GUIへの組み込み
CDragAndDropViewクラスが実装できれば、実際にVST GUIに組み込みます。
VST GUIクラスのopen()関数内でCDragAndDropViewクラスを作成します。
【guieditor.cpp】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
bool PLUGIN_API MyVSTGUIEditor::open(void* parent, const PlatformType& platformType) { // GUIウィンドウが開かれたときに、UIを作成する ~~ 中略 ~~ // 作成したフレームを開く frame->open(parent); // --------------------------------------------- // ここからDrag&Dropの対応 // 引数で指定したサイズがドラッグアンドドロップを受け付ける範囲となる CDragAndDropView* tmp = new CDragAndDropView(size); frame->addView(tmp); // --------------------------------------------- // ここから各コントロールの作成 ~~ 中略 ~~ // GUIウィンドウのオープンに成功した場合はtrueを返す return true; } |
上記により、CDragAndDropViewの引数sizeで指定した範囲でドラッグアンドドロップの操作を受け付けることができます。
なお、CDragAndDropViewは他のコントロールと同じく、addView()で登録した後はframeが破棄された際に解放されるので、deleteで解放する必要はありません。
補足
今回作成したCDragAndDropViewクラスは、ドラッグアンドドロップの処理がCDragAndDropViewクラス内で完結してしまうため、ドロップの処理で他のコントロールを更新したりするには少し不向きかもしれません。
CDragAndDropViewクラスがIDropTargetクラスを継承するのではなく、VST GUIクラス(MyVSTGUIEditor)にIDropTargetクラスの継承を追加してターゲットにするなど、工夫することで対応できます。
例えばCDragAndDropViewクラスを下記のような感じで実装します。
【guieditor.h】
1 2 3 4 5 6 7 8 9 10 |
class CDragAndDropView2 : public CView { public: // CDragAndDropView2クラスの上で行われたドラッグアンドドロップ操作イベントはtargetに渡される CDragAndDropView2(const CRect& size, VSTGUI::IDropTarget* target) : CView(size) { setDropTarget(target); } }; |
VSTGUIクラス側はIDropTargetクラスの継承を追加します。
1 2 3 4 |
class MyVSTGUIEditor : public VSTGUIEditor, public IControlListener , public VSTGUI::IDropTarget // ドラッグアンドドロップ処理を受け取るため、IDropTargetを継承 { // onDragEnter()、onDragMove()、onDragLeave()、onDrop()の実装ももちろん行うこと! |
VST GUIに組み込む際(CDragAndDropView2クラスを作成する際)に自分自身をターゲットとして指定して作成する。
【guieditor.cpp】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
bool PLUGIN_API MyVSTGUIEditor::open(void* parent, const PlatformType& platformType) { // GUIウィンドウが開かれたときに、UIを作成する ~~ 中略 ~~ // 作成したフレームを開く frame->open(parent); // --------------------------------------------- // ここからDrag&Dropの対応 // 引数で指定したサイズがドラッグアンドドロップを受け付ける範囲となる CDragAndDropView2* tmp = new CDragAndDropView2(size, this); frame->addView(tmp); // --------------------------------------------- // ここから各コントロールの作成 ~~ 中略 ~~ // GUIウィンドウのオープンに成功した場合はtrueを返す return true; } |
おわりに
以上でドラッグアンドドロップに対応できます。
上記以外にもVST3についての情報があります。下記をご参照ください。
また、質問やご指摘はコメント欄や掲示板、Twitterでいただけばとおもいます。
■掲示板
■Twitterアカウント:@vstcpp URL:https://twitter.com/vstcpp