再帰処理(再帰関数)について

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

再帰処理(再帰関数)について

#1

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

いつも、お世話になっております、いけやんです。
タイトル通り「再帰処理、又は、再帰関数についての質問です」

環境
Windows XP sp2
VC++ MFC ダイアログです。

①今現在、テキストからデータを読み込み、
②それを親子関係にして、
③そして、全ての親子にチェックを付ける,(チェック)外す,展開する,圧縮する
ちなみにチェック付ける(外す)は解っていただけると思います(汗
展開するは
+aaa→ーaaaa
│-iii
│-uuu
圧縮は逆です。(-→+)

上記にある①②はココで質問さして頂き解決したのですが

③でうまく行かず困っています。
どなたか、お力添えをお願い致します。
また、最近やっと関数の作り方や処理を勉強したので
至らない所も多々ありますが、アドバイス等でもいいので
よろしくお願い致します。

後ほど、ソース乗せます。

いけやん

Re:再帰処理(再帰関数)について

#2

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

関数宣言
void All_Node_Expand(HWND hWndTree,HTREEITEM hParent);
省略
:
:
void CVctreeDlg::All_Node_Expand(HWND hWndTree,HTREEITEM hParent){

	HTREEITEM hItem;

	//全アイテムに対して処理したいなら、ここに入れる
	hItem = TreeView_GetChild(hWndTree,hParent);//子アイテムを取得
	while(hItem){
		m_tree.Expand(hItem,TVE_EXPAND);//展開処理
		All_Node_Expand(hWndTree,hItem);//再帰処理
		hItem = TreeView_GetNextSibling(hWndTree,hItem);//兄弟アイテムを取得
	}
}

//全ノード展開
void CVctreeDlg::OnButton2() 
{
	HWND hWndTree;
	All_Node_Expand(hWndTree,TreeView_GetRoot(hWndTree));//ルートのアイテムを取得
}
上記の様なソースになっています。
コンパイルエラー等は出なく、普通に動くのですが
ボタン2を押しても全く処理がされません。
もしかして、関数の作り方等間違っていますでしょうか?
お手数ですが、お願い致します。

御津凪

Re:再帰処理(再帰関数)について

#3

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

hWndTree には何も設定されていないので、関数どおりに動きません。

HWND 型ということは、Win32API を使用しているのですね?

関数宣言の All_Node_Expand 関数はグローバル関数の宣言なので、
単に All_Node_Expand 関数を呼び出すと、グローバルの All_Node_Expand なのか、
CVctreeDlg クラスの All_Node_Expand なのかが分かりません。
コンパイルでは CVctreeDlg クラスの All_Node_Expand を呼び出していますが。

この場合、グローバルの関数がないので、関数宣言は不要です。
なので、削除したほうがいいです。
(コンパイラによってはエラーを返すものがあります)
確認のためですが、ヘッダファイルには、
class CVctreeDlg{
	/*色々省略...*/
	void All_Node_Expand(HWND hWndTree,HTREEITEM hParent);
	/*色々省略...*/
};
となっていますか?
この All_Node_Expand の部分がクラスメンバの関数宣言です。
(CVctreeDlg::All_Node_Expand はクラスメンバの関数です)

話を戻しますが、
hWndTree には、ツリービューコントロールのウインドウハンドルを入れなければ動きません。

バグ

Re:再帰処理(再帰関数)について

#4

投稿記事 by バグ » 17年前

とりあえず、試していただきたいのですが、OnButton2関数の中でどこでもいいので、ブレイクポイントを設定してみてください。

そして、そこでプログラムが止まらないようであれば、きちんとイベントハンドラが追加されていないことになります。(もし、既に試しているのならば、ごめんなさい)

いけやん

Re:再帰処理(再帰関数)について

#5

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

>VC++6.0 MFC ダイアログです。
思いっきり環境無視でした。
>HWND 型ということは、Win32API を使用しているのですね?
HWND 型はwin32API専用?の型なんですか?
何も知らずに書いていました。すいません。

なので前回、御津凪さんに提示して頂いたサンプルを使わせて頂きたいと思います。
ソースをコロコロと変えて申し訳ないです。
//再帰処理(再帰関数)
void CVctreeDlg::All_Node_Expand(CTreeCtrl* tree, HTREEITEM item){
		
	HTREEITEM child;
		
	if(tree->ItemHasChildren(item)){//子があるかどうか
			
		child = tree->GetChildItem(item);//最初の子を取得
				
			while(child != NULL){//全ての子に対して処理する
					
				/*ココでchildに対して処理*/
				m_tree.Expand(child,TVE_EXPAND);
				All_Node_Expand(tree,child);//再帰処理
				child = tree->GetNextItem(child,TVGN_NEXT);//次の子を取得
					
			}
	}
}
vctreeDlg.h内
class CVctreeDlg{
void All_Node_Expand(CTreeCtrl* tree,HTREEITEM item);
}

>関数宣言の All_Node_Expand 関数はグローバル関数の宣言なので、
>単に All_Node_Expand 関数を呼び出すと、グローバルの All_Node_Expand なのか、
>CVctreeDlg クラスの All_Node_Expand なのかが分かりません。
>コンパイルでは CVctreeDlg クラスの All_Node_Expand を呼び出していますが。
>この場合、グローバルの関数がないので、関数宣言は不要です。
すいません。まだ本の基本的な関数の作り方しか知らなくて。

>確認のためですが、ヘッダファイルには、
見抜かれてますね・・・(汗
ヘッダには書いていませんでした。
で書いたのですが、40個ぐらいエラーがでてきました。

バグさん。
>そして、そこでプログラムが止まらないようであれば、きちんとイベントハンドラが追加されていないことに
>なります。
ブレイクを張ったのですが、見事に通り抜けました。
なので、そのイベントハンドラに追加の仕方をご存知ですか?
お願い致します。

Mist

Re:再帰処理(再帰関数)について

#6

投稿記事 by Mist » 17年前

> なので、そのイベントハンドラに追加の仕方をご存知ですか?

一から十まで聞くよりまずぐぐって調べられたほうがよいと思いますよ。
そのほうが、勉強にもなるし早いだろうし。

http://www.google.com/search?hl=ja&lr=l ... %A9&num=50

いけやん

Re:再帰処理(再帰関数)について

#7

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

>一から十まで聞くよりまずぐぐって調べられたほうがよいと思いますよ。
>そのほうが、勉強にもなるし早いだろうし。
Mistさん、すいません。
イベントハンドラについて調べるのを忘れていました。
まだまだ、調べる「癖」がついてないですね。
出直してきます。

御津凪

Re:再帰処理(再帰関数)について

#8

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

> 40個ぐらいエラー
class CVctreeDlg{ 
	void All_Node_Expand(CTreeCtrl* tree,HTREEITEM item); 
}
これだと確かにエラーが沢山出ます。(再定義されているとか識別子がどうのこうのとか)

CVctreeDlg というクラスは、ソースファイルかヘッダファイルかのどこかで
クラスとして宣言されているはずです。
(なので、上記の追加された部分は不要です)
ソースファイルかヘッダファイルで"class CVctreeDlg" で検索すると多分見つかるはずです。

その中に、
public:
void All_Node_Expand(CTreeCtrl* tree,HTREEITEM item);
を、追加します。
前後に/*色々省略...*/ は、そのクラスで自動生成されたものなどのコードの意味だったのですが。

この説明では多分まだエラーが出るとおもいます。
クラスについて詳しく説明するのは長くなってしまうので、
今一度クラス周りの部分を調べなおすといいと思います。

あと、その中でも今回重要なのは"public:"です。
この意味も調べてください。
これをきちんと理解して使わないと、アクセスできないといったエラーが出ますので。

http://www.google.co.jp/search?hl=ja&q= ... =&aq=f&oq=
クラスについて調べるなら、この二つ目辺りがいいと思います。(私は読んでいませんが)

バグ

Re:再帰処理(再帰関数)について

#9

投稿記事 by バグ » 17年前

リソースエディタ(ダイアログの見た目を編集をするツール)で、貼り付けてあるボタンをダブルクリックしてみてください。
それだけで、イベントハンドラが追加されるはずです。これで、そのボタンが押されるたびに追加された関数が呼ばれるようになります。
ですので、その追加された関数の中を編集してやってください。

バグ

Re:再帰処理(再帰関数)について

#10

投稿記事 by バグ » 17年前

>>御津凪さん
今回の件に関してだけ言えば、privateでも問題ないのではないでしょうか?
ダイアログベースアプリで、なおかつダイアログの中だけで完結してしまう処理のようですし…?

御津凪

Re:再帰処理(再帰関数)について

#11

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

> 今回の件に関してだけ言えば、privateでも問題ないのではないでしょうか?
> ダイアログベースアプリで、なおかつダイアログの中だけで完結してしまう処理のようですし…?

あ、そうでした。(汗
すいません。 "private:" でしたね。

バグ

Re:再帰処理(再帰関数)について

#12

投稿記事 by バグ » 17年前

>>いけやんさん
MFCはクセがあって慣れるまでは使いづらいですし、ましてやVC++6.0だと答えられる人も少ないかもしれませんが、頑張って慣れてください(ぉぃ)

私も趣味以外ではあまり使わなくなりましたが、VC++6.0は速くて素晴らしい環境だと思ってます。

御津凪

Re:再帰処理(再帰関数)について

#13

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

実は私はMFCを使ったことありません。
(VisualStudioの製品版を買ったことがないので)

ではなぜ MFC 系の質問に答えられるかというと、
MSDN に MFC のオンラインリファレンスがあるからで。

バグ

Re:再帰処理(再帰関数)について

#14

投稿記事 by バグ » 17年前

MSDNは便利ですよね(^-^)
MSDNで調べれば、大抵のことは分かりますし♪
ただ、MSDNを見て理解できるのはある程度の知識と経験がある人だと思うんですよね。
まるっきりの初心者にも分かり易いかと言われると…(^_^;)

>>いけやんさん
もう古い本ですが、林晴比古著の【新VisualC++6.0入門】のスーパービギナー編、ビギナー編、シニア編の3冊はMFCの基本が分かりやすく解説されているのでオススメですよ。あ、でもビギナー編を買うなら、スーパービギナー編は不要かな?結構…というか、かなり内容が被ってますんで(苦笑)

古本でよければアマゾンとかで安く入手できると思います。新品でそろえると諭吉さんが飛んでいきます(笑)
私は今の職場に入社したときに、自分を追い詰める意味も込めて新品で全部そろえました(^_^;)

いけやん

Re:再帰処理(再帰関数)について

#15

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

いっぱい返ってきてましたね。
プログラムは、まだエラー出しながらやっているので
返信できる所だけで、

え~と御津凪さんpublicとprivateは、
前に少しだけかじったVBの意味で言うと
publicは意味的にいえば「公共の」とかでどこからでも参照でき、
privateはそのprivate内だけ、他からは参照できない。とかでしたっけ?
Cでも一緒なんですかね。違っていたらすいません。

バグさん。
>頑張って慣れてください
ありがとうございます。

以前にどこかで、いつまでそんな古いの使ってんだよって言われて
ちょっと凹んでいました。
なので
>VC++6.0は速くて素晴らしい環境だと思ってます。
この言葉は励み(少しだけやる気)になりました。

また、イベントハンドラ、ヘッダの定義等の処理をして
何らかの変化(多分エラー)がありましたら、また返信します。

御津凪

Re:再帰処理(再帰関数)について

#16

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

public や private の意味はそれであっていますね。
(ちなみに継承先のみ参照可能な"protected"もあります)
あと、これはC++での機能です。
Cでは存在しません。

いけやん

Re:再帰処理(再帰関数)について

#17

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

御津凪さん。
>実は私はMFCを使ったことありません。
>(VisualStudioの製品版を買ったことがないので)

>ではなぜ MFC 系の質問に答えられるかというと、
>MSDN に MFC のオンラインリファレンスがあるからで。
え?リファレンスを見ながらソース等、提示して頂いてたのですか。
本当に感謝しています。
素人なんでこんなコメントしか言えませんが、すごいですね。

バグさん。
>ただ、MSDNを見て理解できるのはある程度の知識と経験がある人だと思うんですよね。
>まるっきりの初心者にも分かり易いかと言われると…(^_^;)
その通りなんです(泣
今の僕には、msdnのリファレンスを見てもチンプンカンプンですね。

>もう古い本ですが、林晴比古著の【新 VisualC++6.0入門】のスーパービギナー編、ビギナー編、シニア編の
>冊はMFCの基本が分かりやすく解説されているのでオススメですよ。あ、でもビギナー編を買うなら、スーパ
>ビギナー編は不要かな?結構…というか、かなり内容が被ってますんで(苦笑)
う!えっとですね。自分が悪いのですが
8月だけで、林さんの新C言語入門ビギナー編 シニア編を買って
VC++の勉強もした方がいいとの事だったので、林さんのC++入門?(名前忘れました。) を買い
さらにVC++の入門?みたいな物を買い
ポインタも怪しいので完全制覇ポインタ~(名前覚えてないです。)計5冊程
なので、お金が・・・
来月に検討した方がいいですね。

バグ

Re:再帰処理(再帰関数)について

#18

投稿記事 by バグ » 17年前

試しに作ってみました。本当は兄弟アイテムを検査する部分も再帰処理にしようかと思いましたが、流れが分かりづらくなりそうなので止めておきました(^_^;)

///////////////////////////////////////////////////////////////////////////////////////////////////////
// 指定したアイテムより下位にある全アイテムに対してExpand関数を実行する(再帰関数)
//
// CTreeCtrl& tree = 操作したいCTreeCtrlクラス
// HTREEITEM item = 操作したいツリーアイテム(最初にルートアイテムを指定すれば全アイテムを操作できる)
// UINT code = Expand関数の第2引数と同じ値を指定する
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CVctreeDlg::ExpandAllNode(CTreeCtrl& tree, HTREEITEM item, UINT code)
{
	// Expand関数を実行する
	tree.Expand(item, code);

	// 子アイテムの取得(子アイテムが無い場合はchild = NULLとなる)
	HTREEITEM child = tree.GetChildItem(item);

	// 子アイテムが存在している間、ループ処理を行う
	while (child != NULL)
	{
		// 子アイテムの下に、更に子アイテムが無いかを検索する(再帰部)
		ExpandAllNode(tree, child, code);

		// 子アイテムの兄弟アイテムを取得する(兄弟アイテムが無い場合はchild = NULLとなる)
		child = tree.GetNextItem(child, TVGN_NEXT);
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
// 指定したアイテムより下位にある全アイテムに対してSetCheck関数を実行する(再帰関数)
//
// CTreeCtrl& tree = 操作したいCTreeCtrlクラス
// HTREEITEM item = 操作したいツリーアイテム(最初にルートアイテムを指定すれば全アイテムを操作できる)
// BOOL check = SetCheck関数の第2引数と同じ値を指定する
///////////////////////////////////////////////////////////////////////////////////////////////////////
void CVctreeDlg::SetCheckAllNode(CTreeCtrl& tree, HTREEITEM item, BOOL check)
{
	// SetCheck関数を実行する
	tree.SetCheck(item, check);

	// 子アイテムの取得(子アイテムが無い場合はchild = NULLとなる)
	HTREEITEM child = tree.GetChildItem(item);

	// 子アイテムが存在している間、ループ処理を行う
	while (child != NULL)
	{
		// 子アイテムの下に、更に子アイテムが無いかを検索する(再帰部)
		SetCheckAllNode(tree, child, check);

		// 子アイテムの兄弟アイテムを取得する(兄弟アイテムが無い場合はchild = NULLとなる)
		child = tree.GetNextItem(child, TVGN_NEXT);
	}
}

いけやん

Re:再帰処理(再帰関数)について

#19

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

おはようございます。
Mistさんのおっしゃていた。ググってmsdnのリファレンスの
「イベントハンドラの追加」を見ながら色々やってみたのですが
変な?関数がポンポンと追加されていき、結果的に解らなかったので。
質問さして頂きます。

2つ程、自分的にこうではないかと思う事があります。
1つ目は、リファレンスを見ていると5,6番の辺りで
名前を編集とあるのですがここで
ある関数を追加して→名前の編集みたいな事をして
「CVctreeDlg::○○○○○」→「CVctreeDlg::All_Node_Expand」
CVctreeDlg::All_Node_Expandを追加するんですかね?

もう一つは、
>リソースエディタ(ダイアログの見た目を編集をするツール)
すいません。省略させて頂きます
バグさんの書いて頂いたコメントなんですが
ボタンコントロールを→ダブルクリックする→void CVctreeDlg::OnButton2(){}が出来ます。
それをvoid CVctreeDlg::OnButton2() →void CVctreeDlg::All_Node_Expand(){}に
するって事ですか?

説明が下手ですいませんが、お願い致します。

バグ

Re:再帰処理(再帰関数)について

#20

投稿記事 by バグ » 17年前

>>ボタンコントロールを→ダブルクリックする→void CVctreeDlg::OnButton2(){}が出来ます。
>>それをvoid CVctreeDlg::OnButton2() →void CVctreeDlg::All_Node_Expand(){}にするって事ですか?

それでも構わないのですが、その場合は色々と変更しなければいけない箇所が出てきてしまうので、オススメできません。(もし、こちらの方法をお望みの場合はまた質問してください)

ですので、OnButton2関数の中で、All_Node_Expand関数を実行すれば同じことですので、そちらの方が楽です。

※上記を実行する為には、あらかじめ【VctreeDlg.h】内に、All_Node_Expand関数を宣言しておく必要があります。

バグ

Re:再帰処理(再帰関数)について

#21

投稿記事 by バグ » 17年前

全ノードの展開、圧縮、チェックのON・OFFを出来るだけのダイアログを作ってみましたので、参考になれば、どうぞ(^-^)

バグ

Re:再帰処理(再帰関数)について

#22

投稿記事 by バグ » 17年前

ファイル添付を忘れてました(苦笑)

いけやん

Re:再帰処理(再帰関数)について

#23

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

おはようございます。
昨日は、私用でプログラムする時間がなかったので(汗
返信出来ませんでした。すいませんでした。

バグさんサンプル提示&実行可能ファイルまで頂いて、ありがとうございます。

ソースにコメントまで書いて頂いて重ね重ね申し訳ないです。
一応コピペは身につかないと思うので、打ちました。(証拠はないですが・・・)


えっと、そういえば「イベントハンドラに追加」の件ですが
バグさんの物を見せて貰うとVctreeDlg.hに
private:
   void All_Node_Expand(CTreeCtrl& tree, HTREEITEM item, UINT code);
宣言をして、後はメインのソースの方に書くだけでした。
色々複雑な処理をするのかと思っていましたが、
思ってたより処理が少なく助かりました。

これが、以前御津凪さんがおっしゃっていた
クラスメンバ関数の宣言?という物にあたるのでしょうか?
間違っていたら、ごめんなさい。


まだ、展開の処理しか書いていないのですが、
バグさんのソースコードで動きました。

言ってなかった私が悪いのですが、
親は(root)は、3つあり今の実行結果では、
始めの親の一族?(適切な表現が浮かびませんでした。)
の部分はうまく行くのですが、残りの2つの部分はうまくいきません。
自分で考えたのですが原因が解りません。
しつこく質問すいませんが、教えて頂けないでしょうか?
//実行結果
---あああ//親
| |-いいい//子
| |-うう//子
|  |-え//孫
|  |-おおお//孫
|
|-+はは//親
|-+ららら//親

バグ

Re:再帰処理(再帰関数)について

#24

投稿記事 by バグ » 17年前

それでしたら、親(ルートアイテム)の取得の後に、親の兄弟を探すループを追加してやればいけます。
つまり、ExpandAllNode関数や、SetCheckAllNode関数と同じような処理をイベントハンドラの中に追加してやればいいわけです。
下記は展開ボタンが押されたときの例です。
void CVctreeDlg::OnButton1() 
{
	// CTreeCtrlの取得(メンバを追加しない場合の方法)
	CTreeCtrl* tree = (CTreeCtrl*)GetDlgItem(IDC_TREE1);

	// ルートアイテムの取得(ルートアイテムが無い場合はroot = NULLになる)
	HTREEITEM root = tree->GetRootItem();

	// ルートアイテムが無くなるまでループする	
	while (root != NULL)
	{
		// 全ノードの展開
		ExpandAllNode(*tree, root, TVE_EXPAND);

		// ルートアイテムの兄弟アイテムを検索する
		root = tree->GetNextItem(root, TVGN_NEXT);
	}
}

バグ

Re:再帰処理(再帰関数)について

#25

投稿記事 by バグ » 17年前

おっと、返答忘れしてました(^_^;)

>>えっと、そういえば「イベントハンドラに追加」の件ですが
>>バグさんの物を見せて貰うとVctreeDlg.hに
private:

   void All_Node_Expand(CTreeCtrl& tree, HTREEITEM item, UINT code);
>>宣言をして、後はメインのソースの方に書くだけでした。
>>色々複雑な処理をするのかと思っていましたが、
>>思ってたより処理が少なく助かりました。

>>これが、以前御津凪さんがおっしゃっていた
>>クラスメンバ関数の宣言?という物にあたるのでしょうか?

そういう事ですね。イベントハンドラの追加とはちょっと違いますが、クラスのメンバ関数の宣言に関してはあっています。まぁ、イベントハンドラというのも、結局はメンバ関数ではあるんですけどね(^_^;)

イベントハンドラというのはウインドウ上で起こる様々なイベントに対して呼び出される関数だと思っておけばいいかと思います。今回の件ですと『ボタンが押されたら…』というのがイベントにあたります。
他にも『ウインドウのサイズが変わったら…』、『ウインドウの位置が動いたら…』、『マウスがクリックされたら…』、『キーボードから何か入力があったら…』などなど、たくさんあります。

そのイベントに応じて、自分の望んだ動きをさせるのがプログラマの仕事な訳です。こういう動きをするプログラムの事をイベントドリブン形式といいます。

御津凪

Re:再帰処理(再帰関数)について

#26

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

MFC でプログラミングできないので、
どうしても回答が回りくどかったので、
バグさんの回答は本当に助かりました。

バグさんのコードでも、問題なく動くはずですが、
汎用的に考えると、下記の方が良い様な気もします。
void CVctreeDlg::ExpandAllNode(CTreeCtrl& tree, HTREEITEM item, UINT code)
{
	HTREEITEM brother,child;

	brother = item;
	do {
		// Expand関数を実行する
		tree.Expand(brother, code);

		// 子アイテムの取得(子アイテムが無い場合はchild = NULLとなる)
		child = tree.GetChildItem(brother);
		if ( child != NULL) {
			ExpandAllNode( tree, child, code );
		}

		// 兄弟アイテムを取得する(兄弟アイテムが無い場合はbrother = NULLとなる)
		brother = tree.GetNextItem( brother, TVGN_NEXT );

	} while (brother != NULL); // 兄弟アイテムが存在している間、ループ処理を行う
}
(バグさんの上記で提示していただいたコードから修正を加えました)

バグ

Re:再帰処理(再帰関数)について

#27

投稿記事 by バグ » 17年前

確かにそうですね。その方がすっきりしそうです(^-^)
ただ、新たにbrotherを用意しなくてもよさそうなので、更に改造してみました。
void CVctreeDlg::ExpandAllNode(CTreeCtrl& tree, HTREEITEM item, UINT code)
{
	// 兄弟アイテムが存在している間、ループ処理を行う
	while (item != NULL)
	{
		// Expand関数を実行する
		tree.Expand(item, code);

		// 子アイテムの取得(子アイテムが無い場合はchild = NULLとなる)
		HTREEITEM child = tree.GetChildItem(item);

		// 子アイテムが存在する場合は更にその下の階層を調べる(再帰処理)
		if (child != NULL)
		{
			ExpandAllNode(tree, child, code);
		}

		// 兄弟アイテムを取得する(兄弟アイテムが無い場合はitem = NULLとなる)
		item = tree.GetNextItem(item, TVGN_NEXT);
	}
}

いけやん

Re:再帰処理(再帰関数)について

#28

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

バグさん。ありがとうございます。
思った様に動作しました。
残りの圧縮、チェック(付ける、外す)も試したいと思います。

>イベントハンドラというのはウインドウ上で起こる様々なイベントに対して呼び出される関数だと思っておけばいいかと思います。
>今回の件ですと『ボタンが押されたら…』というのがイベントにあたります。
>他にも『ウインドウのサイズが変わったら…』、『ウインドウの位置が動いたら…』、『マウスがクリックされたら…』、『キーボードから何か入力があったら…』などなど、たくさんあります。

>そのイベントに応じて、自分の望んだ動きをさせるのがプログラマの仕事な訳です。
>こういう動きをするプログラムの事をイベントドリブン形式といいます。
なるほど、勉強になります。

御津凪さん。ありがとうございます。
後ほど、御津凪さんのプログラムも打ってみます。

では、また返信します。

バグ

Re:再帰処理(再帰関数)について

#29

投稿記事 by バグ » 17年前

よくよく考えたら、ループさせる必要もなかったですね(^_^;)
更に改良してみました。
void CVctreeDlg::ExpandAllNode(CTreeCtrl& tree, HTREEITEM item, UINT code)
{
	// Expand関数を実行する
	tree.Expand(item, code);

	// 子アイテムの取得(子アイテムが無い場合はchild = NULLとなる)
	HTREEITEM child = tree.GetChildItem(item);

	// 子アイテムが存在する場合は更にその下の階層を調べる(再帰処理)
	if (child != NULL)
	{
		ExpandAllNode(tree, child, code);
	}

	// 兄弟アイテムを取得する(兄弟アイテムが無い場合はitem = NULLとなる)
	item = tree.GetNextItem(item, TVGN_NEXT);

	// 兄弟アイテムが存在する場合は更にその下の階層を調べる(再帰処理)
	if (item != NULL)
	{
		ExpandAllNode(tree, item, code);
	}
}

いけやん

Re:再帰処理(再帰関数)について

#30

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

バグさん。
少し気になったのですが、
while()を使わなくて済むなら使わない方がいいのですか?
while()を使った方が書く処理は短いのですが。

御津凪

Re:再帰処理(再帰関数)について

#31

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

項目がそんなに多くない場合は問題ないですが、
何千個、何万個となると問題が出ます。
(処理速度は別)

たとえば、親しかない項目が1000あった場合、
1000回近く再帰呼び出しが行われ、その分引数などの保存領域を必要とします。
プログラムにはスタックバッファというあらかじめ割り当てられた領域があり、
ここに関数の引数などに自動的に割り当てるようになっています。
そのスタックバッファの領域がなくなってしまうと、ランタイムエラーを出して強制終了してしまいます。

(ちなみにプロジェクトのプロパティでスタックバッファの変更は可能です)

私的には、兄弟については while 文で処理したほうが良いと思います。
何千もの子なんて普通使いませんし。

バグ

Re:再帰処理(再帰関数)について

#32

投稿記事 by バグ » 17年前

その辺りは完全に個人の趣味です(笑)
最新のソースは、ループを使用せずに全て再帰処理にしてみただけですので、どちらも同じ動きをするはずですので(^_^;)
whileを使用した方が分かり易ければ、そちらをお使いくださいm(_ _)m

バグ

Re:再帰処理(再帰関数)について

#33

投稿記事 by バグ » 17年前

>>御津凪さん
たしかに、そこまでの状況は考慮してませんでした(^_^;)
再帰処理を使用する際は、絶対に考えておかなければいけない問題ですよね。

>>いけやんさん
という訳で、今回の件は、ループを使用した方がよさそうです。

いけやん

Re:再帰処理(再帰関数)について

#34

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

なるほど、
>プログラムにはスタックバッファというあらかじめ割り当てられた領域があり、
そういう物があるんですか。知りませんでした。

>たとえば、親しかない項目が1000あった場合、
>1000回近く再帰呼び出しが行われ、その分引数などの保存領域を必要とします。
>プログラムにはスタックバッファというあらかじめ割り当てられた領域があり、
>ここに関数の引数などに自動的に割り当てるようになっています。
>そのスタックバッファの領域がなくなってしまうと、ランタイムエラーを出して強制終了してしまいます。

上記の事、等も考えてプログラムを組んで行くのですね~。
奥が深いですね~。難しい(汗

その状況?えっと臨機応変?に使い分ける事がいいという事ですね。
質問に答えて頂いて、ありがとうございます。

>という訳で、今回の件は、ループを使用した方がよさそうです。
今回のプログラムでは、while()を使いますが、
せっかくみなさんが、答える。又は、考えて頂いたので。
提示して頂いているソースは、全て試します。
(今の所全て試しています。)
では、また返信します。

いけやん

Re:再帰処理(再帰関数)について

#35

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

すいません。タイトルとは脱線すると思うのですが

今何気にこの前に買った「新C言語入門」ビギナー編の「関数の項目」
を見ていたのですが、
その一文には、「~省略 もし引数がない、場合はvoidを使います。」と
書いてあるのですが、この文章で混乱しています。

御津凪さん。バグさんに書いて貰ったコードには

void All_Node_Check(CTreeCtrl& tree, HTREEITEM item, BOOL check);

voidなのに引数を3つ使ってますが。voidでも引数を使っていいのですか?
教えて頂いてもよろしいでしょうか?お願いします。

Mist

Re:再帰処理(再帰関数)について

#36

投稿記事 by Mist » 17年前

> void All_Node_Check(CTreeCtrl& tree, HTREEITEM item, BOOL check);

先頭のvoidは「戻り値がないこと」をあらわしています。
だから、引数とは関係ありません。

> その一文には、「~省略 もし引数がない、場合はvoidを使います。」と
この一文は引数が無い関数を作る場合は

void All_Node_Check(void)

としましょう、といっているのです。

いけやん

Re:再帰処理(再帰関数)について

#37

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

なるほど、解りました。ありがとうございます。

いけやん

Re:再帰処理(再帰関数)について

#38

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

すいません。解決にチェック付け忘れていました。
皆さんのおかげで解決しました。
解決は下記のコードです。
//全ノード展開
void CVctreeDlg::OnButton2() 
{	
	//CTreeCtrlの取得(メンバを追加しない場合の方法)
	CTreeCtrl* tree = (CTreeCtrl*)GetDlgItem(IDC_TREE1);

	//ルートアイテムの取得
	HTREEITEM root = tree->GetRootItem();

	//ルートアイテムが無くなるまでループする
	while(root != NULL){
		//全ノードの展開
		All_Node_Expand(*tree,root,TVE_EXPAND);

		//ルートアイテムの兄弟アイテムを検索する
		root = tree->GetNextItem(root,TVGN_NEXT);
	}
}

関数本体
void CVctreeDlg::All_Node_Expand(CTreeCtrl& tree, HTREEITEM item, UINT code)
{
	//Expand関数を実行する
	tree.Expand(item,code);

	//子アイテムの取得(子アイテムが無い場合は child = NULLとなる)
	HTREEITEM child = tree.GetChildItem(item);

	//子アイテムが存在している間、ループ処理を行う
	while(child != NULL){

		//子アイテムの下に、更に子アイテムが無いかを検索する(再帰処理)
		All_Node_Expand(tree,child,code);

		//子アイテムの兄弟アイテムを取得する(兄弟アイテムが無い場合はchild = NULLとなる)
		child = tree.GetNextItem(child,TVGN_NEXT);
	}
}

ヘッダの中
private:
	//展開,圧縮用関数
	void All_Node_Expand(CTreeCtrl& tree, HTREEITEM item, UINT code);
	//チェック用関数
	void All_Node_Check(CTreeCtrl& tree, HTREEITEM item, BOOL check);
長い間お世話になりました。
御津凪さん。バグさん。Mistさん。
幾つもの質問答えて頂きありがとうございます。

質問をした頃は、ポイントが初心者だったのに
もう中級者になってしましました。
(実力的には、ぴよぴよですが・・・)

実力的には、あれでも(汗
解決する事はいい事だと思いますが、
何故か今少し寂しい?気がします。
結構長い間考えた問題だったからでしょうか?

何はともあれ、協力して頂いた皆様ありがとうございました。

いけやん

Re:再帰処理(再帰関数)について

#39

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

すいません。解決後で、誰も見ないですかね・・・
一応書いてみます。
質問ではないのですが、悩み?みたいな事があります。

void CVctreeDlg::All_Node_Expand(CTreeCtrl& tree, HTREEITEM item, UINT code)

{
//Expand関数を実行する
tree.Expand(item,code);

//子アイテムの取得(子アイテムが無い場合は child = NULLとなる)
HTREEITEM child = tree.GetChildItem(item);

//子アイテムが存在している間、ループ処理を行う
while(child != NULL){

~省略

これから、頑張っていこうと思うのですが
今日は上記の様なソースを提示頂いたから出来たわけで・・・
正直に聞きたい事は、2つあります。
①今日バグさんのソースを見ながら打ちました。
もちろん解らない者なりに考えながら打ちました。
が身になる?力?こんな事で実力は付くのでしょうか?
答えを見ながらテストを、問題を、解くのと何ら変わりなく
不安に思いました。
今からは取り合えず参考書などの問題を打っていこうと重いますが
例文を何回、何百回打って効果があるのでしょうか?

②御津凪さん。バグさん。の
お二方の様すごくなりたいと思います。
お二方は、どんな事しましたか?

すいません。ちょっと引くかもしれませんが
>不安に思いました。
この辺りが・・・
よければ教えて頂きたいです。

バグ

Re:再帰処理(再帰関数)について

#40

投稿記事 by バグ » 17年前

察しの通り、本を読むだけ、例題を写すだけでは何にもなりません。

ただ、色々な人のソースコードを見るという行為自体は、良くも悪くも非常に勉強になります。

例題を写したあとに、どうしてこういう風に書いたら、こう動くのか?

というのを、プログラムソースと睨めっこして考えてください。

考えるというのは抽象的なので…流れを追いかけてみてください。

なんとなく流れが掴めたら、改造してください。

そうすると、これまでと違う動きになりますね?

そうしたら、また何故そうなるのかを考えてください。


こういう自分で手を加える練習は、やって損はしないと思います。というか、やらなければ上達しません。

で、なんとなく、理解できてきたら、ゼロから自分で書いてみるといいですよ。

御津凪

Re:再帰処理(再帰関数)について

#41

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

> すいません。解決後で、誰も見ないですかね・・・

新着記事を見るようにしているので、見ましたよ。

> お二方は、どんな事しましたか?

私の場合、勉強、というより、趣味で覚えましたね。
もちろん好きだから、というのもありますが。

「こういう便利なものを作りたい!」と思って取り組み始め、
闇雲に作ったソースがごちゃごちゃして、修正が効かなくなって挫折…。

こんなことが何回もありましたね。
そうやってプログラミングの技術を身に着けましたね。

それはさておき、

いけやんさんの場合、ソースの意味を「理解」していますでしょうか?
プログラムは絶対的な命令を持ちます。
書いたコードの意味を曖昧にしていると、いざ問題が発生したとき、
どこに問題があるかちんぷんかんぷんになってしまうのではないかと思います。

そんなことになる前に、書いてみたいコードの意味を理解しておく必要があります。

いけやんさんが質問した void でも、文章の意味からでなく、
「voidってなに?」
って所から疑問に思ったほうが良いでしょう。
void の意味を知って、初めて文章の意味が分かるということも決して少なくないはずです。

また、C++を覚える(学ぶと思わないほうが良いと思う)ために、
入門書などで疑問に思った単語やソースなどを調べ、意味を理解する必要があり、
かつ、それがどのように動くか一つ一つ書いて覚えていってください。
ただし、まとめて覚えようとすると、
後でどっちがどっちだか分からないといった混乱を招く恐れがあるのでご注意を。

あと、しっかり覚えるのは「構文と用語の意味」です。

あくまで私論(独学)なので、これかぎりではありません。
バグさんのおっしゃっている通り、
ソースを読み、
どういう動作をしているのか、
どこを変えたら思ったとおりの動作に変えられるか、
を、入門書などのソースからやってみることをお勧めします。

もちろん、意味が分からなければ、
もやもやがなくなるまで徹底して調べ倒すと
後の力になります。

あと、他の方の書いたソースから読むのは余りお勧めできません。
プログラムでは動いていても、初心者には理解不能な格好をしたソースが
あったりするので。

以上、長くなりましたが私からのアドバイスです。

いけやん

Re:再帰処理(再帰関数)について

#42

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

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

>例題を写したあとに、どうしてこういう風に書いたら、こう動くのか?

>というのを、プログラムソースと睨めっこして考えてください。
はい、画面の前で固ま(睨めっこ)ってみたいと思います。


>考えるというのは抽象的なので…流れを追いかけてみてください。

>なんとなく流れが掴めたら、改造してください。

>そうすると、これまでと違う動きになりますね?

>そうしたら、また何故そうなるのかを考えてください。

>こういう自分で手を加える練習は、やって損はしないと思います。というか、やらなければ上達しません。

>で、なんとなく、理解できてきたら、ゼロから自分で書いてみるといいですよ。
上記の改造等はもう少し先になると思いますね。


>「こういう便利なものを作りたい!」と思って取り組み始め、
>闇雲に作ったソースがごちゃごちゃして、修正が効かなくなって挫折…。

>こんなことが何回もありましたね。
>そうやってプログラミングの技術を身に着けましたね。
やはり「失敗は成功の元」なんですね。
いきなり、うまく事なんてないでもんね。

>書いたコードの意味を曖昧にしていると、いざ問題が発生したとき、
>どこに問題があるかちんぷんかんぷんになってしまうのではないかと思います。

>そんなことになる前に、書いてみたいコードの意味を理解しておく必要があります。
今の所、何となく理解している事ばかりですね。
これでは、ダメですね。

>入門書などで疑問に思った単語やソースなどを調べ、意味を理解する必要があり、
>かつ、それがどのように動くか一つ一つ書いて覚えていってください。
>ただし、まとめて覚えようとすると、
>後でどっちがどっちだか分からないといった混乱を招く恐れがあるのでご注意を。
PCでパチパチ打つだけでなく、書くという事も大事なんですね。

>もちろん、意味が分からなければ、
>もやもやがなくなるまで徹底して調べ倒すと
>後の力になります。
了解です。

>以上、長くなりましたが私からのアドバイスです。
お二人ともありがとうございます。

これから、やる事がかなり多そうですが(汗
何回も失敗して、何回も調べ、何回も書いて、何回も改造していきたいと思います。
(何回って何回書いてるんだよ)

大変参考になりました。
本当に感謝しています。
また、掲示板を利用すると思うので
その時は、よろしくお願い致します。

閉鎖

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