VS9のMFCで,OSはXP以上です
MDIで複数の種類のドキュメントが存在していて,
そこから生成されるビューがあり,そこには関連のビューが複数存在します
1ドキュメントに対し複数のビューです
複数のビューの関係?はメインとサブという形にしています
サブはメインが閉じられると全て閉じる振る舞いをします
指定のドキュメント種別ごとのアクティブドキュメント(同一種別内で
最も最前面に配置されているビューに関連するドキュメント)や
アクティブビュー(同一種別内で最も最前面に配置されているメインのビュー)を
取得するのにかなり面倒なことになっています
ざっとですがこの流れです
1. 最も前面のサブのビューでないチャイルドフレームを取得
2. 取得したフレームのアクティブドキュメントを取得
3. 取得したアクティブドキュメントからテンプレートを取得
4. 取得したテンプレートの文字列を取得(GetDocString),検証しOKなら終わり
5. 次の前面のサブのビューでないチャイルドフレームを取得(3にもどる)
で,更に取得できたドキュメントと同一種別の次にアクティブな
ドキュメントやビューを取得するときとかも,またかなり面倒なことになっています
そこで,このような取得ができる関数や簡単な方法などあったらいいなという事で
質問にしました
それとも設計に問題がありそうなんでしょうか?
メイン又はアプリケーションが「カレントのビュー」を必要とするなら、
「カレントになったビューに申告させる」のが最も簡単です。
MSさんのドキュメントビューアーキテクチャは、そのルール内で
使用する分には困ることはありませんが、ちょっと凝ったことをすると
すぐに破綻します。そんなケースでは、独自の仕組みで管理するしか
ありません。
参考になるかどうかわかりませんが、自分の場合、Docテンプレート、
それから作ったDoc、そのDocを表示しているView(複数)、必要なら
Frame(複数)を、自前の構造と配列でメインが一元管理してます。
全てのFrameとViewは自分が
・Createされたとき
・アクティブになったとき
・Destroyされたとき
・その他の重要な変更が加えられたとき
などの都度、メインに報告させてます。従って、メインは常にどのViewが
アクティブで、何をしているかを把握している状態です。
FrameとViewの両方に報告させている理由は、
一般に1つのDocは複数のFrameを持ち、1つのFrameは複数の末端的Viewを
持っているからです(タブViewを使う場合も含まれます)。
まぁ、このあたりでドキュメントビューアーキテクチャとはかけ離れてくるので
これ以上特殊なことをする場合はDocテンプレートとDocを必要としない、
独自の機構に切り替え、当該アーキテクチャとはさよならします(笑)。
アーキテクチャとはさよならですか。。。
UIは見た目だけなのでどこまで作りこむかなぁ
現状正しい動きにはなっているのですけど,ちょっと疑問があります
メインのビューが最初に作られた後にサブのビューが作られます
サブのビューが先に作られることはありません
で,CDocumentのGetFirstViewPositionとGetNextViewにて最初に取得できるのは,
最初に生成されたビューと思っていたのですが,本当なのかがわかりません
何かのタイミングで順番が狂うと,おそらく矛盾が生じてくるかもと
思っていますが,
CDocumentのGetFirstViewPositionとGetNextViewにて最初に取得できるのは,
必ず最初に生成されたビューと思っていて大丈夫なのでしょうか?
MFCのソースを見ると、
Docはメンバの CPtrList m_viewList;に生成したViewのポインタを保持しています。
任意のViewが破棄(RemoveView)されれば当然m_viewListからも削除されます。
さて、GetFirstViewPosition()はm_viewListの先頭位置を戻すだけです。
従って以下のことが言えると思います。
同Docで生成されたViewの先頭が破棄されていないのであれば、
かつ、先頭が他のものに入れ替えられていなければ、
GetFirstViewPosition()は、同Docで生成された最初のViewを戻す。
一般にCDocumentは派生させて使用するのが前提ですので「破棄」
に関わらずm_viewListを変にいじると同じ効果が発生させる
事が可能です。これは、自作のDocに関わらず、そのDocを
継承した先で、同じ事をされれば効果も変わりません。
従って、
GetFirstViewPosition()が最初に生成されたViewを戻すことを
保障するには、CDocumentをproptectedに継承した自前のDocで、
Viewを生成する必要がある。
と、いうことになるのではないでしょうか。
またやっちまった。orz
1.保証
2.に関わらずm_viewListを変にいじると同じ効果を発生させる
に訂正します。
UIにこだわるあたりVisualStudioみたいに
ビューからだけではなく、たとえばプロパティペインなど
ドッキングペインからドキュメントの変更やビューの追加
なんかもするような形なのかな?
GetActiveViewで、アクティブなVIEWはとれます
ttp://msdn.microsoft.com/ja-jp/library/zs0t7t34(v=VS.100).aspx
(解説重要)
まだCViewやCDocumentなんかはCObjectからの派生なので
IsKindOf(RUNTIME_CLASS(名称))
で、継承してつくった自作のクラスのどれをつかっているかチェックすることできます
>何かのタイミングで順番が狂うと,おそらく矛盾が生じてくるかもと
「何かのタイミング」とやらによるけど
ルールに従って作成しているならリストは、AddTailで追加なので
「最初のビューが消されたら、全部破棄」ということが守られていれば
一番が変わることはないはず
> CDocumentをproptectedに継承した自前のDocでViewを生成する必要がある。
>
えっと,CreateNewFrameにてCDocTemplateから作っているということは,
「自前のDocでViewを生成する」ということになっていますか?
もし,なっていれば「最初のビューが消されたら、全部破棄」のルールがある限り
安心してよさそうですね
> ビューからだけではなく、たとえばプロパティペインなど
> ドッキングペインからドキュメントの変更やビューの追加
> なんかもするような形なのかな?
>
そうなんですよ
でもプロパティペインは使いづらいので設計からはずしました
> GetActiveViewで、アクティブなVIEWはとれます
>
ですね
でも同種のドキュメントの中でもっともアクティブというのを探すのが手間でしたね
ある種別のドキュメントがアクティブになっている状態で,そのドキュメントとは
異なる種別のドキュメントを持つビューでしかもメインのビューを探すとかがあったの
で。。。
GetActiveViewの引数にドキュメントテンプレートを指定できたりするといいんですけど
ね
IsKindOf(RUNTIME_CLASS(名称))とかGetRuntimeClassって乱暴な感じがしちゃうのは
私だけ?。。。
地道にいくことにします