ノードの親子関係について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
いけやん

ノードの親子関係について

#1

投稿記事 by いけやん » 17年前

以前にもお世話になったいけやんです。
また、質問さして頂きます。

環境はWinXp
VC6.0 MFC

CTreeCtrlで文字等を親子関係にする処理で悩んでいます。

前までは、
 m_HndTree[0] = m_tree.InsertItem(あああ,TVI_ROOT);
 m_HndTree[1] = m_tree.InsertItem(いいい,m_HndTree[0]);
 m_HndTree[2] = m_tree.InsertItem(ううう,m_HndTree[1]);
 m_HndTree[3] = m_tree.InsertItem(えええ,m_HndTree[1]);

実行結果
--あああ
¦-いいい
¦-ううう
¦-えええ

上記の様な処理でベタ書きで親子にしていたのですが
それをテキストに格納して
テキストから、読み込み表示し親子関係にする処理を考えているのですが
以前質問さして頂いた時に表示までは、うまくいきました。
そこからの、親子関係にするアイデアが中々浮びません。

どなたか、いいアイデアをお持ちではないでしょうか?
どうぞよろしく、お願い致します。

今現在のソースです。
for(
){
 m_HndTree[0] = m_tree.InsertItem(String,TVI_ROOT);//あああ
 m_HndTree[1] = m_tree.InsertItem(String,m_HndTree[0]);//あああ
 m_HndTree[2] = m_tree.InsertItem(String,m_HndTree[1]);//あああ
 m_HndTree[3] = m_tree.InsertItem(String,m_HndTree[1]);//あああ
}

テキストの中
あああ
いいい
ううう
えええ
現在の実行結果
+あああ
¦+あああ
+あああ
+あああ

御津凪

Re:ノードの親子関係について

#2

投稿記事 by 御津凪 » 17年前

方法として挙げるならば、再帰関数を使うと楽かもしれません。
それと、読み込むテキストに親子関係を示さないと、
プログラムの方でどう処理すればいいか分からなくなります。

一応、処理は while 文でも可能だと思います。
コードが複雑になりますが、バグ等でスタックオーバーフローを起こすより安全です。

いけやん

Re:ノードの親子関係について

#3

投稿記事 by いけやん » 17年前

御津凪さん、
すいません、まず再帰関数から調べてました。
再帰関数または、再帰処理を呼ぶらしいです。
自分自身の関数をその内部で呼び出す事みたいですね。

回答の質問は、あまりよくない事は解っているのですが
質問さして頂きます。

その再帰処理をする事によって意味(効果?)みたいな事があるのですか?
調べ不足ならすいません。

>それと、読み込むテキストに親子関係を示さないと、
>プログラムの方でどう処理すればいいか分からなくなります。
上記はどういう事でしょうか?
もう少し崩して貰っていいですか?

すいません。お手数ですがよろしくお願いします。

いけやん

Re:ノードの親子関係について

#4

投稿記事 by いけやん » 17年前

>その再帰処理をする事によって意味(効果?)みたいな事があるのですか?
間違っていたら、すいません。

メリット的な物で調べていたら、
「前の繰り返し結果を使用して同じ演算を
複数回数繰り返すアルゴリズムによって
問題を解決できる場合に便利です。」
上記の様な事が書いてありました。
その他を見ても同じ様な事が書いてありました。

だとすると、小さい親子関係だと再帰処理も必要ないのかもしれませんが
同じ処理の繰り返しで、親と子をひたすら割り当てる処理の時は有効という解釈で合っていますか?

御津凪

Re:ノードの親子関係について

#5

投稿記事 by 御津凪 » 17年前

> >それと、読み込むテキストに親子関係を示さないと、
> >プログラムの方でどう処理すればいいか分からなくなります。
> 上記はどういう事でしょうか?
> もう少し崩して貰っていいですか?
たとえば、読み込むテキストが、
あああ
いいい
ううう
えええ
だと、どれが親でどれが子なのか分かりません。
あああ
  いいい
  ううう
  えええ
とすると、「あああ」が「いいい」・「ううう」・「えええ」の親だと字下げで表現できますよね。

つまり、テキストデータに親子関係の情報を含めないと、
いざ読み込もうとしても、どれがどの親か判別できません。
(一番最初の行がルートとすることはできますが。)

