• 締切済み

MFC モードレスDlgについて

はじめまして質問させてください。 VC++ 2005 MFC で開発しております。 以下に動作仕様を記載いたします。 ・ボタン押下でダイアログをモードレスで作成表示。 ・再度ボタンが押下された場合、表示されていれば無視。  表示されていなければ新規作成。 ・モードレスで作成したDlgはクローズ時に完全にDeleteしたい。 以下のように実装しましたところ、 【クラスA】メイン B* pB; pB = NULL; void A::Onボタンクリック{ if( pB == NULL ){ pB = new B(); pB->Create( ID, this ); } pB.ShowWindow( true ); } 【クラスB】モードレス void B::OnCancel() { //CDialog::OnCancel(); this->DestroyWindow(); } void B::PostNcDestroy() { //CDialog::PostNcDestroy(); delete this; } 2回目以降、クラスAで「pB」がNULLにならずに判定部分ではまっております。 どのような方法が最適かお詳しい方がおられましたらご教授お願い致します。 ちなみにポインタではなくメンバ変数の場合だと if( b.GetSafeHwnd() == NULL ) でうまくいくのですが ポイントはモードレスダイアログの毎回Deleteです。 クラスBでフラグを持つことで解決できますが あまりうまいやりかたではないと思うので質問させて頂きます。 以上になります。 よろしくお願い致します。

みんなの回答

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.5

pB->GetSafeHandle()を使って判断は可能なようです # 実装依存なので今後変わらないとはいえないが … Debugモードの場合 不定値としての0xcdcdcdcdが戻り Releaseモードでは 0が帰ってくるようです

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.4

クラスB側で破棄される場合に呼ばれる OnOKやOnCnacelでクラスA側の特定の関数を呼ぶようにコーディングしましょう void A::MyDone() {   pB = NULL; } といった publicアクセスのメンバ関数を用意しておいて クラスB側で void B::OnOK() {   ((A*)this->GetParent())->MyDone();   this->DestroyWindow(); } void B::OnCancel() {   ((A*)this->GetParent())->MyDone();   this->DestroyWindow(); } といった具合にします または RegisterWindowMessegeでクラスBを閉じる場合にクラスAに通知するメッセージを登録しておいて OnOKには this->GetParent()->PostMessage( uMsgRegist, 1, 0 ); OnCancelには this->GetParent()->PostMessage( uMsgRegist, 0, 0 ); などとしておいて クラスA側のメッセージマップに ON_REGISTERED_MESSAGE( uMsgRegist, MyDoneCallBack ) メンバ関数として LRESULT A::myDoneCallBack(WPARAM wParam, LPARAM lParam) {   pB = NULL;   if ( wParam == 1 ) {     // OKで閉じたとき   } else {     // Cancelで閉じたとき   } } といった具合でしょう

回答No.3

 こんばんは。飽くまで参考意見という事で。  クラスBをシングルトンにする。  ただ、質問には「クラスBにフラグ等を持たせたく無い」とあるので、私ならこうする。 【クラスA】メイン class A : public CDialog { public: //フラグを操作するメンバ関数 void SetFlag(bool flagB) { this->m_flagB = flagB; } private: //クラスBダイアログが開いているかどうか 初期はfalse bool m_flagB; //その他色々 }; void A::Onボタンクリック() { //フラグが上がっているので引き返す if(m_flagB) return; //フラグを上げる m_flagB = true; //クラスBダイアログを開く B* pB = new B(); pB->Create(ID, this); pB->ShowWindow(SW_SHOW); } 【クラスB】モードレス void B::OnCancel() { // TODO: この位置に特別な後処理を追加してください。 A* p = dynamic_cast<A*>(this->GetParent()); if(p) { p->SetFlag(false); } this->DestroyWindow(); } void CDlgB::PostNcDestroy() { // TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください delete this; }

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.2

http://msdn.microsoft.com/ja-jp/library/zhk0y9cw.aspx によると、A::BoxDone()をオーバーライドしておけば モードレスダイアログが破棄された時点で通知される、と 読めるのですが、どうでしょうか。

回答No.1

pBのポインタはdeleteしてもNULLにはならず、元の番地を指しているはずだと思うんですが・・・ やるなら pB->GetSafeHwnd() == NULL とかで判定してはどうですか? やったことないんで動作は分かりませんが。

youdoukou
質問者

お礼

vipasigaru 様 アドバイスありがとうございます。 Delete後に pB->GetSafeHwnd()をしても NULLは帰りません。 ですので困っております。

関連するQ&A

  • MFC ボタンのEnableについて

    はじめまして。 質問させてください。 VC++ 2005 MFCで開発しております。 DLGにボタンを配置して ボタン押下後自身のEnableをきります。 するとタブがダイアログ自体も含め どこにも当たらずタブキーが効きません。 OnOk, OnCancelで処理させたいのですが 当然メッセージを取得できません。 ダイアログのアクティブを一度切り替えるとなおります。 解決方法としては ボタン押下でEnableをきった後 ダイアログにフォーカスを当てると正常に動きます。 This->SetForcus(); これはMFCの仕様なのでしょうか? ボタン押下後自身のEnableをきることはよく行う動きだと思いますが。 以上になります。 お詳しい方がおられましたらご教授お願い致します。

  • MFC、ダイアログベースでのモードレス作成

    現在、MFCで検索プログラムを作成しています。 始めはDoModalで作成していたのですが、ダイアログを閉じずに、ダイアログを複数並べて見たいという意見が出た為、モードレスで作成し直そうとしたところ、ダイアログが現れてくれません。 インターネットで見つけたソースを試してみたのですが、上手くいきません。 どなたか教えて頂けますか? =ダイアログに移るボタンコードに= CDlg1 dlg; dlg.Create(IDD_DIALOG1, this); dlg.ShowWindow(SW_SHOW); (dlg.DestroyWindow();は他に記述) 1. 上記では、ShowWindowに0が返ってしまい、一瞬ダイアログが映って 消えてしまいます。Createは1が返ってるのでいいかと思いますが…。 2. あと、違うソースで試したところ、ダイアログは表示できるものの、 一回消してしまうと、もう一度ボタンを押しても再度は表示されません。 しかも、Destroy()を設定したOKボタンでは強制終了となってしまいます。 モードレスで作成すると、一回そのダイアログを消してしまうと再度表示ができないのでしょうか? モードレスってただ他の処理ができるというだけで、そのダイアログを何枚も表示させておくことはできないのでしょうか? 3. このダイアログにjpegファイルを表示させているのですが、ダイアログベース・htmlView以外で表示させれる方法がありましたら教えて下さい。 よろしくお願いします。

  • 【Java】モーダルDLG内でリストを表示

    Javaを学習し始めて間もない初心者です。よろしくお願いします。 ======================================== 開発環境:Eclipse SDK(Version: 3.5.0) 開発言語:Java ======================================== にて、プログラムを作成しています。 メインDLGの中に配置したボタンを押下したタイミングで、 モーダルDLGを開き、そのDLG内にリストを表示させたいのですが、 参考サイトなどを見ながら、とりあえずモーダルDLGは表示されましたが、 リストが表示されません。 下記に作成ソースを記載しますので、解決法をご存知の方おられましたら、 どこが悪く、どう修正すれば良いかについて、ご教示お願い致します。 なお、当方学習中の身ですので、より良いコードを書くために、 その他の指摘などももしあれば幸いです。 【ソースコード】 import javax.swing.*; import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.Frame; import java.awt.event.*; import java.awt.*; public class TestList extends JFrame implements ActionListener{ Dialog dlg; Frame frm; public static void main(String[] args){ TestList frame = new TestList(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 400, 100); frame.setTitle("リスト表示"); frame.setVisible(true); } TestList(){ { // リスト表示ボタンを追加 JButton btn = new JButton("リストDLGを表示"); btn.addActionListener(this); JPanel p2 = new JPanel(); p2.add(btn); getContentPane().add(p2, BorderLayout.CENTER); } } // ボタン押下イベントを取得する関数 public void actionPerformed(ActionEvent e){ // リスト表示ボタンが押下された時 if (frm == null) { frm = new Frame("リスト"); frm.setSize(200 , 200); frm.setVisible(true); String list_n[] = {"テスト1", "テスト2", "テスト3", "テスト4", "テスト5"}; JList list = new JList(list_n); dlg = new Dialog(frm, "リスト" , true); JScrollPane sp = new JScrollPane(); sp.getViewport().setView(list); sp.setPreferredSize(new Dimension(200, 80)); JPanel p = new JPanel(); p.add(sp); dlg.add(p, BorderLayout.CENTER); } } }

    • ベストアンサー
    • Java
  • MFC VC++6.0 DestroyWindowの実装場所について

    [開発環境]:Visual C++ 6.0 現在、Visual C++ 6.0を使ったプログラミングの勉強をしています。 MFC AppWizard (exe)でSDIプログラムのtest1プロジェクト作成後、メインフレームにボタンを実装し、そのボタンを押下するとモードレスダイアログを表示するというアプリケーションを作っているのですが、ダイアログを終了させる時のDestroyWindowの実装場所と実装方法が分かりません。 ダイアログ用のクラスはCmyDialogとしていますが、ダイアログの終了ボタンを実装した場合、そのボタン処理の中すなわちCmyDialogクラスのなかの関数で行うべきなのでしょうか?それともダイアログの作成と同様にメインフレームがわの処理(CTest1Viewクラスでの処理?)として行うべきなのでしょうか?この場合にはどのような場所でどのようなタイミングで実装すればよいのか分かりません。 ご存じの方、これらについて御教授お願いします。 以下プログラムの一部を記載します。 -test1view.cppの一部-(ここでダイアログの作成と表示をしています) void CTest1View::OnButton1() { CmyDialog* myDLG = new CmyDialog; myDLG->Create(IDD_DIALOG1,this); myDLG->ShowWindow(SW_SHOW); }

  • C++のnew演算子について質問です。

    C++のnew演算子について質問です。 以下は関数にポインタを渡して値を得ようしたプログラムです。 ※ディレクティブは省略しています。 void test( int* a ) { a = new int( 100 ); } void main() { int* b; test(b); printf( "%d", *b ); delete b; b = NULL; } このプログラムを実行すると、コンソール画面には100と表示されるかと思っていたのですが、 実際には滅茶苦茶な値と、例外が発生して強制終了しました。 また、関数に渡したポインタのアドレスもNULLとなってしまいます。 そこで以下のようにソースを変更すると正常に100が表示されました。 void test( int** a ) { *a = new int( 100 ); } void main() { int* b; test(&b); printf( "%d", *b ); delete b; b = NULL; } 結果的には目的が達成できたのでいいのですが、なぜこのような動作をするのかが いまいち釈然としません。 new演算子は自動的には破棄されないのではないのでしょうか? 回答の程、よろしくお願いします。

  • 別スレッドとイベントの終了手順について

    C#の質問になります。 メインフォーム上で別スレッドを起動し、別スレッドからのイベントで メインフォーム上のテキストボックスにメッセージを表示しています。 サンプルソースはフォームにボタン2個とテキストボックス1個を貼り 付けたものになり、ボタン1でスレッド起動、ボタン2で停止させてい ます。 正常パターンでボタン1とボタン2を交互に押下すると意図したとおり テキストボックスにメッセージが出力されます。 このプログラムで、ボタン1を押下し別スレッドが起動した状態で、 フォームの×ボタンを押下すると別スレッドの停止処理中にJoin() 呼び出しで永久に止まってしまいます。 止めるべきスレッド中でイベント(OnTraceEvent)を呼び出している のが問題のような気がします。(この処理がなければ正常) このような時の終了手順の王道的なものはありますでしょうか。   public partial class Form1 : Form   {     ThreadTest _thread = null;     public Form1()     {       InitializeComponent();     }     private void button1_Click( object sender, EventArgs e )     {       if ( this._thread == null )       {         this._thread = new ThreadTest();         this._thread.TraceEvent += new ThreadTest.TraceEventHandler( OnTrace );         this._thread.Open();       }     }     private void button2_Click( object sender, EventArgs e )     {       if ( this._thread != null )       {         this._thread.Close();         this._thread.TraceEvent -= new ThreadTest.TraceEventHandler( OnTrace );         this._thread = null;       }     }     private void OnTrace(String message)     {       if ( this.IsHandleCreated == false )       {         return;       }       MethodInvoker process = (MethodInvoker)delegate()       {         textBox1.AppendText( message + "\r\n" );       };       if ( this.InvokeRequired )       {         this.Invoke( process );       }       else       {         process.Invoke();       }       return;     }     private void Form1_FormClosed( object sender, FormClosedEventArgs e )     {       //フォームの×ボタンを押下した時にスレッドを停止しないと       //破棄されたコントロールを操作しようとするため下記を追加       if ( this._thread != null )       {         this._thread.Close();         this._thread.TraceEvent -= new ThreadTest.TraceEventHandler( OnTrace );         this._thread = null;       }     }   }   class ThreadTest   {     public delegate void TraceEventHandler( String message );     public event TraceEventHandler TraceEvent;     protected virtual void OnTraceEvent( String message )     {       TraceEventHandler TraceEventTemp = TraceEvent;       if ( TraceEventTemp != null )       {         TraceEventTemp( message );       }     }     private Thread _threadLoop = null;     private volatile Boolean _threadFlag = false;     public void Open()     {       //スレッド開始       if ( this._threadLoop == null )       {         this._threadLoop = new Thread( new ThreadStart( Loop ) );         this._threadLoop.Start();         while ( !this._threadLoop.IsAlive ) ;       }     }     public void Close()     {       //スレッド停止       if ( this._threadLoop != null )       {         this._threadFlag = false;         //this._threadLoop.Abort();//ここを有効にすればとりあえず終了する         this._threadLoop.Join();         this._threadLoop = null;       }     }     public void Loop()     {       this._threadFlag = true;       while ( this._threadFlag )       {         OnTraceEvent( DateTime.Now.ToString( "yyyy/MM/dd hh:mm:ss:fff" ) );         Thread.Sleep( 100 );       }     }   }

  • C#のフォーム間のデータの受け渡しについて

    はじめまして。よろしくお願いします。 最近C#をはじめましたがいきなりつまづいてしまいました。 クラスを利用しフォーム間でデータの受け渡しをしたいのですがどうすればいいのでしょうか? 処理は以下のようになっております まず、フォームが2つあります。フォーム1とフォーム2とします。 最初に起動されるのがフォーム1で、フォーム1にはボタンが2つあります。ボタンA、ボタンBとします ボタンA、ボタンBどちらのボタンを押下しても、フォーム2が開きますがどちらを押されてたかをフォーム2のテキストボックス(テキスト2とします)に表示します。 クラスですがフォームが2つとデータ保持のためのクラスが1つ(データ保持クラスとします)があります。 データ保持クラスにはint形のBtnClickプロパティ(get,set)を作成しております。, フォーム1のボタンA押下時処理  データ保持クラスのBtnClickに1を格納し、フォーム2を開きます。 フォーム1のボタンB押下時処理  データ保持クラスのBtnClickに2を格納し、フォーム2を開きます。 フォーム2起動時処理  データ保持クラスのBtnClickから値を取得しフォーム2のテキスト2へ表示します。 で、肝心の質問ですが、データ保持クラスの宣言はどこにすればいいのでしょうか? また、インスタンスはどのタイミングで作成すればいいのでしょうか? フォーム1にpublicとして宣言しインスタンスを作成し、ボタン押下時にBtnClickプロパティーにデータを格納し・・・ というところまではできたのですが、フォーム2で値が取得できないどころか、コンパイルが通りません。 あと、こういうデータ保持クラス使い方って一般的ですか?? 長々と脈略もなく書きましたがご教授ください。どうぞよろしくお願いします。

  • Genericsの型パラメータ

    Genericsについて質問します。既存のクラスにGenericsをつけるとエラーになってしまい困っています。 A、Bという抽象クラスがあり、互いに互いのサブクラスを限定したいフィールドを持つという前提で下記のようなコードを考えました。 が、b.setA(this);で 制約の不一致:型TのメソッドsetB(?)は引数(B<T>)に適用できません。 というエラーが発生してしまいます。(Bクラスも同様) その通りに、Bクラスの?をAに変えると警告が発生してしまい、さらに<?>を追加するとやっとなくなり、Aクラスも同様に修正すると両方ともクラスのパラメータ部でエラーが発生してしまいます。 Genericsを使用した解決策を教えてください。お願いします。 pakcage sample; public abstract class A<T extends B<?>> { private T b; public void setB(T b){ this.b = b; if(b.getA() == null){ b.setA(this); } } } pakcage sample; public abstract class B<T extends A<?> { private T a; protected void setA(T a){ this.a = a; a.setB(this); } protected T getA(){ return this.a; } }

    • ベストアンサー
    • Java
  • ダイアログ最前面表示時の後ろの画面操作について

    はじめまして。 お世話になります。 開発環境:WindowsXP VC++6.0 MFC使用 ダイアログベースで画面を作成(A.exe CDialogベース)し、その画面でボタンを押下し 子画面(A_Child)を表示させます。表示方法はDoModal()で。 そのA_ChildはCDialogベースです。 A_Childダイアログが表示されている間(最前面)は、デスクトップ上の操作を 何も出来ない様にしたいのですが、方法はありますでしょうか? (例:スタート→ログオフでダイアログが表示しますよね。 その時ってそのダイアログ以外は触れないですよね。) せめて、自分たちが作成したアプリだけでも操作不可能にしたいのです。 SetWindowPos()、ModifyStyle()、色々試しましたが上手くいきません。 DoModalで表示させるのがそもそもまちがいののでしょうか? 何か方法が有りましたらよろしくお願いします。 説明が下手ですみません。

  • ダイアログを終了させてもハンドルが1つ増加したまま。。。

    VC++のMFCを使ってダイアログベースのEXEを造っています。 ハンドルのリークが発生し、困っています。 <動作内容> メインのダイアログで、ボタン押下により別のダイアログを表示します。 DoModal()でモーダルダイアログを作成します。 別のプロセスからブロードキャストされるメッセージを処理したいため、 ボタン押下のルーチンで DoModal() せずに、スレッドを作成し、 そのスレッドで DoModal() を実行しています。 スレッド作成は AfxBeginThread() を使用しています。 <サンプルソース> ●メインダイアログ // ボタン押下のルーチン void CTestModalDlg::OnButton1() { AfxBeginThread( TestDlgThread, (LPVOID)this, THREAD_PRIORITY_NORMAL ); } // スレッド static UINT TestDlgThread(LPVOID pThis) { CTestDlg1 Dlg; Dlg.DoModal(); } ●DoModal() で表示されるダイアログ 何も手を加えてない、デフォルトのまま。 <結果> DoModal() で表示されたダイアログを CDialog::OnCancel() で終了させ、 メインのスレッドが終了しても、ハンドルカウントが1つ増加しています。 Sleep() を入れて値をみてみると、 ・スレッド作成:2増加 ・DoModal() でダイアログ表示:1増加 ・OnCancel() で終了:増減なし ・スレッド終了:2減少 =>結果、1増加となっていました。 以下のパターンでは問題ありませんでした。 ・スレッドを作成+終了(ダイアログ表示しない) ・スレッドを作成せずに、ボタン押下ルーチンから DoModal() でダイアログ表示+終了 ということで、AfxBeginThread()、DoModal() 自体は問題ないのですが、 スレッドを作成して DoModal() するとリークが発生します。 識者の方、原因、対策など、ご教授願います。