TreeViewでノード追加時にキーが既に使われているかを判定するには?

解決


たうお  2006-03-21 04:27:38  No: 130734

はじめまして、いつも大変お世話になっております。
WinXPSP2 VB6SP5の開発環境です。

TreeViewコントロールでノードを追加する時に、
キーが既に使われているかどうかを判定したいのですが、
そのような方法はございますでしょうか?

作ろうとしているものは

コンピュータ>ソフトウェア>Windows>インターネット、通信>電子メール
コンピュータ>ソフトウェア>Windows>インターネット、通信>その他
コンピュータ>ソフトウェア>Windows>グラフィックス、映像、音楽>3D
コンピュータ>ソフトウェア>Windows>グラフィックス、映像、音楽>MIDI
コンピュータ>ソフトウェア>Windows>ゲーム、エンターテインメント>RPG
コンピュータ>ソフトウェア>Windows>ゲーム、エンターテインメント>その他
コンピュータ>ソフトウェア>Windows>ゲーム、エンターテインメント>アクション
コンピュータ>周辺機器>ワークステーション用
コンピュータ>周辺機器>その他
コンピュータ>パーツ>CPU>AMD>Athlon
コンピュータ>パーツ>CPU>AMD>Duron
本、雑誌>雑誌>ファッション>女性>ティーンズ、ストリート
本、雑誌>雑誌>ファッション>女性>美容、ヘアメイク
本、雑誌>雑誌>ファッション>男性>CHECKMATE



(以下2万行以上続く)

というデータからTreeViewを作りたいのです。
私が考えている手順としましては、
まず親ノードを追加。
TreeView1.Nodes.Add , , "カテゴリー", "カテゴリー"

次に
コンピュータ>ソフトウェア>Windows>インターネット、通信>電子メール
の行を取り出して「>」でsplitし、
TreeView1.Nodes.Add "カテゴリー", tvwChild, "コンピュータ", "コンピュータ"
TreeView1.Nodes.Add "コンピュータ", tvwChild, "コンピュータ>ソフトウェア", "ソフトウェア"
TreeView1.Nodes.Add "コンピュータ>ソフトウェア", tvwChild, "コンピュータ>ソフトウェア>Windows", "Windows"
TreeView1.Nodes.Add "コンピュータ>ソフトウェア>Windows", tvwChild, "コンピュータ>ソフトウェア>Windows>インターネット、通信", "インターネット、通信"

そして次の行に行って同じ処理を繰り返そうと思っているのですが
TreeView1.Nodes.Add "コンピュータ", tvwChild, "コンピュータ>ソフトウェア", "ソフトウェア"
これでは固有のキーでは無いとなってしまいます。

On Error トラップでエラーなら次の処理をする、という方法しか思いつきません・・。
でもこれだと他のエラーが発生してしまったら・・と思うと躊躇してしまいます。

長くなりましたが、宜しくご教示の程お願い致します。


魔界の仮面弁士  2006-03-21 07:43:51  No: 130735

元データがソートされて並んでいるのなら、直前行のデータだけを
確認すれば済みそうですね。

たとえば、元データが
  a>b>c>D
  a>b>c>E
  a>b>X>Y>Z
  a>b>X>o>p
  L>M>N
な構造だったとしたら……

1. "a>b>c>D" の行
  1.1 直前にデータが無いので、4階層中、0階層が前回と一致。
  1.2 ルートノードを取得し、その下に 1階層目の "a"を登録。
  1.3 さらにその下に、2階層目の "a>b" を登録。
  1.4 さらにその下に、3階層目の "a>b>c" を登録。
  1.5 さらにその下に、4階層目の "a>b>c>D" を登録。
  1.6 この行の処理が終わったので、次の行を読み込む。

2. "a>b>c>E" の行
  2.1 直前の "a>b>c>D" と比較して、4階層中、"a>b>c" までの 3階層が一致。
  2.2 3階層目の"a>b>c" を取得し、その下に 4階層目の "a>b>c>E" を登録。
  2.3 この行の処理が終わったので、次の行を読み込む。

3. "a>b>X>Y>Z" の行
  3.1 直前の "a>b>c>E" と比較して、5階層中、"a>b" までの 2 階層が一致。
  3.2 2階層目の"a>b" を取得し、その下に 3階層目の "a>b>X" を登録。
  3.3 さらにその下に、4階層目の "a>b>X>Y" を登録。
  3.4 さらにその下に、5階層目の "a>b>X>Y>Z" を登録。
  3.5 この行の処理が終わったので、次の行を読み込む。

4. "a>b>X>o>p" の行
  4.1 直前の "a>b>X>Y>Z" と比較して、5階層中、"a>b>X" までの 3 階層が一致。
  4.2 3階層目の"a>b>X" を取得し、その下に 4階層目の "a>b>X>o" を登録。
  4.3 さらにその下に、5階層目の "a>b>X>o>p" を登録。
  4.4 この行の処理が終わったので、次の行を読み込む。