次に再帰処理の方ですが、

> だとすると、小さい親子関係だと再帰処理も必要ないのかもしれませんが
> 同じ処理の繰り返しで、親と子をひたすら割り当てる処理の時は有効という解釈で合っていますか?

それであっていると思います。

再帰処理はアルゴリズムで使用することが多いので、
普段は使うことが少ないかもしれません。
たとえば、2の乗数を計算する時、 while 文を使用すると、
int pow2( int a ){
	int n;
	if(a <= 0) rerurn 0;
	n = 1;
	while(a > 0){
		n*=2;
		--a;
	}
	return n;
}
のようになりますが、再帰処理を行うようにすると、
int pow2( int a ){
	if(a <= 0) rerurn 0;
	else if(a == 1) rerurn 2;
	else return pow2(a-1)*2;
}
このように短く済みます。
(正しく動くかは未確認です)
一番の利点は、作業用に利用する一時変数が減るのと、
プログラムの行数が減り、実行ファイルのサイズが小さくなる点が挙げられます。

欠点としては、使い方を間違えると簡単に無限ループに陥ってスタックオーバーフローを起こすことや、
ぱっと見何をしているのか分からない、等があります。

今回の親子関係の問題では、
あああ
 いいい
  ううう
   えええ
    おおお
     …
のような場合、追加するための親への変数を保持するのが非常に面倒です。
(スタックを使えば可能ではありますが)

そこで再帰処理を使用します。
関数の引数を使用すれば、いくら深い子があっても、
1. 親に子を追加
2. 1.で追加した子にさらに子(孫)が存在する場合は再帰で関数を呼ぶ(子を親として、孫を子として渡す)
3. 親に追加する子が他にあれば1.へ
4. なければ終了
の処理をする関数を用意するだけで事足ります。
実際はもっと複雑になると思いますが…。

最後に、ずいぶんと長くなってしまいましたが、理解できましたでしょうか?

いけやん

Re:ノードの親子関係について

#6

投稿記事 by いけやん » 17年前

御津凪さん、ありがとうございます。

>つまり、テキストデータに親子関係の情報を含めないと
--------+------------------------------------
02-00-00|《あああ》 ROOTになる物 親
02-01-00| いいい[い] FIRST 子
02-01-01| ううう LAST 孫
02-01-01| ええええ LAST 孫
02-01-01| おお/お LAST   孫
02-02-00| かかか FIRST 子
02-02-01| きき LAST 孫
02-02-01| くくくくく LAST 孫
02-02-01| けけけ LAST    孫
--------+------------------------------------
こういう感じですかね・・・(自信なし)

>最後に、ずいぶんと長くなってしまいましたが、理解できましたでしょうか?
御津凪さんの説明上では、何となくですが解りました。

ですが、不安要素がいくつかあり、
①再帰処理をやった事がない。
②02-01-01といった形で親子関係にするのか
CString等で02-01-01を丸ごと、とって来て
char等で、1個ずつ格納していき
最初が0、次が2,'-'飛ばして、又0,次が1なら子供にする
みたいな処理にするのか?

こんな感じで、ちょっと混乱していますね。
とりあえず、処理を書いてから返信したいと思います。

いけやん

Re:ノードの親子関係について

#7

投稿記事 by いけやん » 17年前

返信遅くなりました。
まず下記の処理をしようとし最初から躓きました。
>1. 親に子を追加

コンパイルエラーはないのですがツリーに何も表示されないので
×ボタンを押して終わろうとすると「中止」「再試行」「無視」等のウィンドウが出てきます。
ソースの方に致命的なバグがあると思うのですが、自分では見つけられないので
お力添えをお願いします。

下記の処理を加えるまでは、動いていたのでここだと思います。

num = str.Mid(4,6);
if(num == "00"){m_HndTree[n] = m_tree.InsertItem(String,TVI_ROOT);++n;}//親か
else if(num == "01"){m_HndTree[--n] = m_tree.InsertItem(String,m_HndTree[0],TVI_FIRST);++n;}//子か
else{m_HndTree[n] = m_tree.InsertItem(String,m_HndTree[--n],TVI_LAST);}//孫

