ドロップ禁止場所へドラッグした際にドロップ禁止のイメージを表示するには?

解決


saru  2004-08-18 19:21:31  No: 54238  IP: [192.*.*.*]

ダイアログベースで開発しているのですが、
ツリービューでドラッグアンドドロップしたアイテムを
ウィンドウ外に移動させたときにドロップ禁止イメージ
(エクスプローラで表示される円の中に斜線)をドラッグ
イメージに重ねて表示させたいと思っています。

質問1. ドロップ禁止イメージの描画方法

       通常のドラッグイメージは表示出来ているのですが、
       このドロップ禁止イメージ(マーク)を(重ねて)表示させる
       ことが出来ません。

質問2. ウィンドウ外でマウスカーソルとドラッグイメージを
       同じ位置に描画する方法

       ウィンドウ内でドラッグイメージの描画は出来たのですが
       ウィンドウ外に出たときにうまく描画が行えません。
       SetCapture()でウィンドウ外の情報を取得し、マウスカーソルの
       座標は取得出来ているのですが、その座標を使って、
       "DragEnter(NULL, 座標)"でドラッグイメージ(まだ通常の
       ドラッグイメージ)を表示させるとマウスカーソルの位置と
       表示されるドラッグイメージの位置がずれて表示されてしまいます。
       マウスカーソルは座標をウィンドウの左上が"0,0"とした位置からの
       相対する位置に描画しているが、ドラッグイメージはデスクトップの
       左上を"0,0"とした位置から相対した位置に描画しているようです。
       マウスカーソルとドラッグイメージが重なるように表示させる方法
       を教えてください。

以上、ご指導宜しくお願い致します。
開発環境は Windows Xp, VC++6.0, MFC使用です。

編集    削除
saru  2004-08-19 02:28:52  No: 54239  IP: [192.*.*.*]

"質問1"が解決しました。
リソースにデフォルトで用意されているドロップ禁止カーソル
(IDC_NODROP)を保存し、ソースコードからLoadCursor()で
取得します。それをカーソルにセットすれば表示出来ました。
以下、ソースコード

HCURSOR hcursor = AfxGetApp()->LoadCursor(IDC_NODROP);
SetCursor(hcursor);

"質問1"は解決です。ありがとうございました。

編集    削除
とおり  2004-08-19 20:51:56  No: 54240  IP: [192.*.*.*]

試していないですが
ScreenToClient、ClientToScreen
どちらかでどうでしょう。

#未確認です。駄目だったらゴメンナサイ

編集    削除
saru  2004-08-20 05:28:15  No: 54241  IP: [192.*.*.*]

とおりさんこんばんわ、いつも貴重なアドバイス
ありがとうございます。

ClientToScreenとScreenToClientを試してみました。
どちらも座標(らしき)を取得出来ています。

ScreenToClientの場合、その座標をドラッグイメージを
描画するDragEnterに渡すと、ドラッグイメージが
マウスカーソルに対しデスクトップのかなり左上の方から
現われます。

ClientToScreenで同様に試すとドラッグイメージは最初出て
いないのですが、マウスカーソルをデスクトップの左上に
移動させると、ドラッグイメージがいきなり現われます。
現われる位置もマウスカーソルと一致しています。
しかしこの状態では使えないので、使える方法を検討中です。
座標は取れているのでドラッグイメージの描写を工夫しないと
いけないのかも知れません。
もう少し色々やってみます。

編集    削除
あいる  2004-08-20 23:57:26  No: 54242  IP: [192.*.*.*]

ここでははじめましてのあいるです。

たぶん・・・ですが、単純にDragMove してないだけとか??
----- TreeView の OnMouseMove 内 -----
  CTreeCtrl  *pCtrl = &GetTreeCtrl();
  UINT       flags;
  HTREEITEM  hTargetItem = pCtrl->HitTest( point,&flags );

  // メンバで CImageList *m_pDragImageList; と定義されていて初期化済
  m_pDragImageList->DragLeave( this );
  pCtrl->SelectDropTarget( hTargetItem );

  // ここで条件に合わせてカーソル変更
  ::SetCursor( AfxGetApp()->LoadStandardCursor( IDC_NO ) );

  m_pDragImageList->DragEnter( this,point );
  m_pDragImageList->DragMove( point );
----
こんな感じの手順でいいかと
SetCaputure してるなら、DragEnter(NULL,point) ではなくthisでいいかと。

編集    削除
saru  2004-08-22 13:08:00  No: 54243  IP: [192.*.*.*]

あいるさんご指導ありがとうございます。
返信が遅くなりまして大変申し訳ありません。

最初にちょっと気になったのですが・・・
>ここでははじめましてのあいるです。
これは別の所で知り合っているという意味でしょうか?
それともあいるさんがこの掲示板では初めて発言する
という意味の挨拶なのでしょうか?

すみません、本題に入ります。
原因がわかりました。単純なコーディングミスでした。
あいるさんに書いて頂いたソースコードと
自分のソースコードを見比べていて気づいたのですが、
私はドラッグイメージの描画とドロップ禁止イメージの描画を
if文で分岐して記述しているのですが、ドラッグイメージの
描画の方ではDragEnterとDragMoveを行っていたが、
ドロップ禁止イメージの描画の方では行っていなかった
というの原因でした。
以下間違っていたソースコード。

if ((hitem = HitTest(point, &flags)) != NULL)
{
    m_pimagelist->DragLeave(this);
    SelectDropTarget(hitem);
    m_pimagelist->DragEnter(NULL, m_ScreenPoint);
    m_pimagelist->DragMove(m_ScreenPoint);
} else {
    SetCursor(AfxGetApp()->LoadCursor(IDC_NODROP));
}

↑これではドロップ禁止場所でドラッグイメージの描画が
行われないのは当たり前でした。失礼致しました。
ただ、DragEnterの第一引数が"this"ではやはりウィンドウ内
での描画指定になっているようでしたので"NULL"にしました。
以下修正後のソースコード。

----OnMouseMove内----

HTREEITEM           hitem;
UINT                flags;

//ドラッグ状態にある。
if (m_bDragging)
{
    SetCapture();
    m_ScreenPoint.x = point.x;
    m_ScreenPoint.y = point.y;
    ClientToScreen( &m_ScreenPoint );

    static HCURSOR oldCursol;
    static bool flag = false;
    //ドロップ禁止場所からドロップ許可場所へ戻ってきた場合、
    //通常のカーソルに戻す。
    if (flag == true) {
        SetCursor(oldCursol);
    }
    //ドロップ許可場所では通常のカーソルを設定。
    if ((hitem = HitTest(point, &flags)) != NULL)
    {
        m_pimagelist->DragLeave(this);
        SelectDropTarget(hitem);
        m_hitemDrop = hitem;
        flag = false;
    } else {
        //ドロップ禁止場所ではドロップ禁止イメージのカーソルを設定。
        oldCursol = SetCursor(AfxGetApp()->LoadCursor(IDC_NODROP));
        flag = true;
    }
        //ドラッグイメージの描画。
        m_pimagelist->DragEnter(NULL, m_ScreenPoint);
        m_pimagelist->DragMove(m_ScreenPoint);
}
---------------------

と言った具合に致しました。
一応やりたい動きは出来ましたので、[解決]チェックは
入れておきますが、おかしな点がありましたらご指摘を
宜しくお願い致します。
とおりさん、あいるさんありがとうございました。

編集    削除
saru  2004-08-22 13:12:51  No: 54244  IP: [192.*.*.*]

↑と言っておきながら[解決]を押し忘れました。
失礼致しました。

編集    削除