いつもお世話になっています。CCです。
1、ViewクラスにモーダルDialogBoxを生成しています。
2.DialogBoxにあるListBoxがあります、
問題:
ListBoxに表示している項目をクリックすると
Viewクラスのある関数を呼び出したい。
ある関数の引数は, CDC* pDCを含まれっています。
環境:.Net2002 MFC使用
よろしくお願いします。
クラスと言う考え方をそのまま貫くのであれば、
Viewクラス上で行うべき事はViewクラスにさせるべきだと思います。
で、Dialog側でやるべき事は、呼び出す処理を特定する為の情報と
呼び出しに必要な情報(Dialog側が持っているなら)を引き渡して
Viewによろしくとお願いする事だと思います。
同一アプリ内であれば、ユーザー定義のウインドウメッセージを
使ってViewに対して通知する事をトリガにして処理をすれば、
比較的簡単に実装できます。
DialogがViewのポインタを保持していてViewのクラスを認識しているなら
ポインタを通じてデータの引き渡しは出来そうですね。
あと、Viewの関数を呼び出す時に引き渡すCDCのポインタは
どのウインドウのCDCを期待しているのでしょう?
文面からでははっきりと断定できません。
単純に考えるとViewのCDCなのかなとも思えるのですけれど。
CDCが含まれると言う事は描画を行なうのですよね。
ならば、直接呼ばずにInvalidateを呼ぶ手もあると思いますけれど。
関数を呼び出して、親ウィンドウをどうしたいのかわからないが
大抵の場合、
モーダルダイアログを表示中に、親ウィンドウを弄るのはあまりよろしくないかと
親ウィンドウがもってる変数に値を入れるぐらいは問題なくできるが…
あと、モーダル中にメッセージを飛ばして、親ウィンドウはうけとれましたっけ?
>ListBoxに表示している項目をクリックすると
>Viewクラスのある関数を呼び出したい。
>ある関数の引数は, CDC* pDCを含まれっています。
そのDLGがVIEWを知ってるなら好きなように呼べは良いと思います。
そのVIEWを知らないで、親のHWND経由で探すのは、特にMFCの場合
困難になる場合があります。これは、MFCがDLGの引数に指定したCWnd
ではなく、そのルートのトップレベルフレームを親にしてモーダル
(場合によってはモーダルの様に振舞うモードレス)DLGを作成するからです。
また、CDCはVIEWのHWNDに関連付けて作らないと意味無いので、注意が
必要です。その関数をラップする関数(この中でClientDC等を作成して当該
関数をコール)を作成したほうが楽かも。
>あと、モーダル中にメッセージを飛ばして、親ウィンドウはうけとれましたっけ?
できます。(大昔のシステムモーダルは別(vv;)
PATIOさん、ryoさん、仲澤@失業者さん
ご返事ありがとう。
>DialogがViewのポインタを保持していてViewのクラスを認識しているなら
>ポインタを通じてデータの引き渡しは出来そうですね。
すみません、具体的な例を教えていただきませんか。
>単純に考えるとViewのCDCなのかなとも思えるのですけれど。
はい、ViewのCDCです。
>CDCが含まれると言う事は描画を行なうのですよね。
>ならば、直接呼ばずにInvalidateを呼ぶ手もあると思いますけれど。
いままで、Invalidateを使ってやっています。
でも、画面上で、頻繁にやるとちらつきになっています。
回避するため、直接の描画関数を呼び出したい。
やることは、次のことです。
線と線を交差していますが、画面上で交差の点を選択します、
複数の点場合、DlgBoxを開きます、
選択されたの点はどちの線になっているか、DLGBoxのListBoxで表示されます、
そのListBoxの一覧に選択すると、該当の線の色を変わるという目的です。
void CSelct_Line_DLG::OnLbnSelchangeList2()
CFrameWnd* pFrame = static_cast<CFrameWnd*>(AfxGetMainWnd());
if(pFrame != NULL){
CWnd* pWnd;
pWnd = pFrame->GetActiveView();
if(pWnd != NULL){
pWnd->InvalidateRect(m_LineRect); //ここまで、
//以下は選択された点を表示し、前に選択された点を消す
if(mOpenType==221)
SetList1(mOpenType);
if(mOpenType==21 || mOpenType==22 || mOpenType==12204){
if(Old_pRect !=pRect)
pWnd->InvalidateRect(Old_pRect);
//前のPoint画面上で消す
pWnd->InvalidateRect(pRect);
SetList21(mOpenType);
}
}
}
}
問題というのは、
選択された点の線だけ、色が変わります。
画面の全体を再描画しないこと。(頻繁にやるとちらつきになっています。)
当然、モードレスDlgは一つの選択肢だと思います、
今回モーダルDialogBoxを使って、OKボタンを押さない限りに
別の場所に選択されないこと。
(他の場所に触らなくない)
View側に
OnDraw_StructClassPart( pDC );
があります、
DlgBox側にOnDraw_StructClassPart( pDC );をどう呼び出し。
よろしくお願いします。
更新するべき部分が特定できるならInvalidateではなくてInvalidateRectを使います。
ちらつくというのは画面が一旦クリアされて書き直される様子が見えてしまうから
ちらつくわけで、これを回避するにはフレームワークのバックグラウンドの消去を無効に
してメモリ上のバックバッファで書いて画面に転送するとチラつきが軽減できます。
>DialogがViewのポインタを保持していてViewのクラスを認識しているなら
>ポインタを通じてデータの引き渡しは出来そうですね。
えと、どの当たりがイメージできないのかを説明してもらった方が良いかも。
言葉的にはそのまんまの事を書いているので。
>すみません、具体的な例を教えていただきませんか。
ダイアログにビューのポインタを持てるようにして
class ダイアログ : 略
public:
ビュー * m_pVew;
ダイアログのDoModalするまえにビューのポインタを設定しておくだけ。
ビューでDoModalするならビューのポインタは自分のことなのでthis。
ダイアログ.m_pVew = this;
ダイアログ.DoModal();
ダイアログのヘッダーファイルでは先にclass ビュー;って書いとけばいい。
ダイアログの実装では先に#include ビュー.hって書いとけばいい。
これで、アクセスできる。
m_pVew->OnDraw_StructClassPart();
うろ覚えなので動くか知らん
ビュー::OnDraw_StructClassPart()
{
CClientDC dc(this);
OnDraw_StructClassPart(&dc);
}
PATIOさん、wclrp ( 'o') さん
ご返事ありがとう。
>ちらつくわけで、これを回避するにはフレームワークのバックグラウンドの消去を無効
>に
>してメモリ上のバックバッファで書いて画面に転送するとチラつきが軽減できます。
そういう方法がどうやればできるのでしょうか。
(初めて、そういうことを聞きました)
>ビュー::OnDraw_StructClassPart()
>{
> CClientDC dc(this);
> OnDraw_StructClassPart(&dc);
>}
やってみたら、
CClientDC dc(this);ここで、エラーが出ました。Debug Assertion Failed!
どう解決するかわかりません。
よろしくお願いします。
> そういう方法がどうやればできるのでしょうか。
> (初めて、そういうことを聞きました)
ダブルバッファとかバックバッファとかで調べれば出てくると思います。
描画の高速化の手法としてはポピュラーな物なので。
最初の内はとにかく表示出れば良いと言う感じで組むと思うのですが、
とりあえず表示ができるようになると欲が出てきますよね。
で、その辺の部分は皆通る道なので割と解説しているHPも多いです。
さらに踏み込むと今度は情報が減ってきますけれど。
とりあえず、調べて見てわからない所をまた質問してください。
> CClientDC dc(this);ここで、エラーが出ました。Debug Assertion Failed!
>
> どう解決するかわかりません。
せっかくDebug Assertion Failed!と出ているのですから
情報を利用しましょう。もともとASSERTはデバッグ時に拙い箇所を
見つけやすくする為にある物です。リリース版でリンクすると
出なくなりますが、それは拙いよと言うメッセージが出なくなっただけで
拙いままになっていると言う事になります。
出てきたAssertionはちゃんと対応する必要があります。
何処でAssertが起こっているかも表示されていると思うので、
その部分を探して見てみることをお勧めします。
たいていの場合、そのAssertがどういうものなのかの説明が
コメントで入っていますよ。(英語ですが)
あと、メッセージボックスとかOutputのウインドウに表示された内容は
かなりの確立でデバッグの材料になります。
これはデバッグに必要ないという確信が無い限りは
全ての内容を提示した方が話が早い場合が多いです。
PATIOさん、
ご返事ありがとう。
>で、その辺の部分は皆通る道なので割と解説しているHPも多いです。
http://t-recipe.com/vc/flicker.html
見ていました。
>あと、メッセージボックスとかOutputのウインドウに表示された内容は
>かなりの確立でデバッグの材料になります。
>> CClientDC dc(this);ここで、エラーが出ました。Debug Assertion Failed!
エラーメッセージ
.exe の 0x7c22e51f (mfc70d.dll) でハンドルされていない例外が発生しました :
0xC0000005: 場所 0x0000002a を読み込み中にアクセス違反が発生しました。 。
推測:
DlgBoxから
ビュー::OnDraw_StructClassPart()
{
CClientDC dc(this);
OnDraw_StructClassPart(&dc);
}
を呼び出すと、dc(this)とViewのdcは別物でしょうね、
どうすればいいでしょうか。
(既にView側dcを使いたい)
調べたのですが、
DialogがViewのポインタを保持していてViewのクラスを認識している
と思っています。
実際、そうではないか、あまり自信がない。どう検証するかわかりません。
よろしくお願いします。
DlgBoxと言われているクラスでビューのメソッドを呼び出す為には
ビューのインスタンスが必要になりますけれど、
インスタンスはどうやって得ているんでしょう?
実際にはビューの実体は既に存在するはずなので参照かポインタで
使おうとすると思うのですけれど。
クラスのメンバー関数を呼び出す為にはクラスのインスタンスが必要という
部分は理解されているでしょうか?
もしかしてC++言語の文法で分からないところとか無いですか?
PATIOさん
ご返事ありがとう。
>インスタンスはどうやって得ているんでしょう?
モーダルDialogBoxの場合はどうやって得ることがわかりません。
もしよろしければ、例を示してありがたいです。
よろしくお願いします。
となるとどうやってDlgBoxと言われているクラスでビューのメンバー関数を
呼び出しているのですか?
インスタンスが得られなければ、呼び出す事は出来ないと思いますけれど。
確実にしたいのであれば、DlgBoxなるクラスに親であるビューのポインタを
メンバー変数として追加して、DoModalする前に設定すれば良いかと思います。
この辺の話に関してはモーダルだろうがモードレスだろうが同じ事です。
あと、C++言語の文法に関する知識に関しては一通りあると言う認識で
良いのでしょうか?
これが足りないのであれば、こっちの補強をしないと進むのに無理があると
思いますけれど。
C++言語の勉強とMFCの使い方をいっぺんに勉強するのは無理が有りますよ。
MFCを使わずにコンソールアプリでC++言語を使って簡単なアプリが
作成できるくらいの知識はありますか?
PATIOさん
ご返事ありがとう。
>メンバー変数として追加して、DoModalする前に設定すれば良いかと思います。
wclrp ( 'o') さんから
>ダイアログ.m_pVew = this;
追加したら、うまくできました。
どうもありがとうございました。