• ベストアンサー

ツリーコントロールとツリー構造のデータとのリンク

ツリーコントロールとツリー構造のデータとのリンク 私が開発しているソフトウェアは、データ構造として ツリー構造を使っています。このツリー構造のデータ を表示するためにツリーコントロールを使って いますが、データとツリーコントロールのリンクする 方法として良い方法を探しています。 ここでいう「リンク」とは、例えば ツリー構造のデータにデータの追加や削除が おこなわれた場合、該当するツリーコントロールの データも追加と削除をおこなう。ことです。 現時点では、ツリー構造のデータにデータの追加や 削除がおこなわれたら、ツリーコントロールに SendMessageを送ってツリーコントロール側の データの追加や削除をおこなっています。この場合、 ツリー構造のデータのクラスに、GUIのクラスの ポインタを保持しています(ツリーコントロール へのSendMessageのためにCWnd*を保持している)。 データにGUIに関わるコードが存在するので、 GUIに依存しない方法に変えたいのですが、みなさんは このような場合はどうしていますか? ちなみに現時点では、Design PatternのObserver Patternを採用してみようと思っています。 他に良い方法があれば教えてください。 よろしくお願いします。 開発環境:VC++6.0, MFC

  • pugoo
  • お礼率96% (25/26)

質問者が選んだベストアンサー

  • ベストアンサー
  • buuchan1
  • ベストアンサー率31% (6/19)
回答No.4

