ツリーコントロールとツリー構造のデータとのリンク
私が開発しているソフトウェアは、データ構造として
ツリー構造を使っています。このツリー構造のデータ
を表示するためにツリーコントロールを使って
いますが、データとツリーコントロールのリンクする
方法として良い方法を探しています。
ここでいう「リンク」とは、例えば
ツリー構造のデータにデータの追加や削除が
おこなわれた場合、該当するツリーコントロールの
データも追加と削除をおこなう。ことです。
現時点では、ツリー構造のデータにデータの追加や
削除がおこなわれたら、ツリーコントロールに
SendMessageを送ってツリーコントロール側の
データの追加や削除をおこなっています。この場合、
ツリー構造のデータのクラスに、GUIのクラスの
ポインタを保持しています(ツリーコントロール
へのSendMessageのためにCWnd*を保持している)。
データにGUIに関わるコードが存在するので、
GUIに依存しない方法に変えたいのですが、みなさんは
このような場合はどうしていますか?
ちなみに現時点では、Design PatternのObserver
Patternを採用してみようと思っています。
他に良い方法があれば教えてください。
よろしくお願いします。
開発環境:VC++6.0, MFC
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を直接扱うクラスのように見えます。このブラ
ックボックス化こそが、オブジェクト指向で言うところの本
質的な隠蔽というものです。
以上、簡単ですが理解していただけたら幸いです。
ご回答ありがとうございます。
> InsertItem()の際に、追加したデータ自身を
> SetItemData()しておくのがミソです。
これはわかります。私もSetItemData、GetItemDataを
利用しています。しかし、CAdressViewを使った例が
わかりません。具体的には、CAdressView::AddAdress
をコールするのはわかりますが、このクラスの
オブジェクトをどこに保持して、どのようにして
オブジェクト(のポインタ)を取得するかがわかりません。
その辺りはどうお考えですか?
No.5
- 回答日時:
MFCのドキュメント&ビューだったら、
CAdressViewは実際のビュー(CView派生クラス)かな。
CAdressViewのメンバ変数としてCAdressTreeCtrlやCAdressListCtrlがいる感じです。
フレームの中にビューがあって、さらにビューの中にツリーとリストがあると思えばわかりやすいでしょう。
また、ドキュメント&ビューであれば、やはり
CList<CAddressData, CAddressData&> m_AddressBook;
はドキュメントクラスのメンバでしょう。
そんな感じですが、イメージ沸きますでしょうか?
わかりにくいようなら、簡単なサンプルでも作成します。
ご回答ありがとうございます。
返信が遅くなりすみません。
なんとなくですがわかりました。
自分で簡単なプログラムを作って試してみます。
No.3
- 回答日時:
ANo.1
> CTreeCtrlの派生クラスを作って、ツリーデータを直接追加できるようにするのが、一般的なオブジェクト指向の考え方です。
違うんじゃない? データーとその表現が一体化していてはツブシが効かない。
No.1
- 回答日時:
この場合、考え方が全く逆でしょう。
MFCということはCTreeCtrlを使っているかと思いますが、CTreeCtrlの派生クラスを作って、ツリーデータを直接追加できるようにするのが、一般的なオブジェクト指向の考え方です。
(例)
CTreeCtrlの派生クラス、CMyTreeCtrlを作成し、ツリーデータを格納するクラスCMyDataを直接追加できるように CMyTreeCtrl::SetItemData(CMyData)関数をオーバーライドします。
このとき、CMyDataクラスのメンバ変数にツリーコントロールに表示するテキストを含めてやれば、CMyTreeCtrl::SetItemData(CMyData)関数内からCTreeCtrl::SetItemText()を呼ぶことにより、ツリーコントロールに対して、データの設定とテキストの設定を同時に行うことができます。
ご回答ありがとうございます。
> この場合、考え方が全く逆でしょう。
すみません。よくわかりませんので
詳しく教えていただけないでしょうか?
よくわからない点は、
ユーザがツリーコントロール(CTreeCtrl)の
データを選択して、データの追加や削除の
コマンドを実行した場合はご回答いただいた
方法で良いと思いますが、ソフトウェア的に
ツリーのデータを追加と削除をおこなう場合は
どうでしょうか?
ソフトウェア的にとは、ツリー構造のデータに
対して、データの追加と削除をおこなった場合です。
この場合はツリーコントロールの更新をおこなう
必要があるとおもいますが、それをどうやって
実現するのでしょうか?
簡単な方法として、ツリーコントロールのデータを
全て削除して(CTreeCtrl::DeleteAllItems)から
再度全データを追加する(CTreeCtrl::InsertItem)
方法がありますが、これではデータ量が多い場合は
ツリーコントロールの更新に時間がかかって
しまいます。それに、ユーザによって展開されていた
ノードが全て閉じた状態になってしまいます。
ご回答いただいた方法に対して私の理解が間違って
いましたらすみません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- 着うた・着メロ Andriodスマホに、メール添付で送った音源。DLした「ダウンロード」フォルダーをホーム画面に 1 2022/09/04 16:44
- ブルーレイ・プレーヤー・レコーダー あなたなら,どちらのツリーを置きますか? 3 2022/11/15 16:01
- ブルーレイ・プレーヤー・レコーダー 再度,質問します。 8 2022/11/17 13:54
- その他(データベース) c言語の問題です。これを踏まえてコーディングしたいのでおしえていただきたいです。 3 2023/08/03 09:27
- 家具・インテリア こんにちは。写真の通り、クリスマスの装飾品の引っ掛ける部分が壊れてしまい、ツリーに引っ掛けられなくな 3 2023/01/14 15:44
- その他(クラウドサービス・オンラインストレージ) 個人情報保護の件 1 2023/05/18 12:19
- HTML・CSS HTMLを正しく表示させるには 2 2023/06/18 09:12
- クリスマス サンタ 折り紙 3 2022/12/02 15:03
- Windows 10 エクスプローラでリスト表示かつその場で階層表示はできますか? 1 2022/09/02 01:48
- Android(アンドロイド) Androidスマホのデータ移行が終わらない 1 2023/08/04 17:25
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
合計3TBのデータのハッシュ値を...
-
教えて下さい
-
配列でデータが入っている要素...
-
【エクセル】測定時間がバラバ...
-
Accessで該当データにフラグを...
-
多量のSUMIF式を軽くしたい
-
[C言語] コメント文字列を無視...
-
メモ帳(テキストデータ)をExc...
-
Excelのマクロでワードのテキス...
-
C言語プログラム変更
-
配列の勉強をしています。使用...
-
ノイズの入った波形をきれいな...
-
VBAを使ってOutlookメール本文...
-
モジュラス103の算出方法について
-
ビットシフトについて
-
win7でvbsファイルが実行できない
-
EXCELVBAでSQLserverからデータ...
-
HTMLでテキストボックスで...
-
CString型の文字列連結について
-
GETはできるがPOSTができない、...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
教えて下さい
-
配列でデータが入っている要素...
-
【エクセル】測定時間がバラバ...
-
メモ帳(テキストデータ)をExc...
-
VBA 空白セルを削除ではない方...
-
多量のSUMIF式を軽くしたい
-
Excelのマクロでワードのテキス...
-
エクセルで2つの時系列のデー...
-
この行は既に別のテーブルに属...
-
VBAを使ってOutlookメール本文...
-
シーケンサにパソコンからアク...
-
EXCELVBAでSQLserverからデータ...
-
ブレーカー落ちで壊れたりしな...
-
[C言語] コメント文字列を無視...
-
オープンチヤットでデータ削除...
-
モジュラス103の算出方法について
-
javaでDBからデータを取ってき...
-
カンマからスラッシュに
-
VBA 毎日取得するデータを順番...
-
Android携帯をUSBメモリ代わりに
おすすめ情報