ドラッグ&ドロップの遅延レンダリングもどき(ファイル)

MFCのCOleDataSourceなんかだと、ドロップ時に遅延レンダリングなんてこともできるらしいが、
.NET・C++/CLIで似たような事が出来ないかと、思いつきだけで作ってみた。

やり方としては、DataObjectのGetDataをオーバーライドして
マウスのボタンが押されていない状態で、GetDataが呼ばれたタイミングを
(マウス操作としての)ドロップ完了と見なす。
それを検出したドロップ元は、
メモリの内容をファイルに保存したり
圧縮ファイルから中のファイルを取り出してたりして、
ドロップ先に渡すファイルを作成する。

public ref class DataObject_DelayRender : public System::Windows::Forms::DataObject
{
public :
    //----------------------------------------------------------------
    // コンストラクタ
    DataObject_DelayRender(void)
    : DataObject()
    {
        Initialize();
    }

    DataObject_DelayRender( System::Object^ data )
    : DataObject( data )
    {
        Initialize();
    }

    DataObject_DelayRender( System::String^ format, System::Object^ data )
    : DataObject( format, data )
    {
        Initialize();
    }

    //----------------------------------------------------------------
    // GetDataをオーバーライド
    /*/
    virtual System::Object^ GetData( System::String^ format ) override
    {
        ButtonCheck();
        return DataObject::GetData( format );
    }

    virtual System::Object^ GetData( System::Type^ format ) override
    {
        ButtonCheck();
        return DataObject::GetData( format );
    }
    //*/
    // これだけオーバーライドしておけば大丈夫?
    virtual System::Object^ GetData( System::String^ format, bool autoConvert ) override
    {
        ButtonCheck();
        return DataObject::GetData( format, autoConvert );
    }

    protected:
    // 遅延レンダリング 関数
    virtual void OnRender( void )
    {
        System::Windows::Forms::MessageBox::Show( L"ドロップされました!" );
    }

    // 変数の初期化
    virtual void Initialize( void )
    {
        m_bComplete = false;
    }

    // ボタンの状態を調べる
    virtual void ButtonCheck( void )
    {
        // ボタンが離れた後の初回にレンダリングを行う

        /*/// .NET版
        if( ( m_bComplete == FALSE )
        && ( System::Windows::Forms::Control::MouseButtons == System::Windows::Forms::MouseButtons::None ) )
        //*/
        //*// Win32 API版
        // GetAsyncKeyStateでマウスの状態を調べる
        if( ( m_bComplete == false )
        && ( !::GetAsyncKeyState( VK_LBUTTON )
            && !::GetAsyncKeyState( VK_RBUTTON )
            && !::GetAsyncKeyState( VK_MBUTTON )
            && !::GetAsyncKeyState( VK_XBUTTON1 )
            && !::GetAsyncKeyState( VK_XBUTTON2 )
        ) )
        //*/
        {
            // 初回終了
            m_bComplete = true;

            OnRender();
        }
    }

    bool m_bComplete;
};
    

使うときは、これを更に継承してOnRender()をオーバーライドするのがいいと思われる。

DoDragDropする箇所では、

DataObject_DelayRender^ objDataObj;

objDataObj = gcnew DataObject_DelayRender( DataFormats::FileDrop, strDropFiles );

// ここでは、リストビューからのD&D例
frmListView->DoDragDrop( objDataObj, DragDropEffects::Copy );

みたいに書く。

マウスのボタンの状態を取得するところがWin32 APIになっているのは、
System::Windows::Forms::Control::MouseButtonsだと、
Explorerへのドラッグ中にボタン状態がNoneになってしまうことがあったためで、
原因もわからないので、とりあえずWin32にしておいた。
strDropFilesは、遅延レンダリング時に作成するファイル名と同じものをあらかじめ入れておくこと。
違う名前だとうまくいきません。

以上でドラッグ&ドロップの遅延レンダリングもどき(ファイル)の実装はおわり。
完璧ではないと思うが、一通り試した限りではうまくいくようなのでこれでOKとしておく。

もっと正攻法だったり完璧な方法なんかがあれば教えてください>凄いプログラマのみなさま。

更新:2006/04/30
GetKeyState → GetAsyncKeyStateに変更。
ネームスペースを修正

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です