環境はVC++2008のMFCです。
SDIで作っているペイントソフトに似たシステムがあるのですが、
複数のファイルを同時に開いて閲覧することが多くなったため、
1つのウィンドウで管理することにしました。
最初はMDIで作り直すしかないと考えたのですが、
それよりも容易にSDIで実現できる方法があればアドバイスをお願いできないでしょうか?
私はSDIにタブコントロールを配置し、その内部にビューを描画してMDIもどきを作ろうな
どと考えましたが、
実装方法が不明で悩んでいます。
結局、何をやりたいのかと言う話になると思います。
MDIの形で実現する方法もあるでしょうし、
今考えられているようなタブを使った方法もあると思います。
MDIで作成すれば、MFCの雛形をそのまま生かせる事がメリットですが、
作り直しになる部分が出るのは仕方ありません。
既定のMDIの動作に何処までこだわるのかと言う部分も一つの条件だと思います。
MDIでの動作に拘らずに単純に複数のウインドウを開いて同時に閲覧したいという
話なのであれば独自実装も有りでしょうから方法論は色々あると思いますよ。
あとは何処まで自分で作りこむの?と言う話ですね。
ウインドウ制御の基本がわかっていれば、独自実装で複数ウインドウを開くのは
そこまで難しい話では無いと思います。
但し、開いているウインドウの管理部分は自分で考える必要があります。
回答ありがとうございます。
タブを使った方法は可能ということですね。
新規作成、開く、閉じる、に対応できれば私の目的は達成です。
解決できるか分かりませんが、実装方法を引き続き調べてみます。
大本に戻ってみると何かきっかけがつかめるかもしれません。
・DOSの実用アプリはほとんどかMDIだった
ただし、画面がアルファベットで80文字×24行しかなかったという事情で
表示できるのは1ファイルのみが多かったですね。もちろん全て同じ種類
のデータです。
・MDIの概念はWindow3.xのSDKがはじまりっ
それまでは無かったのですね。ファイルマネージャ(今のエクスプローラ)が採用。
SDKで公開されました。これがきっかけでMDIアプリの全盛期を迎えることに
なります。20年も前のことです。
・Win95ではSDIにやや先祖帰りしたのだが・・・
Wordの祖先はWordPadの祖先と同じでSDIでした。Win3.xでMDIになり、
Win95時代にはSDIに先祖帰り、Win98時代からまたMDIに戻り・・・(vv;)。
・MDIでもSDIでもないアプリもいっぱいあるぞ
統合開発環境(VisualStudio)やIEなんかがそれですね。
基本的に複数種類のドキュメントを複数種類のViewで表示。
MSさんはエクスプローラスタイルとかって呼んでますね。
・選択は無限だ、新しいスタイルを創造してください。
ユーザーを快適にしてやってください。
それを何と呼ぶのかなど関係ありません。
アドバイスありがとうございます。
今現在、足りない頭をフル回転させてやみくもに実装中です。
まずはファイルの新規作成からタブでのファイル切り替えまでです。
・タブコントロール(タブの部分だけ)を配置したダイアログバーを、メインフレームの
下にドッキングさせる。
・ファイルの新規作成時にタブページを1つ追加し、ドキュメントクラスのインスタンス
をリストに格納して、CWinApp::OnFileNew()は実行させなくする(ドキュメントの中身が
削除されるため)。代わりに、2回目以降の新規作成時はドキュメントのインスタンスを
newして生成する。
・タブをクリックするとリストと連動させ、該当のドキュメントをアクティブなドキュメ
ント?にする。
今実現しているのは上から2つ目までです。
用語が適切ではないかと思いますが、リストから該当のドキュメントを取得して「アクテ
ィブ(編集対象)にする」方法が分からず躓いています。
システム上でビューは1つだけで、ドキュメントのみを切り替える構造をイメージしてい
ます。
上記の内容から指摘、アドバイス等いただければ有難く存じます。
既存のドキュメント-ビュウ アーキテクチャをそのまま使っているのなら
その部分の関連付けの処理とかどういう状態で保持されているとかその辺も含めて
理解した上で無いと漏れが出そうですね。
私の場合、この部分に手を入れた事が無いので正直な話良くわかりません。
構造的に一つのビュウに対して複数のドキュメントを切り替えるというやり方が
可能なのかも良くわかりませんし。
いっその事、データもウインドウを対に自分で管理して
タブの状態を見て表示対象にするウインドウを切り替えた方が
すっきりわかりやすそうな気もしますが、
ドキュメント-ビュウ アーキテクチャの部分を把握した上で
利用できるならそれはそれで良いと思うので調べて見た方が良いかもしれません。
MFCのソースがついていると思うので追っかけてみるの手ですよ。
まずは基本的な方針を決めたほうが良いかもしれません。
・Viewを作るのにDocとDocテンプレートを使用するかどうか。
1.する場合
・DocにViewを管理させるかどうか
1.1 させる場合
ドキュメントビューアーキテクチャに準拠してコードする。
1.2 させない場合
Doc経由でなく、独自にViewを管理し、MFCに何もさせない。
Docはただのお飾り。あとは好き放題。
2.しない場合
CCreateContextを拡張して独自のFram/View作成関数を実装する。
DocはそのClass自体不要なので簡単。あとは好き放題。
・そもそもドキュメントビューを使わない。CViewの派生クラスも使わない。
部分的にMDIにしたいなら、CreateMDIWindow()などを使う。
そうでないなら、CreateWindowEx()する。
・全てのViewをそうするか、Viewの性質によって構築方法を選ぶか
一般に、元がSDIスタイルなら、主たるドキュメント以外はDocを
外しても問題なし。
てなことを、検討するべきかもしれません。
うーん、何から話すべきか悩みましたが、
>私はSDIにタブコントロールを配置し、その内部にビューを描画してMDIもどきを
>作ろうなどと考えましたが、
タブ切り替えでビューを切り替えるイメージなら、まぁSDIベースで作っても、
MDIベースで作っても苦労は多いでしょう。
SDIベース → 複数Doc-Viewの管理が難しい
MDIベース → ViewがChildFrameの子ウィンドウになるように実装されているため
ChildFrameからタブコントロールへの関連づけ変更が難しい
Doc-View機能を生かしつつ、できるだけ綺麗に実装するなら、
いっそのこと、CDocTemplateの派生クラスをご自分で実装されてはどうでしょう。
必要な関数はほとんどvirtualになっていますので、綺麗な形で実装できるはずです。
私ならば、基本は CSingleDocTemplate の実装とし、
CDocument* CSingleDocTemplate::m_pOnlyDoc を
CList<CDocument*> CSingleDocTemplate::m_DocList とかに置き換えるかな。
もしかすると、CSingleDocTemplateの派生クラスとして実装してもいいかも。
CMultiDocTemplateを見ると、複数ドキュメントの扱い方も分かるはずです。
あとは、フレームとの関連づけをタブコントロールとの関連づけに置き換えれば
完了です。
試してないので、全て憶測ですが、参考になりましたら幸いです。
すみません、遅くなりました。今現在の状況です。
皆様のアドバイスを考慮しまして、できる限りSDIのドキュメントビューアーキテクチャ
に準拠しておいた方が安全だと感じ(そもそも難しく考えすぎていました)、ビューとド
キュメントの関係には手を加えないようにしました。ただビューに関してはCTabViewとい
う便利なものがあったのでそちらを使いました。
・CDocument型の派生クラスに、描画するデータをまとめたクラス(本体)を1つ持たせ
る
・ビューには常に本体のデータのみを描画させる
・同じ型でリストにしたもの(退避用)を別に持たせる
・タブの切り替えに応じて本体を退避用リストにコピーした後、退避用から該当のデータ
を本体にコピーして画面をリフレッシュする
上記だけを見ればもはやMFCにすら無関係で低水準な考え方に思えますが、複数ファイル
を操作しているように見せかけることはできました。ただこれで実用していいものか疑問
が残るので、ドキュメントビューアーキテクチャを活用できる状態になればそちらにも手
を加えてみようと思います。
>bunさん
>MDIベース → ViewがChildFrameの子ウィンドウになるように実装されているため
> ChildFrameからタブコントロールへの関連づけ変更が難しい
私はMDIで開発したことはありませんが、
少し触ってみると標準機能として複数ファイルを開いてタブで切り替えられるようなので
すが、それとはまた別の話でしょうか。
Doc-Viewは「ViewとDocは一蓮托生」のようなモデルに意地悪なほど忠実です。
このモデルの原型はたぶん「Word」なんでしょうが、一般的にはこのような
単純なモデルが使えるのは非常に限られた幸運なケースに過ぎません。
こういった融通の利かないモデルとは、せいぜいFrameとViewを作ってもらう
程度の付き合いが適切かもしれません。
シリアライズもまったく省力化にはなってませんしね。
まぁ、クラス間の隔離と、巧妙な隠蔽(実際は構築中にはFrame/Doc/Viewは
お互いにお互いを知っている)については研究の価値はあるかもしれません。
ドキュメント-ビュー アーキテクチャは、多分下敷きにMVCモデルがあって
ドキュメントと呼んでいる部分がモデルに当たり、
ここで言うビューがMVCのViewとControllerが一緒になったものかなと思っています。
ドキュメントクラスは、WordやExcelのようにドキュメントを扱うようなケースを
ベースに考えられているようなので用途によってはオーバースペックだったり、
逆に適応させるのが難しい(もしくは概念的に合わない)ケースもありますね。
例えば、地図データのビューアのように単純に表示したい場合で
特にユーザーに表示する地図データを選ばせるような事しないケースでは
Doc-Viewアーキテクチャはかえって邪魔になる事があります。
起動したら決まったところにあるデータにアクセスして表示するだけなら
不必要な部分がかなりあるからです。
Doc-ViewアーキテクチャはMFCが作成された初期の頃からある考え方なので
ある意味古臭くなっているのか知れません。
役割分担をしっかりして設計するという意味(クラス間の隔離)では
大いに意味があると言う点では、仲澤@失業者さんに賛成です。
無計画にクラスを作成してしまうと各クラスの役割がぼやけて
実装が歪むなんて事は良くある話です。
これは、ウインドウ間の役割分担に関してもいえる事ですけれど。
動かす事に気をとられて各モジュールの役割を分離する事を失念しないように
設計する必要があると思いますよ。
Doc-Viewの考え方の基本は、1つのドキュメントで1つのファイルを扱うことに
あります。つまり、
ファイル:ドキュメント:ビュー = 1:1:多
です。
この
ドキュメント:ビュー = 1:多
の部分を実現するのがCTabViewであるように思います。
最初の話である
>SDIで作っているペイントソフトに似たシステムがあるのですが、
>複数のファイルを同時に開いて閲覧することが多くなったため、
>1つのウィンドウで管理することにしました。
からすると、ファイル自体をたくさん開きたいということなので、
ファイル:ドキュメント:ビュー = 1:1:多
において、ファイルそのものが[多]になってくるわけです。
それは、すなわち複数のドキュメントを同時に扱うことを意味します。
複数のドキュメントはSDIでは同時に扱えません。
だから、Doc-Viewの仕組みとしてはMDI(Multiple Document Interface)レベルの
ものが必須なのです。
そして、MDIは各ドキュメントをCMdiChildWndの子ウィンドウとして表示します。
これを各タブページの子ウィンドウに置き換えてやる必要があるわけです。
意味伝わりますかねぇ?
>少し触ってみると標準機能として複数ファイルを開いてタブで切り替えられるよう
>なのですが、それとはまた別の話でしょうか。
MDIは、タブでは無く、子フレームの切り替えで複数ファイルを切り替えます。
なので、タブで切り替えられるように改造すればいいわけです。
で、そのための最短路が[CDocTemplateの派生クラスの実装]ではないか?
というのが私の意見なわけです。
元々、Doc-Viewアーキテクチャは、Doc(データ)とView(表示部)を分ける事で
同じDocに対して結びつけるViewを変更できる。
データハンドリング部は共有できると言うのが基本にあったはずです。
bunさんが書かれている1:多と言うのがそれですね。
実際にはViewを何種類も作成して表現を変えるなんて事は殆どやってませんけれど。
Doc-Viewの仕組みに拘るのであれば、MDIにしてDocとViewのペアを複数管理する
ような仕組みになるのだと思いますけれど、仕組みに何処までこだわるかと言う話に
なるかなと思います。MFC的には複数ドキュメントならMDIと言う話になるかもですが、
SDIのGUIで複数ファイルを扱いたいと言う話もないわけではないですから。
アプリケーション自身が開かれている複数のファイルを管理する必要がないなら
複数起動を可能にしてSDIを複数起動すれば複数のファイルを同時に表示する事は
不可能ではありません。
表示用の実行モジュールと各モジュールをコントロールするメニュー用実行モジュールで
構成して連携させると言う手もないわけではありませんし。
まあ、やり方論の話なので必要な要件を実現する為にどういう実装を選択するか
と言う話になると思います。
ここから先はご本人次第かなと思いますね。
メンテナンスしやすい実装になっている事が望ましいと言う所なんでしょうね。
もしかしたらわかりにくかったかもと思ったので。
Docが一つでViewが複数と言う話をしましたけれど、
Docが一つと言っているのはインスタンスの話ですね。
一つのドキュメントファイルに対してインスタンスが一つ起きるというイメージ。
複数のファイルを扱う場合、インスタンスは複数存在する状態になるのが
素直な実装になります。
Viewが複数といっているのも実際にはインスタンスの話です。
Viewは表示に必要な情報を全て保持する必要がありますから
Viewのインスタンスは自分と対になっているDocの表示する為の情報を保持します。
(例えば、ドキュメントのどの部分を表示している等の情報です)
ViewからみたらDocとの関係は1対1です。
この対を一つしか持たないのがSDIで、複数管理しているのがMDIです。
だからMDIではタイル表示のように同時に表示する事が出来ます。
まあ複数のファイルを同時表示可能な状態に保つとなるとその分だけメモリを
食いますからその辺は動作環境ともご相談になりますね。
もっとも、最近のPCはハイスペックな物が多いので問題になるケースは
少ないかもしれませんけれど。