5. "L>M>N" の行
  5.1 直前の "a>b>X>o>p" と比較して、5階層中、0 階層が一致。(すべて不一致)
  5.2 ルートノードを取得し、その下に 1階層目の "L"を登録。
  5.3 さらにその下に、2階層目の "L>M" を登録。
  5.4 さらにその下に、3階層目の "L>M>N" を登録。
  5.5 この行の処理が終わったので(以下略)


たうお  2006-03-21 09:04:52  No: 130736

早速のご丁寧なご返答、どうもありがとうございます!
只今かなり感激しております!!

早速参考にさせて頂きたいと思います。
最初、MakeSureDirectoryPathExistsを使ってフォルダを作れば
既存のサンプルでもいけるかなぁと考えていたのですが、
中にはフォルダに適さない文字も含まれていたために断念しました。

実はこれはヤフーオークションストアのカテゴリ一覧ファイルなのです。
こんなにカテゴリ増やさなくてもいい気もしますが・・(^^;

とりあえず処理時間は二の次で頑張ります!

有難うございました。

#If TreeView1.Nodes("キー") Is Nothing Then 〜
#みたいなものが使えれば・・残念です


魔界の仮面弁士  2006-03-21 11:39:32  No: 130737

> #If TreeView1.Nodes("キー") Is Nothing Then 〜
> #みたいなものが使えれば・・残念です
無ければ作りましょう。それがプログラムの醍醐味。

Dictionaryオブジェクトなどを用いて、ノードの登録時に、
そのキーを記録しておけば、後からExistsメソッドで検索できますよね。


たうお  2006-03-23 04:20:21  No: 130738

> 魔界の仮面弁士さま
お陰様で大分ノードの追加が出来てきました。(かなり遅いですが・・)
一度全てのノードを追加してみようと思い、数時間かかって
ノード数が32000台(2^15)近辺になるとエラーが出てしまいました。
具体的には、Nodes.Countにマイナス値が入っている状態です。

という事はTreeViewコントロールにはノードの上限はここら辺なのでしょうか?
カスタムドローしたTreeViewはどうなのでしょう・・。
ちょっとカスタムドローのサンプルでノードを追加してやってみようと思います。

# カスタムドロー表示までしかサンプルがなく、イベントや状態の取得が壁です(^^;

うーん


魔界の仮面弁士  2006-03-23 06:23:14  No: 130739

> 一度全てのノードを追加してみようと思い、数時間かかって
最初は、ノードをすべて折りたたんだ状態で表示しておき、そのノードが
展開される時(Expand イベント)に、動的にロードするという手もありますね。
(フォルダ階層を表示する際に、この手をよく利用しています)

で、それと同様の話として、
  http://btmtz.mvps.org/index.html
の [VBTreeView] - [TVFastLoad] にあるように、LVN_GETDISPINFO で
という手もありますが……いずれにしても、件数が多すぎかも。(^^;

> ノード数が32000台(2^15)近辺になるとエラーが出てしまいました。
> 具体的には、Nodes.Countにマイナス値が入っている状態です。
戻り値が Integer 型ですからね……。

CInt(&h7FFD) → +32765 
CInt(&h7FFE) → +32766 
CInt(&h7FFF) → +32767 
CInt(&h8000) → -32768 
CInt(&h8001) → -32767 
CInt(&h8002) → -32766

> カスタムドローしたTreeViewはどうなのでしょう・・。
試す価値はあるかと思いますが、それでも厳しいかも知れません。

TreeView には、ListView と違って Virtual モードが無い(と思う)ので、
先述の LVN_GETDISPINFO /  LVN_DELETEITEM を使って動的に処理したと
しても、ノードを [*]キーなどでを全展開すれば、結局はそれだけの
件数を登録する事になり、やはりリソースを圧迫してしまう気がします。

ちょっと変わった実装としては、 http://btmtz.mvps.org/ の
[VBListView] - [LVItemTree] のようにすれば、もしかしたら、
リソースを圧迫せずに済むかもしれません。
# 使い勝手が異なるのが難点ですけれどね。


たうお  2006-04-02 11:05:00  No: 130740

ご無沙汰してしまいました。
ちょっと本業のほうで休み無くばたばたと・・。

ちょっと試してみた結果、やはり全てを一つのTreeViewで表示させるのは
かなり厳しいと判断いたしました。
なので正攻法(?)なListViewをお供に使いやってみる方法をとってみようと
思います。

> ちょっと変わった実装としては、 http://btmtz.mvps.org/ の
> [VBListView] - [LVItemTree] のようにすれば、もしかしたら、
> リソースを圧迫せずに済むかもしれません。
こ、これは思いも尽きませんでした(^^;すごいですねぇ〜
私の発想力がもう少し(いやもっと)柔軟であればこれを使って・・
というのが出来たのでしょうねぇ。

これからも時間の許す限り精進したいと思いますのでまたよろしく
お願い致します。
この件に関しましては解決済みとさせて頂きます。

魔界の仮面弁士様、ありがとうございました!!


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加