お世話になります。
現在、D7でTreeViewのD&Dに挑戦しているのですが、考え方というか方法が判らずに悩んでいます。
たとえば、子の部分にドロップした場合は子の子になってしまうのですが
同階層でしたに入れたい場合どのような感じになるのでしょうか?
よく、項目の間に線が出てきて、そこに挿入しささるというものを見かけるのですが、あれの実装が希望です。
すいませんが、御指南くださいませ。
Google 「Delphi TreeView D&D」でいっぱいあります
>Google 「Delphi TreeView D&D」でいっぱいあります
それがいっぱい無いんですよ。
子に移動のD&Dのやりかたではなく、間に入れる方法はまったくでてきません。
親自体にドロップし、子としての移動はできますが子と子の間に移動。親と親の間が不明なんです。
こんにちは,Mr.XRAYです.
TreeViewのItemのDrag and Dropは,ノードの階層下に追加するのが仕様のハズです.
変更したければ,マウスの現在位置から,判定して,その任意のレベルのノードにItemを追加する
という作業になるのではないかと思います.
ただし,個人的には疑問です.ユーザが
「あれ!? ドラッグでノードの下に追加なるんじゃなかったっけ? 同じレベルに追加されちゃった」
ということにもなりかねませんから.
>よく、項目の間に線が出てきて、
これはカスタム描画がが必要です.GetDragImagesという関数を使用しますが,
これは,protected部にあります.
したがって,TreeViewを継承したクラス(つまり,コンポーネント)を作成するか,
protected部にアクセスする仕組みが必要です.
参考コードが以下にあります.
http://www.delphidabbler.com/tips/119
面倒であれば,TreeViewを拡張したコンポーネントを提供しているところがあります.
それを利用してみてはいかがでしょうか.
VirtualTreeViewというコンポーネントを使用した nanaTreeというのがあります.
これはソースコード付きですから,ダウンロードして研究してみてはいかがでしょうか.
nanaTreeの参考ページ
NanaTree Ver1.05の公開とオープンソース化のお知らせ
http://yourcolor.seesaa.net/article/134778238.html
NanaTree について
http://mrxray.on.coocan.jp/bbs/DelphiBBS/mrxray_delphifan_coffe.cgi?tree=s2848#2848
>ノードの階層下に追加するのが仕様のハズです.
だと思います.
すでに,Drag and Dropのテストをしているのであれば理解しているとは思いますが,
OnDragDropイベントで処理しますから,いくらでも仕様の変更は可能です.
こんにちは.Mr.XRAYです.
朝の寝ぼけたレスで,ちょと変な説明でスミマセン.
言いたかったのは,以下のようなことです.
ネット上のサンプルコードを見ると,OnDragDropイベントにコードが書いてあると思います.
このイベントのコード次のように,何も処理がないコードにします.
procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
begin
///
end;
すると,ドラッグ・ドロップしても,ノードの追加はしてくれません.
つまり,実際にノード(Item)を追加するのは,このOnDragDrop内に書いたコードが行っているわけです.
これは,自分の希望のItemなり,ノードの追加等のコードを,ここに自由に書けることを意味しています.
ということです.
>よく、項目の間に線が出てきて、そこに挿入しささるというものを見かけるのですが、あれの実装が希望です。
以前見たなーと感じたのでお役にたてば。
http://www2.big.or.jp/~osamu/Delphi/tips.cgi?index=0316.txt
これを少し変更すればいけると思います。
こんにちは,Mr.XRAYです.
>http://www2.big.or.jp/~osamu/Delphi/tips.cgi?index=0316.txt
>これを少し変更すればいけると思います。
ですね.後は工夫次第ですね.
私が前に提示した,GetDragImagesは,残念ながら,ImageListでビットマップを設定していないとダメでした.
スミマセン.
子ノードとしてではなく,(移動)挿入ですが,
1つの考え方として,各ノードにアイコン(画像)が表示されているものとして,
ドラッグする時に,このアイコンでドラッグ開始した時はインサート.テキスト部分からドラッグ開始した
場合は,子ノード追加というような仕様にするとすれば,
例えば次のようなコードで可能です.
これも,動作仕様をいろいろ検討する必要があるように思います.
procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
SourceNode : TTreeNode;
DestNode : TTreeNode;
AHit : THitTests;
begin
//選択ノード
SourceNode :=TreeView1.Selected;
//ターゲットノード
DestNode := TreeView1.DropTarget;
AHit := TreeView1.GetHitTestInfoAt(X, Y);
//もしノードの画像(ビットマップ)でマウスダウンしてドラッグしてきたら
//DestNodeにインサートする
if (htOnIcon in AHit) then begin
SourceNode.MoveTo(DestNode, naInsert);
//それ以外,つまりテキスト部分であったら子ノードとして追加する
end else begin
SourceNode.MoveTo(DestNode, naAddChild);
end;
end;
別の考え方として,横線を描画するのであれば,
横線が,ドロップ先のアイコンとアイコンの間にあれば挿入,それ以外では子ノードに追加.
というのもありかも知れません.
この場合,子ノードに追加の状態であれば,横線は表示しないとか.いや,してもいいのかな?
残念ですが,想像力が働きません.
こんにちは.Mr.XRAYです.
折角の質問ですので,できればサンプルプログラムを作ってみたいと考えています.
動作仕様のいいアイディアがありましたらお願いします.
どういう場合に,ノードの追加,または子ノードとして追加とするか,
アイコンが表示されている場合と,アイコンがない場合の動作をどうするか,等ですね.
なお,{Ctrl] キーを押した場合とか,キー操作は伴わないものとします.
>横線が,ドロップ先のアイコンとアイコンの間にあれば挿入,それ以外では子ノードに追加.
>というのもありかも知れません.
あっ,これダメですね.いいアイディアだと思ったんですが,
既に子ノードがあるとき,一番上の子ノードと,その親ノードの間に横線がある時にどうするか,
判定基準が... う〜む.難しい.
このノードの挿入でよくあるのは,上下の矢印があってっ,それで,上とか下に移動というのはありますね.
やっぱり確定的な仕様の作成は難しいかな.
Acrobatの場合は、マウスカーソルが、追加先のアイテムのイメージ部にポイントすると、イメージの下まで選択線が延びて同階層に追加されます。文字列部にポイントしたときには、文字列の下のみ選択線が描画され、子ノードに追加されます。
こんにちは.
Novさんどうもです.
>Acrobatの場合は、
なるほど,目次の部分ですね.
訊いてみるもんです.気が付きませんでした.
質問された方には,悪いことを言ってしまいましたね.スミマセン.
言い訳になりますが,TreeViewというと,エクスプローラぐらしか頭に入ってきませんでした.
この方針で,やってみたいと思います.
ありがとうございます.
[CTRL] 押しながらで COPY 押してないと MOVE
Selected と DropTarget が同じ場合 同階層 違う場合 Child にする
コピー先に同名があれば ~1 ~2 と付けて行く
procedure TForm3.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
I,J: Integer;
B: Boolean;
begin
if TreeView1.DropTarget = TreeView1.Selected then
begin
//[CTRL] が押されている場合のみ
if (GetAsyncKeyState(VK_CONTROL) and $8000) <> 0 then
begin
J := 1;
while J <> 0 do
begin
B := True;
for I := 0 to TreeView1.DropTarget.Owner.Count - 1 do
begin
if TreeView1.DropTarget.Owner.Item[I].Text = TreeView1.Selected.Text + '~' + IntToStr(J) then B := False;
end;
if B = False then
begin
Inc(J);
end
else
begin
TreeView1.Items.Add(TreeView1.DropTarget,TreeView1.Selected.Text + '~'+IntToStr(J));
J := 0;
end;
end;
end;
end
else
begin
//同名があるか確認
B := True;
for I := 0 to TreeView1.DropTarget.Count - 1 do
begin
if TreeView1.DropTarget.Item[I].Text = TreeView1.Selected.Text then B := False;
end;
//同名が無い場合
if B = True then
begin
TreeView1.Items.AddChild(TreeView1.DropTarget,TreeView1.Selected.Text);
end
else
begin
//同名がある場合
J := 1;
while J <> 0 do
begin
B := True;
for I := 0 to TreeView1.DropTarget.Count - 1 do
begin
if TreeView1.DropTarget.Item[I].Text = TreeView1.Selected.Text + '~' + IntToStr(J) then B := False;
end;
if B = False then
begin
Inc(J);
end
else
begin
TreeView1.Items.AddChild(TreeView1.DropTarget,TreeView1.Selected.Text + '~' + IntToStr(J));
J := 0;
end;
end;
end;
//MOVEの場合移動元を削除
if (GetAsyncKeyState(VK_CONTROL) and $8000) = 0 then
begin
TreeView1.Selected.Delete;
end;
end;
end;
procedure TForm3.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
Accept := True;
if (GetAsyncKeyState(VK_CONTROL) and $8000) = 0 then
begin
TreeView1.DragCursor := crDefault;
end
else
begin
TreeView1.DragCursor := crDrag;
end;
end;
KHE00221さんどうも.コードサンクスです.
早速やってしまいました.
>[CTRL] 押しながらで COPY 押してないと MOVE
これは私も考えたんですよね.
>Selected と DropTarget が同じ場合 同階層 違う場合 Child にする
なるほど.この仕様もありですね.
>コピー先に同名があれば ~1 ~2 と付けて行く
うんうん.エクスプローラ風ですね.
これはちょっと考えたいですね.
どんな状況で,どんなアプリで使えかにもよりますが,いっそのこと同名はコピーできないとか....
まだまだアイディア募集中です.って,最初の質問者を無視していいのか?
当方はのんびりやります.切っ掛となった質問者はお隠れになっているようですので(笑).
スレッドを乗っ取ってしまったのかな?
ところで,KHE00221さんのサイト,コンテンツが少し少なくなっているよう気もしますが.
整備中なのでしょうか.気のせいかしら.
とりあえず、移動のみのサンプル書いてみました。
http://d.hatena.ne.jp/au2010/20120227/1330313151
こんにちは.Mr.XRAYです.
>とりあえず、移動のみのサンプル書いてみました。
>http://d.hatena.ne.jp/au2010/20120227/1330313151
早っ!! いですね.
私なんかまだ,PDFの目次部分の操作仕様を観ているだけです.
そうですか.「移動先の表示はTVM_SETINSERTMARKメッセージ」を使うんですか.
図があるとどんな動作をするコードか理解できていいですねぇ.
サンプルコード使わせてください.
例によって,いつになるか分かりませんが,当サイトにも掲載したいのです.
よろしく!! m(_ _)m
動作仕様はこれで決まりですね.
ツイート | ![]() |