ryoさん、レスありがとうございます。
しかし、VIEWは、再描画しませんでした。
(途中経過)
○View側のコーディング(OnDraw()で拡大率(m_Magnify)にあわせた表示をしていま
す)
void CNekketsuView::SetMagnify(const int aMagnify)
{
m_Magnify = aMagnify ;
Invalidate() ;
}
○メインフレーム側のコーディング
void CMainFrame::OnMag2()
{
CNekketsuView * wActiveView = (CNekketsuView * )(MDIGetActive())-
>GetActiveView() ;
if (wActiveView->IsKindOf(RUNTIME_CLASS(CNekketsuView))) {
wActiveView->SetMagnify(2) ;
}
}
目的のViewがアクティブな場合、再描画しますが、
実際、目的のViewがアクティブでない場合がでてきたので、どうするか考えています。
拡大倍率をドキュメントで持つのはおかしい気がします。
SDI だとあまり実感が沸かないでしょうから、Doc-View形式で作る場合は、基本的
にMDIで考えるべきです。
そうすると、1つのドキュメントを拡大率の異なる複数のビューで表示することが
あり得ることに気付きます。
ドキュメントに拡大率を持ってしまったら、複数の拡大率を1つのドキュメントで
管理せねばならず、おかしな設計となります。
よって、この場合、スマートな設計と言えるのは、
拡大率をビューで持つか、チャイルドフレームで持つかのいずれかになります。
SDIの場合、チャイルドフレームは存在しないので、ビューで正解という結論に落ち
着きます。
再描画要求もMDIで考えると脳みそがスッキリします。
以下の処理の流れで、
-> 1対1の処理の流れ
=> 1対多の処理の流れ
として記述します。
[拡大率]が変わるイベント発生
->
CDocument::UpdateAllViews()
=>
CxxxView::OnUpdate() // 拡大率の異なる複数のViewに一斉送信
->
CxxxView::Invalidate() // 個々のView内で自分自身を再描画するために
または InvalidateRect() // Invalidate()を呼び出す(熱血さんが実装のこと)
->
WM_PAINTメッセージ発生
->
CView::OnPaint() // CViewクラスに実装されたWM_PAINTのハンドラ
->
CxxxView::OnDraw() // CView::OnPaint()からvirtual呼び出し
複数ビューへの対応は CDocument::UpdateAllViews()を呼び出せば、MFCが全て面倒
を見てくれるので、熱血さんは面倒を見なくてよいです。
その結果、再描画が必要な状況だったら、OnUpdate()内でInvalidate()を呼び出し、
そうでなければInvalidate()を呼び出さないという流れです。
ちなみに、Doc-Viewのイメージですが、
チャットとかテレビ会議とかを思い浮かべると近いかなと思います。
チャットの場合、チャットルームに入室要求をするのはユーザ側です。
Doc-Viewで言えば、新たなビューを開くことがこれにあたります。
誰かがチャットで発言をすることが、Documentの更新です。
Documentが更新されたら、即座に UpdateAllViews() で全ビューに
反映します。
これが、発言をチャット入室者全員の画面に反映することにあたります。
なんとなくイメージできますか?
bunさん、レスありがとうございます。
> 拡大率をビューで持つか、チャイルドフレームで持つかのいずれかになります。
チャイルドフレームにダイアログバーをもつといろいろ制約があるので、拡大率のメン
バ変数は、ビューでもつことにしました。
今現在、MDIで1つのドキュメントに対し2つのVIEW。一つは、絵をだして、一
つはダンプみたいなものをだしています。フォーカスがダンプの方へいっていると、メ
インフレームの倍率変化のバーをクリックしてもだめという状況です。
○メインフレーム側のコーディング
void CMainFrame::OnMag2()
{
CNekketsuView * wActiveView
= (CNekketsuView * )(MDIGetActive())->GetActiveView() ;
if (wActiveView->IsKindOf(RUNTIME_CLASS(CNekketsuView))) {
wActiveView->SetMagnify(2) ;//2倍
}
}
> フォーカスがダンプの方へいっていると、メ
> インフレームの倍率変化のバーをクリックしてもだめという状況です。
コーディングされている通りの正しい動作と思いますが。
フォーカスがダンプの方にいっているということは、
MDIGetActive())->GetActiveView()
がダンプViewを返しているのだから、表示倍率の変更はできないでしょ。
それともダンプ画面の表示倍率を変えたいの?
CNekketsuView は絵を表示しているViewですか、ダンプを表示しているViewですか?
まさか両方ともCNekketsuViewであり、初期設定等で表示内容を変えているってことは
ないよね。
Doc-Viewの考え方は、確かに分かりづらいところなので、
サンプルを示します。
熱血さんの例にしたがって、Doc-View風コーディングをすると
以下のようになります。
かなり、はしょってますが、先ほどの話と合わせて、これで分かるかな。
void CMainFrame::OnMag2()
{
m_nMagnify = 2;
GetActiveDocument()->UpdateAllViews(NULL, UPDATE_MAGNIFY);
}
INT CMainFrame::GetMagnify() {return m_nMagnify;}
void CNekketsuView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();
switch(lHint)
{
case UPDATE_MAGNIFY:
SetMagnify(pMainFrame->GetMagnify());
Invalidate();
case ????
:
}
}
void CNekketsuView::OnDraw(CDC* pDC)
{
// CNekketsuView::OnUpdate()関数内で、SetMagnify()した値を使って
// 描画を行う
}
CNekketsuViewが絵を表示するビューだと仮定してます。
ダンプを表示するビューは拡大/縮小は関係ないはずなので、
OnUpdate()関数内で、
case UPDATE_MAGNIFY:
を省略します。
これで、上記の話の
> そうでなければInvalidate()を呼び出さないという流れです。
ということになります。
bunさん、レスありがとうございます。
> コーディングされている通りの正しい動作と思いますが。
それは、わかるのですが、アプリケーションとしては、ダブルVIEW表示(セパレー
トつかってます)で、エンドユーザから見ると二つのVIEWとも、アクティブになっ
ているという、イメージをもたせているので、(実際プログラムでは、できないとおも
いますが)ここで、ユーザインターファイスをどうしようかと思っています。
左VIEWのダンプがフォーカスされていても、ユーザが表示倍率を変えるような操作をし
た場合、右VIEWに、再描画され、表示倍率が変わるという、動作が理想的だと思いま
す。で、ちょっといろいろ考えているところです。
通常は表示倍率が有効でない左Viewにフォーカスがある場合は
表示倍率のコントロールは無効化すると思います。
無効化していても表示は見えるはずなのでその時点の表示倍率の確認は
可能ですよね。で、表示倍率が有効な右Viewにフォーカスがある時に
表示倍率のコントロールを有効化します。
これだったらリーズナブルな動きになるのではないかと思います。
ドキュメントに関連付けられているViewを順番にチェックして
右Viewを探し出せれば、何とかなりそうな気もしますけれど
どうしたもんですかねぇ。
ダブルVIEW表示って何?
ダンプ画面と表示画面がセットになっている様なチャイルドフレームが有るのなら、
そのフレーム経由でダンプ画面から表示画面に要求を送ればいいんではないのかな。
またはそのセットになっている二つのビューを持つ新たなビュークラスを作るのが
正しいのではないだろうか。
Doc-Viewアーキテクチャーではドキュメントに複数のビューを関連付けられます。
その複数のビューは同一のクラスであっても大丈夫です。つまり一つのドキュメント
を複数の同じ種類のビューで表示することが可能です。熱血さんのアプリケーション
でいえば一つのドキュメントに対して、二つの絵を表示し、片方が1倍でもう一方が
2倍で表示するということが可能になります。
そう考えるとやはり倍率を保持するのは各ビューにすべきで、ユーザは倍率を変える
べき対象を選択しておくことが必要になります。で、ダンプ画面と表示画面がセット
になっているのであれば、そのセットをアプリケーションが管理すべきです。(ここ
でいうアプリケーションはCWinAppの派生クラスのことでは有りません。)
> 通常は表示倍率が有効でない左Viewにフォーカスがある場合は
> 表示倍率のコントロールは無効化すると思います。
この辺はPATIOさんに全面的に同意しますが、
> ドキュメントに関連付けられているViewを順番にチェックして
> 右Viewを探し出せれば、何とかなりそうな気もしますけれど
順番にチェックするより、左右のビューをセットで管理しておく方がいいと思います。
PATIOさん、maru さん、レスありがとうございます。
> 通常は表示倍率が有効でない左Viewにフォーカスがある場合は
> 表示倍率のコントロールは無効化すると思います。
なるほど、そういうものなのですか・・。
>ダンプ画面と表示画面がセットになっている様なチャイルドフレームが有るのなら、
>そのフレーム経由でダンプ画面から表示画面に要求を送ればいいんではないのかな。
その手がありましたか・・という感じです。
>左右のビューをセットで管理しておく方がいいと思います。
ちょっと、いろいろ試してみます。
>>左右のビューをセットで管理しておく方がいいと思います。
>ちょっと、いろいろ試してみます。
私の示したサンプルがその例です。
UpdateAllViews()で、その名前の通り、
左右のビューを同時更新するということです。
> 私の示したサンプルがその例です。
> UpdateAllViews()で、その名前の通り、
> 左右のビューを同時更新するということです。
そんなことを言っているつもりはないんだけどなぁ。
私が言っているのは左右の左右のビューを管理するものが必要といっているんで
あって、それはドキュメントではないということ。なぜドキュメントがその目的
にふさわしくないかは以前に述べたとおり。
まぁ、一つのドキュメントに一つの左右ビューしか関連付けしないなら問題はな
いけどね。
何か勘違いしてますか?
そうでしたら、失礼しました。
ちなみに...
私が伝えたかったのは、Doc-View の基本的な考え方です。
その昔、VisualC++6を購入した時、添え付けられていた入門書(VisualC++6プログ
ラム入門だったかな?)の受け売りです。
あの本の住所録のサンプルが非常に分かりやすくて、その内容を伝えたかったので
すが、短い言葉だけで伝えるのはとっても難しいですね(汗)。