私が話したいのは以下のようなことです。 (×) GUIに依存したデータクラス (○) 特定のデータを扱えるGUIクラス ここから先は、住所録を例にします。 住所録のデータを以下のように定義します。 class CAddressData {  LPCTSTR Name; // 名前  LPCTSTR Adress; // 住所  LPCTSTR Phone; // 電話番号 }; 住所録の場合、複数件同時に扱うはずですから、以下の形で 保持することにします。 CList<CAddressData, CAddressData&> m_AddressBook; これをツリー形式で表示するならば、エクスプローラのよう な形をイメージする人が多いかと思います。つまり、左側に ツリー、ツリーで選択中の情報を右側のリストに詳細表示と いうものです。 この場合、ツリーとリストは同じ住所録というデータを扱っ ていて、ただ表示の方法が違うだけだと言うことは分かりま すよね。 なので、pugooさんがやったように、[GUIに依存したデータク ラス]にしてしまうとツリーとリスト双方にSendMessageしな ければいけなくなります。 そして、GUIが変わった(コンボボックス+リストになったな ど)だけで、SendMessage先が変わります(= データクラスの実 装が変わる)。 データフォーマットが変わってないのに、データクラスの実 装が変わるのはおかしくないですか? これが、No.3の人の言う[データーとその表現が一体化してい てはツブシが効かない]です。 ところが、pugooさんのデータとツリーコントロールのリンク という考え自体方は非常に重要な考え方なのです。 発想を逆転して、[データをGUIに結びつける]のでは無く、 [GUIを特定データに特化]します。GUIの派生クラスを作って、 特定データを直接扱えるようにします。派生というのは特化と 呼ばれることもあるぐらいですから、 これはごく自然な流れです。 (例) ツリーの場合  (電話番号を[市外局番][市内局番]にツリー分けして追加する) CAdressTreeCtrl::InsertItem(CAddressData* pData) {  // ツリーアイテムを追加  HTREEITEM hSigaiItem = (pData->Phoneより市外局番の挿入位置を算出);  HTREEITEM hSinaiItem = (pData->Phoneより市内局番の挿入位置を算出);  HTREEITEM hCurItem =   CTreeCtrl::InsertItem(pData->Name, hSigaiItem, hSinaiItem);  // データを記憶  CTreeCtrl::SetItemData(hCurItem, (DWORD)pData); // これがミソ } このとき、InsertItem()の際に、追加したデータ自身を SetItemData()しておくのがミソです。このおかげで、GUIイ ベント発生時のデータ更新は、GetItemData()一発でm_AddressBook を介さずに中身のデータへ直リンクです。 質問にあったソフトウェア的にツリーのデータを追加と削除 ですが、追加を例にすると class CAdressView {  CList<CAddressData, CAddressData&> m_AddressBook; // データ  CAdressTreeCtrl m_AdressTreeCtrl; // ツリー public:  void AddAdress(CAddressData& rData)  {   POSITION Pos = m_AddressBook.AddTail(rData);   m_AdressTreeCtrl.InsertItem(&m_AddressBook.GetAt(Pos));  } } のような感じで実装を行い、CAdressView::AddAdress()をコ ールすると、データとコントロールが有機的に結びつきます。 さらに、CAdressViewの外側の人からは、CAdressViewが CAddressDataを直接扱うクラスのように見えます。このブラ ックボックス化こそが、オブジェクト指向で言うところの本 質的な隠蔽というものです。 以上、簡単ですが理解していただけたら幸いです。

pugoo
質問者

お礼

ご回答ありがとうございます。 > InsertItem()の際に、追加したデータ自身を > SetItemData()しておくのがミソです。 これはわかります。私もSetItemData、GetItemDataを 利用しています。しかし、CAdressViewを使った例が わかりません。具体的には、CAdressView::AddAdress をコールするのはわかりますが、このクラスの オブジェクトをどこに保持して、どのようにして オブジェクト(のポインタ)を取得するかがわかりません。 その辺りはどうお考えですか?

その他の回答 (4)

  • buuchan1
  • ベストアンサー率31% (6/19)
回答No.5

MFCのドキュメント&ビューだったら、 CAdressViewは実際のビュー(CView派生クラス)かな。 CAdressViewのメンバ変数としてCAdressTreeCtrlやCAdressListCtrlがいる感じです。 フレームの中にビューがあって、さらにビューの中にツリーとリストがあると思えばわかりやすいでしょう。 また、ドキュメント&ビューであれば、やはり CList<CAddressData, CAddressData&> m_AddressBook; はドキュメントクラスのメンバでしょう。 そんな感じですが、イメージ沸きますでしょうか? わかりにくいようなら、簡単なサンプルでも作成します。

pugoo
質問者

お礼

ご回答ありがとうございます。 返信が遅くなりすみません。 なんとなくですがわかりました。 自分で簡単なプログラムを作って試してみます。

回答No.3

ANo.1 > CTreeCtrlの派生クラスを作って、ツリーデータを直接追加できるようにするのが、一般的なオブジェクト指向の考え方です。 違うんじゃない? データーとその表現が一体化していてはツブシが効かない。

pugoo
質問者

お礼

buuchan1さんの考えがよくわからないので、 buuchan1さんの回答を待ちたいと思います。

  • terra5
  • ベストアンサー率34% (574/1662)
回答No.2

今までそのケースは経験ありませんが、 多分GUIを含まないツリー構造のデータのクラスを作り、 それを継承してGUI依存部を実装すると思います。 こうすればGUI不要なら元のクラスを使えばいいし、 別のGUI環境下ならGUI依存部のみ書き換えればいいんじゃないかと。

pugoo
質問者

お礼

ご回答ありがとうございます。 他の掲示板にも同じ質問を書き込んでいたのですが、 (マルチポストは嫌われるとご指摘がありましたが) 同じような意見をいただきました。 ぜひ参考にさせていただきます。

  • buuchan1
  • ベストアンサー率31% (6/19)
回答No.1

この場合、考え方が全く逆でしょう。 MFCということはCTreeCtrlを使っているかと思いますが、CTreeCtrlの派生クラスを作って、ツリーデータを直接追加できるようにするのが、一般的なオブジェクト指向の考え方です。 (例) CTreeCtrlの派生クラス、CMyTreeCtrlを作成し、ツリーデータを格納するクラスCMyDataを直接追加できるように CMyTreeCtrl::SetItemData(CMyData)関数をオーバーライドします。 このとき、CMyDataクラスのメンバ変数にツリーコントロールに表示するテキストを含めてやれば、CMyTreeCtrl::SetItemData(CMyData)関数内からCTreeCtrl::SetItemText()を呼ぶことにより、ツリーコントロールに対して、データの設定とテキストの設定を同時に行うことができます。

pugoo
質問者

お礼

ご回答ありがとうございます。 > この場合、考え方が全く逆でしょう。 すみません。よくわかりませんので 詳しく教えていただけないでしょうか? よくわからない点は、 ユーザがツリーコントロール(CTreeCtrl)の データを選択して、データの追加や削除の コマンドを実行した場合はご回答いただいた 方法で良いと思いますが、ソフトウェア的に ツリーのデータを追加と削除をおこなう場合は どうでしょうか? ソフトウェア的にとは、ツリー構造のデータに 対して、データの追加と削除をおこなった場合です。 この場合はツリーコントロールの更新をおこなう 必要があるとおもいますが、それをどうやって 実現するのでしょうか? 簡単な方法として、ツリーコントロールのデータを 全て削除して(CTreeCtrl::DeleteAllItems)から 再度全データを追加する(CTreeCtrl::InsertItem) 方法がありますが、これではデータ量が多い場合は ツリーコントロールの更新に時間がかかって しまいます。それに、ユーザによって展開されていた ノードが全て閉じた状態になってしまいます。 ご回答いただいた方法に対して私の理解が間違って いましたらすみません。

関連するQ&A

  • ツリー構造の比較のアルゴリズムを教えてください

    ディレクトリ構造の変更前と変更後の比較を行って、 どのフォルダがどこへ行ったかを判別するプログラムを作成したいのですが、どんなアルゴリズムにすればよいでしょうか? 変更前と変更後でディレクトリは1:1に対応しません。n:mや削除、追加など色んなパターンがあります。 ツリー構造(ディレクトリ構造)とは、以下のようなイメージのものです。 C:. ├─Acrobat │ ├─ActiveX │ ├─Browser │ ├─FileInfo │ ├─HowTo │ │ ├─ENU │ │ │ └─Images │ │ └─JPN │ │ └─Images │ ├─Javascripts

  • C#のツリービューでツリーノードとデータの関連付け

    こんにちは。 C#でツリービューの操作をしています。 すでに階層構造を持つデータがあります。これをツリービューに表示させようとしています。 TreeNode treeNodeFruits = new TreeNode("果物"); としてツリービューに追加してあげると普通に表示できますが、このままだと独自データと関連付けがされていないため、ノードをクリックした際に何もできません。 C++ではHTREEITEMのlParamにユーザーデータのポインタをセットできますが、C#ではツリーノードに関連付けできそうな項目が見当たりません。 C#ではツリーノードと独自に持つデータとの関連付けをどのようにすればよろしいのでしょうか?

  • プログラム中のツリー形式のデータの保存方法について

    こんにちは。 趣味で、VC#2010を使ってウィンドウズプログラミングを行なっております。 カテゴリは、VBが最もVC#に近そうだったので、 VBとさせていただきました。 今回は、データの保存方法について質問させてください。 .NETでは、2次元の表に表せるようなデータであれば、 DataSetクラスで保存するのが便利だと思いますが、 ツリーになっているようなデータはどのように保存するのが定石でしょうか? ツリーになっているデータというのは、 TreeViewコントロールで表示するようなデータで、 このサイトのカテゴリもそれの一つだと思います。 ライフ ├恋愛・人生相談 |├恋愛相談 |├夫婦・家族 |… … このような3階層のものに限らず、より深いツリーのデータの保存形式の定石もあればご指導頂けると幸いです。 以上です。 よろしくお願い致します。

  • マスタデータ更新

    こんにちは。 システム開発の基礎的なところがわからないので、教えていただきたく、投稿させていただきます。 システム開発をほとんどやったことがないので、言葉が変なところもあるかと思いますが、宜しくお願いいたします。 サーバー上に、AというSQLServerのDBがあります。 今までは、システム管理者のみがAccessからA.DBのリンクテーブルを使い、マスタデータの更新/追加/削除を行っていましたが、今後、リーダークラスの人もできるようにしたい!という要望があり、そのインターフェース部分を作成しています。 いろいろと考え、フロントエンド側にAccessでB.mdbを作成し、そこには、A.DBと同じテーブル構造の一時TBLを作成し、B.mdbを開いた時にA.DBから全データを取得することにしました。(取得するところまではできています) ここから、設定するための画面作成をしますが、最終的に、更新/追加/削除されたデータは、どのようにA.DBにUPすればいいのでしょうか? 考えた方法として (1)B.mdb内に、一時テーブルとは別に、更に同じ構造の変更用テーブルを作成。 設定画面から更新/追加/削除されたデータは変更用テーブルに保存し、全ての処理が終了したら、変更用テーブルにあるデータを1つづつ見て、A.DBへ更新/追加/削除をかける (2)一時テーブルのデータを直接更新/追加/削除し、全ての処理が終了したら、全テーブルのレコードを1件づつ比較し、A.DBへ更新/追加/削除をかける というくらいしか思いつかないのです。 その他に思ったのが、一時テーブルもしくは変更用のテーブルに、レコード毎に「更新/追加/削除」がわかるようにフラグを設けて、そのフラグに従ったSQL文を発行する というくらいです。。。 根本的に、マスタデータに対する更新/追加/削除のやり方が間違っていたりしますか? 誰も聞ける人がいないので、どうぞ宜しくお願いいたします!!!

  • ドコモデータリンクをアンイストールできない。

    Windows7の64ビット版に誤ってドコモデータリンクのアプリをダンロードしました。このアプリは64ビット版に対応していないことがわかったため、コントロールパネルからアンインストールしようとした所、アンインストールできません。ドコモのHPを見たら、改めてこのアプリをダウンロードしてからアンインストールしてくださいとの記述があり、そのようにしたところ、アプリのダウンロードの途中で「インストールされようとしているバージョンより新しいバージョンがすでにインストールされています。セットアップを続行することはできません。」とのダイアログが出てきて前に進みません。コンピュータCのプログラムファイル内にはデータリンク関係のファイルは既にありません。コントロールパネルの表示だけにデータリンクが存在し、これを削除できない状態です。不都合はありませんが、コントロールパネルからこの表示を削除する方法を教えてください。回りくどい説明でごめんなさい。よろしくお願いします。

  • ツリービューの使い方が・・・

    VBのカスタムコントロールはほとんどさわったことがないので、ぜんぜんわからないです。 初心者っぽい質問で申し訳ないのですが、プロセスとプロセスがもっているスレッドを、プロセスID&スレッドIDをキーにツリー構造を持たせたいのですが、ツリービューのツリーへのアクセスのしかたがわかりません。 MSDNライブラリが壊れているようで、ヘルプが出ないのです。 新しいMSDNライブラリ入れてから、トラブル続き。 TreeView1.Nodes.Add , , "キー", "値" TreeView1.Nodes.Add , , "キー\サブキー", "値" じゃなさそうみたいです。 かといってそれぞれのノードが小枝への参照をもっているわけでもないし、小枝を追加するメソッドをもっているわけでもないし。 単純に小枝への追加のしかたが知りたいだけなんですけど・・・。 だれか教えてください。

  • 圧縮せずにディレクトリ構造をメールで送るには?

    海外の同僚があるソフトのデータがほしいと言ってきました。しかしそのソフトのデータはディレクトリツリー構造になっています。  1.彼はLHAなどの圧縮ソフトがないので圧縮して送れません。  2.自己解凍で送ると向こうの会社のサーバーがウィルスと勘違いして削除してしまいます。  3.しかもパソコンは素人に毛が生えたような初心者です。  4.私が持っているメールソフトではディレクトリーツリー構造をそのまま送れません。 何か良い方法はないでしょうか? お願いします。

  • PHPで開発効率をあげる方法。

    初めまして、ラブ・ザ・ゲームといいます。 初めて質問するのですが、独学でPHPを勉強しています。 自作のプログラムを作ったり、オブジェクト指向がなんとなくわかってきた・・・と思います。 そこで、みなさんが実践している開発効率を上げる方法を教えてください。 私は、どのプログラムでも使う基本のデータと、個々のプログラムで使用するデータを分けたいのですが、こういう方法が正しいのかが、わかりません。 多くのプログラム使う、 『No,oya,res(ツリー構造のため),名前、タイトル、コメント、日付、IP』 で、データをまとめる、サブルーチンなりクラスにします。 それを追加・変更サブルーチンや、クラスの継承で、 『No,oya,res(ツリー構造のため),名前、タイトル、コメント、日付、IP』 に、『アドレス、画像』 を付け加えたいのです。 こうすれば、バグや修正するときに、楽だと思うのですが。 この方法は、どうでしょうか? サブルーチンなのでしょうか? オブジェクト指向は、データ中心だと読んだので、こういう方法は少し地が浮きもするのですが。 クラス・オブジェクト指向でも可能なのでしょうか? また、ほかに、開発効率を挙げる方法がありましたら、お教えください。

    • ベストアンサー
    • PHP
  • データ構造で悩んでます

    以下の構造体があります。 struct Test {   string name;   int no;// 1~100   int age;// 1~100 }; stlのvectorに頻繁に動的に追加、削除されるとします。これをnoやageをキーに効率よく検索する方法を教えてください。 私が思いついたのは、 ・multisetを別に用意する。問題点は追加、削除毎にソートされてしまう。 ・no,age分vectorを用意する。速いけど汎用性が無い。 boostや他のライブラリは無しでお願いします。

  • データ構造の保存法について

    データ構造のメモリ上の状態、つまりポインターによるノード間のつながりをファイルに保存して、そのファイルを読み込むとコンピュータ上で前回のデータ構造を再現(ポインターによるつながりを再現)できる方法を探しています。 現在バイナリーツリーで上記の保存法を色々探したり考えたりしているのですが、いい方法が見つかりません。 各ノードに番号をふってファイルに保存し、次回読み込んだときに上手く工夫してやればできるかな、といった程度です。 ご存知の方がおられたら教えていただけないでしょうか? よろしくお願いいたします。