テキストの中身
-----+------------------------------------
02-00|《垂木エディタ》
02-01| 垂木台[群]
02-02| 部材集計表
02-02| 平面割付図
02-02| 単品制作図
02-01| 野地下地
02-02| 部材集計表
02-02| 平面割付図
02-02| 単品制作図
-----+------------------------------------

いけやん

Re:ノードの親子関係について

#8

投稿記事 by いけやん » 17年前

すいません。先ほどの件なのですが
表示されないのは、解決しました。
>num = str.Mid(4,6);
上記でとってくる位置が違っていました。
デバックで走らすとnumの中が"00|<<垂木"まで入っていました。

なのでnum = str.Mid(3,2);しました。
numの中も"00"なっていました。

ですが、下記はまだ直っていません。
>×ボタンを押して終わろうとすると「中止」「再試行」「無視」等のウィンドウが出てきます。
>ソースの方に致命的なバグ
よろしくお願いします。

御津凪

Re:ノードの親子関係について

#9

投稿記事 by 御津凪 » 17年前

> ×ボタンを押して終わろうとすると「中止」「再試行」「無視」等のウィンドウが出てきます。
多分そのウインドウはランタイムエラーのダイアログで、
上記のプログラムから察するに、 m_HndTree の許容配列を超えて処理してしまっているのではないでしょうか。


まず、上記のコードを1命令1行に直し、デバッグモードのステップ実行で、
n の値を確認してみるといいと思います。

私の予想では、親を追加する時は0番に格納されるのであっていると思いますが、
次の子の追加で、先に --n が評価されるので、0番に格納されてしまうと思います。


…まさか、

-----+------------------------------------

はテキストに入っていませんよね?
入っているとしたら読み飛ばしていますか?
読み飛ばさないとこの行が孫として処理されてしまいます。
(--n で n が負数になる)

いけやん

Re:ノードの親子関係について

#10

投稿記事 by いけやん » 17年前

御津凪さん。ありがとうございます。

>-----+------------------------------------
>入っているとしたら読み飛ばしていますか?
これは、読み飛ばしていました。

言うとおりnの中を一つ一つ確認した所始めは0でうまくいくのですが
--した後に++しているので、0に格納されていました。
-1に直しました。

if(num == "00"){m_HndTree[n] = m_tree.InsertItem(String,TVI_ROOT);++n;}
else if(num == "01"){m_HndTree[n-1] = m_tree.InsertItem(String,m_HndTree[0],TVI_FIRST);++n;}
else{m_HndTree[n] = m_tree.InsertItem(String,m_HndTree[n-1],TVI_LAST);}

結果>ランタイムエラーのダイアログ
も出なくなりました。

余談ですが、前に御津凪さんが立てたスレをこっそり見ていまして、
i++より++iの方がいいという事を知ってそれから
++i --i 前置を使う様になりました。

御津凪

Re:ノードの親子関係について

#11

投稿記事 by 御津凪 » 17年前

> 結果>ランタイムエラーのダイアログ
> も出なくなりました。

と言うことはちゃんと表示されたのですか?

> 余談ですが、前に御津凪さんが立てたスレをこっそり見ていまして、
> i++より++iの方がいいという事を知ってそれから
> ++i --i 前置を使う様になりました。

読んで頂いてありがとうございます。

今回の問題で使い方の勉強にもなったのだろうと思います。

いけやん

Re:ノードの親子関係について

#12

投稿記事 by いけやん » 17年前

>読んで頂いてありがとうございます。
いえいえ、こちらこそありがとうございます。勉強になります。

>今回の問題で使い方の勉強にもなったのだろうと思います。
そうですね、こういう事は自分で一回失敗した方が身しみていいですね。

>と言うことはちゃんと表示されたのですか?
う~ん答えはNoですね
《垂木エディタ》親                    
   垂木台[群]    子                  
    部材集計表   孫                   
    平面割付図   孫                   
    単品制作図   孫                 
   野地下地      子                    
    部材集計表   孫                 
    平面割付図   孫                 
    単品制作図  孫
にしたいのですが、現在の実行結果は
《垂木エディタ》親                    
   垂木台[群]  子 
     野地下地  孫
  部材集計表   親                 
  平面割付図   親                 
  単品制作図  親
表示位置がずれていて、さらに親子関係もおかしいので
ソースをデバックで確認してみます。

御津凪

Re:ノードの親子関係について

#13

投稿記事 by 御津凪 » 17年前

「野地下地」が孫なのは前の子の追加の時、親が格納されていた0番に子が入っているためだと思います。

最初の三つの孫がないのは、格納されていない(何も入っていない)番号を親としているからでしょう。

順を追うと、

親を n(0) 番に追加し、 ++n(1) 。
子を 0 番を親として n-1(0) 番に追加し、 ++n(2)。
孫を n-1(1) 番を親として n(2) 番に追加。



となっているはずです。
※カッコ内は n の計算結果

子を入れるときの処理の ++n をなくし、
孫の親を n にし、 孫の入れる場所を n+1 にすると
うまくいくのではないでしょうか?

ふと、思ったのですが、
親、子、孫の三つだけであれば、
3つの配列を用意して、
0番 : 親
1番 : 子
2番 : 孫
のように決めて入れる様にする方が早いかもしれません。
(実際、両方とも同じ感じに格納されていくので)

いけやん

Re:ノードの親子関係について

#14

投稿記事 by いけやん » 17年前

遅くなりました。
かなり混乱しました(今も)

>孫の親を n にし、 孫の入れる場所を n+1 にすると
上記の処理にすると表示結果は、

《垂木エディタ》親
垂木台[群] 子
部材集計表 子
平面割付図 子
単品制作図 子
野地下地 子
部材集計表 子
平面割付図 子
単品制作図  子
になりました。

>孫の入れる場所を n+1 にすると
この処理は正しいみたいです。

>孫の親を n にし
これは、前の処理で加算されたnがそのまま入るので
実行結果
《垂木エディタ》親
垂木台[群] 子
部材集計表 孫
平面割付図 曾孫
単品制作図 玄孫(やしゃご)
野地下地 玄姪孫(げんてっそん)
部材集計表 来孫(らいそん)
平面割付図 昆孫(こんそん)
単品制作図  仍孫(じょうそん)

なので、下記の処理でうまくいきました。

num = str.Mid(3,2);
if(num == "00"){m_HndTree[n] = m_tree.InsertItem(String,TVI_ROOT);n+1;}
else if(num == "01"){m_HndTree[n-1] = m_tree.InsertItem(String,m_HndTree[0]);n+1;}
else{ m_HndTree[n+1] = m_tree.InsertItem(String,m_HndTree[n-1]);n+1;}

実行結果
《垂木エディタ》親
垂木台[群] 子
部材集計表 孫
平面割付図 孫
単品制作図 孫
野地下地 子
部材集計表 孫
平面割付図 孫
単品制作図  孫

御津凪

Re:ノードの親子関係について

#15

投稿記事 by 御津凪 » 17年前

何か良くわからない書き方だったのですいませんでした。(汗
うまく行ったのは良かったですね。

しかし、上記のコードで、
n+1;
は、無意味なコードです。
(式を受け取る変数がない)

このコードだと、 n が 0 のままなので、
m_HndTree[-1] : 親のデータ
m_HndTree[ 0] : 子のデータ
m_HndTree[ 1] : 孫のデータ
となっているかと思います。

P.S
そこまで子の呼び方があるんですか!?
知りませんでした…。

いけやん

Re:ノードの親子関係について

#16

投稿記事 by いけやん » 17年前

おはようございます。

>しかし、上記のコードで、n+1;は、無意味なコードです。
確かにそうですね。
実際の所nは値的にいえばずっと0ですもんね。

という事は、カウントアップ用(インクリメント、デクイメント)専用の

変数を用意した方がいいですかね?

後ですね。ちょっと聞きたいのですが。
>ふと、思ったのですが、
>親、子、孫の三つだけであれば、
>3つの配列を用意して、
省略

確かに親子関係でいえば
親、子、孫までの3つの関係しか今のところありません。

上記の事は、どういう事でしょうか?

テキストの中を
"00"→"0"親
"01"→"1"子
"02"→"2"孫
に変えるとかでしょうか?

理解力がなくてすいません(涙
よろしく、お願いします。

御津凪

Re:ノードの親子関係について

#17

投稿記事 by 御津凪 » 17年前

おはようございます。

> 3つの配列を用意して、
の部分は、正確に言うと、親子関係を設定するための変数(m_HndTree)の配列を3として、
m_HndTree[0] = 親
m_HndTree[1] = 子
m_HndTree[2] = 孫
を、それぞれ格納する様に処理を行うということです。
int i = atol(num); // 文字列から数字へ
m_HndTree = m_tree.InsertItem(String,(i == 0)?TVI_ROOT:m_HndTree[i-1]);


コードはこんな感じになります。
このコードは処理可能な親子のレベルが配列と比例します。
ある程度深さが分かっていればそれに合わせて配列を用意すれば済みますが、
深さが不明な場合、配列の長さをいくら大きくしてもエラーが発生する恐れがあります。

エラーを発生させないようにするには、再帰処理が楽です。

つまり、親子関係の深さが分かっていれば、再帰処理なんて面倒なことはせずに
済むということです。

(そういえば、コードからインクリメントやデクリメントが無くなってた)

いけやん

Re:ノードの親子関係について

#18

投稿記事 by いけやん » 17年前

御津凪さん。サンプルありがとうございます。

子、孫の処理は下記の様な感じですかね?

num = str.Mid(3,2);//切り出し
n = atol(num);//文字列から数字へ変換
m_HndTree[n] = m_tree.InsertItem(String,(n == 0)?TVI_ROOT:m_HndTree[n-1]);++n;
m_HndTree[n] = m_tree.InsertItem(String,(n == 1)?m_HndTree[n-1]);++n;//エラー
m_HndTree[n] = m_tree.InsertItem(String,(n == 2)?m_HndTree[n-1]);++n;//エラー
御津凪さんが書いてくれた所は通るのですが
子と孫の処理は下記の様なエラーが出ます。

',' が ')' の前に必要です。
なので ,や :を付けてもその部分がエラーで怒られます。
どう解決したらいいのでしょか?
すいませんが、お願いします。


>m_HndTree = m_tree.InsertItem(String,(i == 0)?TVI_ROOT:m_HndTree[i-1]);

>(i == 0)?部分
こんな書き方できるんですか、知りませんでした。
自分なりの解釈では、if(i==0)と一緒かな?
と思っています。

御津凪

Re:ノードの親子関係について

#19

投稿記事 by 御津凪 » 17年前

m_HndTree = m_tree.InsertItem(String,(i == 0)?TVI_ROOT:m_HndTree[i-1]);

は、
if(i == 0){
	m_HndTree = m_tree.InsertItem(String,TVI_ROOT);
}else{
	m_HndTree = m_tree.InsertItem(String,m_HndTree[i-1]);
}


と、同等です。
上記の記法は「三項演算子」といって、

式 ? 式が真の場合に評価する部分 : 式が偽の場合に評価する部分

となっています。

エラーになっているのは、":"と片方の式がなく、構文として合っていないためです。
それを直せば(消すと)エラーはなくなりますが、このコードだと、
同じ文字列を親、子、孫にそれぞれ追加してしまいます。

なので、
num = str.Mid(3,2);//切り出し
int n = atol(num); // 文字列から数字へ
m_HndTree[n] = m_tree.InsertItem(String,(n == 0)?TVI_ROOT:m_HndTree[n-1]);
// ↑指定された番号に追加

だけで、いいはずです。
切り出した文字列(数字)はそのまま親子関係の深さになるので、
インクリメントやデクリメントは一切不要になります。

一応、上記の処理している意味は理解しているでしょうか?

三項演算子は処理の優先度の関係のせいで、意図しない結果になったりします。
もし使うとしたら、
m_HndTree[n] = m_tree.InsertItem(String,((n == 0)?TVI_ROOT:m_HndTree[n-1]));

と、括弧で囲む癖をつけると良いと思います。

いけやん

Re:ノードの親子関係について

#20

投稿記事 by いけやん » 17年前

>上記の記法は「三項演算子」といって
勉強になります。

>一応、上記の処理している意味は理解しているでしょうか?
う~んと、ですね。
大体は理解したのですが・・・
どうしても下記の部分が自分的には、納得?(理解?)していません。

>切り出した文字列(数字)はそのまま親子関係の深さになるので、
>インクリメントやデクリメントは一切不要になります。

m_HndTree[n] = m_tree.InsertItem(String,((n == 0)?TVI_ROOT:m_HndTree[n-1]));
この処理でいえば

m_HndTree[n]の部分が
例えば70まであったとすれば,
自分的には、
[0] [n]//1
[1] [n]//2
[2]→[n]//3



[70]→[n]//70
振り当てていくから、++nカウントアップ(インクリメント)の処理は必要ではないんでしょうか?
頭が固くて、すいません。
お願いします。

御津凪

Re:ノードの親子関係について

#21

投稿記事 by 御津凪 » 17年前

確か、 m_HndTree は InsertItem 関数で<u>親を指定するためだけ</u>の変数のはずなので、
n を数値に置き換えた時、
親("00")の場合、
m_HndTree[0] = m_tree.InsertItem(String,((0 == 0)?TVI_ROOT:m_HndTree[0-1]));
↓
m_HndTree[0] = m_tree.InsertItem(String,TVI_ROOT);
で、0番に親が格納されます。

子("01")の場合、
m_HndTree[1] = m_tree.InsertItem(String,((1 == 0)?TVI_ROOT:m_HndTree[1-1]));
↓
m_HndTree[1] = m_tree.InsertItem(String,m_HndTree[0]);
で、0番を親として1番に子が格納されます。

孫("02")の場合、
m_HndTree[2] = m_tree.InsertItem(String,((2 == 0)?TVI_ROOT:m_HndTree[2-1]));
↓
m_HndTree[2] = m_tree.InsertItem(String,m_HndTree[1]);
で、1番を親(親の子)として2番に孫が格納されます。
…と、続いていきます。

単純に親子関係を構築する場合は、 m_HndTree の配列を項目の数だけ用意するといったことは不要です。

いけやん

Re:ノードの親子関係について

#22

投稿記事 by いけやん » 17年前

すいません。何か勘違いをしていたみたいです。

解っているかどうかの自分なりの説明書いてみます。
まず、
>m_HndTree[n] = m_tree.InsertItem(String,((n == 0)?TVI_ROOT:m_HndTree[n-1]));
>この処理でいえば
>m_HndTree[n]の部分が
この部分は,atol関数で数字に変換しているから
0,1,2が順番に入っていくんですね。
n = atol(num);//nに0,1,2が代入される
m_HndTree[n]//0
m_HndTree[n]//1
m_HndTree[n]//2
で、私の言っていた
>[0] [n]//1
>[1] [n]//2
>[2]→[n]//3
>:
>:
>:
>[70]→[n]//70
>単純に親子関係を構築する場合は、 m_HndTree の配列を項目の数だけ用意するといったことは不要です。
これは、親、子、孫までの関係しかないので
例え100,200,300,・・・になっても
0~100を割り当てるのではなく、
親、子、孫の関係の0,1,2を振り分けて
その100個分を0,1,2で管理(親子関係)にするという事合っていますか?

すいません。馬鹿(自分なり)の説明なので解りにくいと思います。

御津凪

Re:ノードの親子関係について

#23

投稿記事 by 御津凪 » 17年前

> これは、親、子、孫までの関係しかないので
> 例え100,200,300,・・・になっても
> 0~100を割り当てるのではなく、
> 親、子、孫の関係の0,1,2を振り分けて
> その100個分を0,1,2で管理(親子関係)にするという事合っていますか?

その通りです。
もちろん、ひ孫までの関係を作るなら0(親)、1(子)、2(孫)、3(ひ孫)の、
4つの配列で管理することになりますね。

> すいません。馬鹿(自分なり)の説明なので解りにくいと思います。

そんなことはありませんよ。

いけやん

Re:ノードの親子関係について

#24

投稿記事 by いけやん » 17年前

すいません。返信遅くなりました。

御津凪さん。表示はうまくいきました。
ありがとうございます・

ですが、今まで動いていた機能が正しく動作しなくなったので
今から自分なり考えて
また明日、返信したいと思います。

いけやん

Re:ノードの親子関係について

#25

投稿記事 by いけやん » 17年前

こんにちは。
自分なりに考えたのですが、解らないので質問します。

>今まで動いていた機能が正しく動作しなくなったので
上記の件なのですが、
今までボタンを何個は貼り付けていたのですが、
いくつかは動くのですが、数個は正しく機能しなくなりました。

そのボタンの処理の内容は
//全ノード展開
//全ての折りたたまれているノードを展開する
void CVctreeDlg::OnButton2() 
{
	for(int k = 0 ; k < 3 ; ++k){
		m_tree.Expand(m_HndTree[k],TVE_EXPAND);
	}
}


//全ノード圧縮
//全てのノードを折りたたむ
void CVctreeDlg::OnButton3() 
{
	for(int k = 0 ; k < 3 ; ++k){
		m_tree.Expand(m_HndTree[k],TVE_COLLAPSE);
	}
}


//全選択ボタン
//全てのノードにチェックを付ける
void CVctreeDlg::OnButton4() 
{
	for(int k = 0 ; k < 3 ; ++k){
		m_tree.SetCheck(m_HndTree[k],TRUE);
	}
}


//全チェック解除
//全てのノードのチェックをはずす
void CVctreeDlg::OnButton5() 
{
	for(int k = 0 ; k < 3 ; ++k){
		m_tree.SetCheck(m_HndTree[k],FALSE);
	}
}
前までは下記の様に、ベタ書きで入れていたので
m_HndTree[0~70]=m_tree.InsertItem(String,m_HndTree[4]);

#define LOOPMAX 70
for(int k = 0 ; k < LOOPMAX ; ++k){
m_tree.Expand(m_HndTree[k],TVE_EXPAND);
}
でうまくいっていたのですが
テキストから読み込みができる様になってから正しく動作しません。

自分的には、0,1,2で親子付けしているので、0~2まで
for()で回せばいけると思ったのですが、違うみたいです。

お手数ですが、よろしくお願いします。

御津凪

Re:ノードの親子関係について

#26

投稿記事 by 御津凪 » 17年前

m_HndTree は、あの処理では親子関係を示すために使用したため、
これでは最後に格納された親・子・孫しか操作できません。

全ての項目に対して行う場合、全ての項目を読み込み時に確保する方法と、
再帰処理を書く方法があります。
前者だと沢山項目があるとその分メモリを消費してしまうので、
後者の再帰処理を書いておきます。
void handle_children( CTreeCtrl* tree, HTREEITEM item ){
	HTREEITEM child;
	if(tree->ItemHasChildren(item)){ // 子があるかどうか
		child = tree->GetChildItem(item); // 最初の子を取得
		while(child != NULL){ // 全ての子に対して処理する
			/* ココで child に対して処理 */
			paycode(tree,child); // 再帰処理
			child = tree->GetNextItem(child,TVGN_NEXT); // 次の子を取得
		}
	}
}
私はMFCを使ったことがないので、MSDNを見ながら書きました。
ミスがあるかも知れませんが、このような処理で大丈夫のはずです。

御津凪

Re:ノードの親子関係について

#27

投稿記事 by 御津凪 » 17年前

間違ってました。

paycode(tree,child); // 再帰処理

ではなく、

handle_children(tree,child); // 再帰処理

でした。

いけやん

Re:ノードの親子関係について

#28

投稿記事 by いけやん » 17年前

御津凪さん。何度もすいません。

'handle_children' : ローカル関数の定義が正しくありません。
というエラーが回避できません。

ソースです。
//全ノード展開
void CVctreeDlg::OnButton2() 
{
	//再帰処理(再帰関数)
    void handle_children(CTreeCtrl* tree, HTREEITEM item){

	HTREEITEM child;

	   if(tree->ItemHasChildren(item)){//子があるかどうか

		child = tree->GetChildItem(item)//最初の子を取得

		    while(child != NULL){//全ての子に対して処理する

			/*ココでchildに対して処理*/
			m_tree.Expand(m_HndTree[n],TVEEXPAND);
			handle_children(tree,child);//再帰処理
			child = tree->GetNextItem(child,TVGN_NEXT);//次の子を取得

		   }
	   }
   }

}
自分では、void CVctreeDlg::OnButton2()に
入れる事が間違っているのかと思ったり
void handle_childrenを外に出したりしたのですが
違うみたいです。
素人な質問ですいませんが、お願いします。

御津凪

Re:ノードの親子関係について

#29

投稿記事 by 御津凪 » 17年前

> 自分では、void CVctreeDlg::OnButton2()に
> 入れる事が間違っているのかと思ったり

関数の中に関数は書けません。

再帰処理を行う関数は他と全く同じ関数なので、特別扱いというものはありません。

それと、変数 child は、再帰処理により全ての項目をたどるので、
コメント通り、 child に対して展開などの処理を行います。
よって、
m_tree.Expand(m_HndTree[n],TVEEXPAND);
は、
m_tree.Expand(child,TVEEXPAND);
となります。

> void handle_childrenを外に出したりしたのですが

CVctreeDlg クラスの定義にこの関数を宣言して、
CVctreeDlg::handle_children として関数を定義してみてください。
(関数名は自由につけられますので、他の関数名にあった名前をつけてください)

一応、クラスメンバの書き方は理解していますでしょうか?

グローバル関数として定義してもいいのですが、クラスメンバとしておいたほうが
効率が良いです。

いけやん

Re:ノードの親子関係について

#30

投稿記事 by いけやん » 17年前

御津凪さん。返信遅くなりました。
え~とですね。

正直にいいますと。
関数の使い方、作り方など、怪しい部分あります。
(大体の感じ等は解っているのですが)
自分で関数等を作った事がなく改めて解ってない事が解りました。

当然、再帰処理の所が解らなくなって来たので
このまま質問を続けても
御津凪さんに迷惑を掛けるので、

明日、「関数の作り方」「再帰処理」「VC++」
この辺りの参考書を買って勉強して出直してきます。

自分的に調べもせず質問をするのはよくないと思うので、
素人、初心者、質問者でも最低限(解らないなら解らないなりに)
調べてから質問すべきなので。

>一応、クラスメンバの書き方は理解していますでしょうか?
これもあまり解らないですね。
違うならすいません。
ヘッダ、もしくは#includeの下の辺り(グローバル)
とこら辺に
void handle_children(CTreeCtrl* tree,HTREEITEM item);
宣言してhandle_childrenという関数
を使いますよー。
という宣言の事ではないですよね?

御津凪

Re:ノードの親子関係について

#31

投稿記事 by 御津凪 » 17年前

> ヘッダ、もしくは#includeの下の辺り(グローバル)
> とこら辺に
> void handle_children(CTreeCtrl* tree,HTREEITEM item);
> 宣言してhandle_childrenという関数
> を使いますよー。
> という宣言の事ではないですよね?

これは関数宣言ですね。
CやC++では、これをしないとエラーが出ることがあります。

> 明日、「関数の作り方」「再帰処理」「VC++」
> この辺りの参考書を買って勉強して出直してきます。
>
> 自分的に調べもせず質問をするのはよくないと思うので、
> 素人、初心者、質問者でも最低限(解らないなら解らないなりに)
> 調べてから質問すべきなので。

確かにそのほうがいいでしょう。
ただし、分厚い入門書や参考書は余りお勧めできませんね。
途中で投げ出してしまう可能性が高いので。

こちらのログを参考にするといいと思いますよ。

http://www.play21.jp/board/formz.cgi?ac ... &rln=19877
Title:オススメの本は?

あと、このスレを一旦止める場合は(解決していなくても)解決マークをつけておいて、
新しく立て直したほうがいいでしょう。
(なぜか二人しか書いていないスレなので)

いけやん

Re:ノードの親子関係について

#32

投稿記事 by いけやん » 17年前

御津凪さん。
本のアドバイスありがとうございます。

>あと、このスレを一旦止める場合は(解決していなくても)解決マークをつけておいて、
>新しく立て直したほうがいいでしょう。
了解です。

>(なぜか二人しか書いていないスレなので)
そういえば、そういですね・・・なぜだ???
御津凪さんにしかお世話(もしくわ迷惑?)になってないですね(汗

御津凪さん、ありがとうございました。

後ですね。図々しいのですが、
また月曜にでも新しいスレを立てると思うので
時間があればで、いいので、
御津凪さんにも答えて頂ければうれしいです。
説明が解り易いので。

閉鎖

“C言語何でも質問掲示板” へ戻る