MFC - ボタンの処理について

このQ&Aのポイント
  • MFCを用いてWebカメラからのキャプチャを行うソフトを作成しています。ダイアログ形式のソフトで、Captureボタンが押されたらWebカメラの映像を表示し、Stopボタンが押されたらキャプチャを終了します。
  • 現在、Captureボタンのイベントハンドラ内でキャプチャ処理を実行しており、その間はCaptureボタンが押された状態になってしまい、Stopボタンを押すことができません。改善策として、オリジナルのメッセージを作成し、Captureボタンのイベントハンドラ内でメッセージを送信してキャプチャ処理を行うように変更しましたが、同じ問題が発生しています。
  • キャプチャを行っている間でも、Captureボタンが押された状態にならず、Stopボタンを押すことができません。この問題を解決するためにはどのようなプログラムの組み方が必要でしょうか?
回答を見る
  • ベストアンサー

MFC - ボタンの処理について

現在MFCを用いてWebカメラからのキャプチャを行うソフトを作成しています。 環境はVisual Studio 2005です。 ソフトウェアはダイアログ形式で、”Capture"と"停止"のボタン、そして1つPictureControlを配置し、"Capture"ボタンが押されたらWebカメラからの映像をPictureControlに表示し、"停止"ボタンが押されたらキャプチャを終了するというものです。 少し長くなってしまうのですがよろしくお願いします。 開発当初、ダイアログクラスのメンバ変数にbool型の Cap_Flag を追加し、コンストラクタにより初期値を false に設定するようプログラムを組みました。 そして "Capture"ボタンが押され、そのイベントハンドラが呼び出された時に、 Cap_Flag を true に設定しキャプチャを行う関数を実行するようにしました。 キャプチャを行う関数の中では、 Cap_Flag をチェックし true に設定されている間キャプチャを行うよう while( Cap_Flag == true ) としてキャプチャを行います。 その後 "停止"ボタン が押されれば、そのボタンに対するイベントハンドラ内で Cap_Flag に false を設定し、キャプチャを終了しようと考えました。 この設計では確かに "Capture"ボタンが押されればキャプチャが行われ、PictureControlに映像が表示されるのですが、これらのキャプチャ処理は "Capture"ボタン のイベントハンドラ内で実行しているため、キャプチャを行っている間、つまり while( Cap_Flag == true ) となっている間は永遠に実行状態になっているため "Capture"ボタン が押されっぱなしの状態になり、"停止"ボタンを押すことが出来なくなってしまいます。また無理に "停止"ボタン を押そうとすると固まってしまうため、うまく"Capture"と"停止"を行うことが出来ない状況です。 改善策として、オリジナルのメッセージを作成しメッセージマップでそのオリジナルの命令に対してキャプチャを行う関数が呼び出されるよう設定しました。よって、 "Capture"ボタンが押されたときに呼び出されるイベントハンドラ内で Cap_Flag を true に設定し、オリジナルのメッセージを送信して、そのメッセージに対応するキャプチャを行う関数を呼び出すようプログラムを組みなおしました。 このように組みなおした理由は、"Capture"ボタンが押されたときに呼び出されるイベントハンドラ内の処理は、Cap_Flag を true に設定することと、オリジナルのメッセージを送信することのみで、イベントハンドラ内ではキャプチャを行う関数は実行されず、 実際に "Capture"ボタン が押されたとしても、押された状態ではなくすぐに基の状態(表示)にもどるだろうと考えたためです。 ですが、このように変更しても "Capture"ボタンのイベントハンドラ内でキャプチャ処理を行っていることと同様に "Capture"ボタンが押されっぱなしの状態になり、"停止"ボタンを押すことが出来ません。 どのようにプログラムを組めば、実際にキャプチャを行っている間でも、"Capture"ボタンが押された状態にならず "停止"ボタン を押すことができるようになるでしょうか? 参考になるアドバイス、またはウェブページをご紹介いただけれたらと思います。 よろしくお願い致します。

質問者が選んだベストアンサー

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

afx_msg void myThreadExit( WPARAM wParam, LPARAM lParam ) は LRESULT myThreadExit( WPARAM wParam, LPARAM lParam ) でした ・・・ 関数を抜ける時には return S_OK; など リザルトコードを返してください

happy-hack
質問者

お礼

返信が遅れてしまい申し訳ありませんでした。 とても分かりやすいアドバイスをありがとうございます。 無事実装が完了し、正常に動作させることができました。 本当にいろいろとありがとうございました。

その他の回答 (2)

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

スレッドプロシージャは 外部関数にしたほうがいいでしょう クラスのメンバーでやるなら static関数にしないとまずいです … お勧めはしませんが AfxBeginThread( Csample3::ImageCapture, this ); として呼び出し ヘッダーでの宣言は static UINT ImageCapture( LPVOID ); といった具合になります キャプチャー関数へ渡すのは thisポインターよりも 必要なデータの構造体のほうがいいでしょう 画面のキャプチャーサイズ 描画用のコントロールのハンドル 親ウィンドウのハンドル : Csample3Dlgのハンドル(m_hWnd) スレッドを抜けるためのフラグ スレッドが終了したことを知らせるメッセージ : RegisterWindowMessageなどで取得する 単純な外部関数として UINT ImageCapture( LPVOID lpparam ) {   LPMYSTRUCT pmySTruct = (LPMYSTRUCT)lpParam;   while( !pmyStruct->bDone ) {     // キャプチャー処理   }   PostMessage( pmyStruct->hParent, pmyStruct->uMsgExit, 0, 0 );   return 0; } といた具合のほうがいいように思います DLG側でスレッドの終了を感知する関数を追加 afx_msg void myThreadExit( WPARAM wParam, LPARAM lParam ) {   //必要な後処理   // CWinThread変数の開放など } メッセージマップに ON_REGISTERED_MESSAGE( m_myREGMSG, myThreadExit ) を追加 メンバー変数として static UINT m_myREGMSG; を追加 CPPファイルに UINT CsampleDlg::m_myREGMSG = RegisterWindowMessage( _T("MyThread_Exit") ); といった具合でしょう

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

普通はキャプチャーを別スレッドに仕立てて使うようにすると思いますよ メインスレッドの中でボタンのクリックイベントから抜けないなら CWinThreadクラスのPumpMessageメソッドを適当な頻度で呼びましょう ループ処理のをしていると思いますので適当なカウンタを設けて このカウンタが20回とかカウントしたら呼び出すとかして見ましょう   if ( nCnt % 20 == 0 ) {     AfxGetApp()->PumpMessage();     nCnt = 0;   }   nCnt++; といった具合です

happy-hack
質問者

お礼

返信ありがとうございました。 おっしゃられた通り、 AfxGetApp()->PumpMessage(); をループ文の中で実行した所、クリックイベントから抜け出し正常に終了することができました。ありがとうございます。 ですが、”普通はキャプチャーを別スレッドに仕立てて使うようにすると思いますよ” この一文も気になったので、スレッドを立ててキャプチャを行うようプログラムを組み替えました。 ですが、以下のような問題が生じてしまいました。 プロジェクト名は "Sample3" となっているため、それぞれのヘッダファイルやソースファイルはこのプロジェクト名が記載されています。 そして CWinThread* m_pThread = AfxBeginThread(&Csample3Dlg::ImgCapture, (LPVOID)this); としてスレッドを立てました。ちなみにキャプチャスレッドはCsample3Dlgクラス内で、 UINT ImgCapture(LPVOID pParam); というように定義されています。 この手順で一応はスレッドが立ち上がると考えたのですが、コンパイルすると以下のようなエラーが出てしまいます。 エラー 2 error C2665: 'AfxBeginThread' : 2 オーバーロードのどれも、すべての引数の型を変換できませんでした このエラーに対処すべく、色々と検索をかけて調べてみたところどうやら文字コードに依存して出てくるエラーだと分かり、文字コードを "マルチバイトコード" に変更したのですが、それでもこのエラーを取り除くことができませんでした。  何が問題なのでしょうか?  連続の質問で恐縮ですが、もしご理解いただけたらアドバイスをお願いしたいと思います。よろしくお願いいたします。

関連するQ&A

  • イベントの発生から対応する処理実行までの作り方

    以前に、ボタンクリックなどのイベントが起きたら すぐにそのボタンクリックに対応した処理をその場(イベント ハンドラ)で実行するのではなく、 "イベントが発生しました関数"のようなものに最初に イベント情報を渡してしまい、あとはその関数からイベントが 振り分けられていき、最終的にそのイベントに対応した処理が 実行される。といったプログラムを見たことがあるのですが、 このような技法は一般的に行われるものなのでしょうか? 巨大なプログラムになるとこのような技法が使われる気が しますが・・・ また、この技法には何か名前がついているのでしょうか? また、これに関して記載しているサイト・書籍などありましたら 教えてください。

  • CLICKイベントと、MOUSE_DOWNイベント

    AS3です。 CLICKイベントと、 MOUSE_DOWN、MOUSE_UPイベント って 併用できないのでしょうか? 画像のギャラリーを作っています。 クリックしたときに、ボタンの色が一瞬変わって、 ギャラリーの画像も変わるものを作ろうとしています。 addEventListener(MouseEvent.MOUSE_DOWN, mDown, false, 0, true); addEventListener(MouseEvent.MOUSE_UP, mUP, false, 0, true); addEventListener(MouseEvent.CLICK, mClick, false, 0, true); こうすると、 mDown、mUPのハンドラ関数は実行されるのですが mClickのハンドラ関数は無視されます。 併用できない場合、上記のことを達成するには どのようにみなさん書かれているのでしょうか? ご存知の方いらっしゃいましたら、 何卒よろしくお願いいたします。

    • ベストアンサー
    • Flash
  • 【VC++6.0】イベントハンドラ関数を流用したいのですが、、、

    VC++超初心者です。 既出の質問(http://okwave.jp/qa2658942.html)と同様ですが、VC2005(CLR)でなく、VC++6.0の時 どのようにコーディングすればよいか教えていただけませんでしょうか。 よろしくお願いします。 ********************************** 以下の2つのボタンのイベントハンドラ関数があった場合 //ボタン1のイベントハンドラ関数 void CAAAADlg::OnOK() { 処理内容 } //ボタン2のイベントハンドラ関数 void CBBBBDlg::OnOK() { } ボタン2をクリックしたときの動作とボタン1の動作を同じにしたいと思っています。 **********************************

  • C#でボタンクリックをキャンセル

    C#でボタンクリックをキャンセル こんにちは。 C#+.Netです。 ・テキストボックスとボタンを持つフォーム ・ボタンが押された時にテキストボックスの内容をチェックする。 ・OKであれば、そのままフォームを閉じる。 ・NGであればメッセージボックスを表示して、フォームは開いたまま。 というフォームを作成したいのです。 フォームはShowDialogで表示させます。 ボタンのDialogResultには、DialogResult.OKを設定してあります。 ボタンのClickイベントを使って、メッセージボックスを出すことはできたのですが、フォームを開いたままにすることができません。 あるいは、ボタンのDialogResultはNoneのままにして、イベントハンドラ内から、フォームを閉じる方法がないかと思ったのですが、それもわかりません。 どのようにすればよいのでしょうか?よろしくお願いします。

  • フォーム内のラジオボタンの数の取得

    flag = 0; for(i=0;i<document.frm.re_id.length;i++){   if (document.frm.re_id[i].checked){     flag = 1;   } } if (!flag){     alert('ラジオボタンのいずれかをご選択ください');   return false; } return true; 今はこのように記述してtrueの時にsubmitが実行されるようにしています。 ラジオボタンが2つ以上ある時はdocument.frm.re_id.lengthがきちんとラジオボタンの数を返してくるんですが、ラジオボタンが1つの場合undefindとなってしまいます。 document.フォーム名.ラジオ名.lengthはラジオボタンが1つの場合は使えないのですか?

  • 割り込み処理について

    お世話になります。 今、VC++でWinSockを用いてパケット送信ソフトを作成しています。 パケット送信開始ボタンをクリックすると呼ばれる OnBnClickedButtonStart() 停止ボタンをクリックすると呼ばれる OnBnClickedButtonStop() 今、送信開始ボタンクリックイベント関数 OnBnClickedButtonStart()内にソケットの設定や ソケット送信などを行っています。 while(1){ if( (sendto(sock, send_buf, size , 0,(struct sockaddr*)send_addr, sizeof send_addr)) == SOCKET_ERROR ){ MessageBox("Error : Send Socket !"); return; } } と送信開始ボタンをクリックすると無限ループでソケットを送信しています。 以下質問です。 (1)送信開始ボタンをクリックするとwhile()で無限ループになります。その処理中に、停止ボタンなどクリックすることは出来ますか?出来る場合どのようにして出来るようになるのでしょうか?(プロパティの設定とか?) (2)停止ボタンクリックが出来るようになった場合、停止ボタンクリック関数内には、ソケットクローズ処理だけで送信は停止しますか? どうぞよろしくお願い致します。

  • イベントハンドラが取得できない VC++ MFC

    おはようございます(><) VC++.NETで開発を行っています。 MFCを使って開発をしています。 CDialogを継承したCmyDialogでOnLButtonDownのイベントがとれません。 OnLButtonDownのイベントを使いたかったのですが 自動でイベントを設定するプロパティのメニュー(雷のマークみたいなもの)にイベントがなかったので 自分でCmyDialog::と書いたらリストの中に OnLButtonDown( UINT nFlags,CPoint point)がでたので 定義に追加、イベントの記述を追加しました。 雷マークで作ったイベントのコードには // TODO : ここにコントロール通知ハンドラ コードを追加します。 と自動で記述され、ブレイクポイントを設定するとそこで止まるのですが 私が記述したLButtonDownのイベントでは実行してもブレイクポイントで止まりません。 他のイベントと比べて違うのは BEGIN_MESSAGE_MAP(CmyDialog, CDialog)の中に ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnLvnColumnclickList1) のように イベントハンドラ名、リソース名?、イベント名 と自動で記述があります。 ここを追加すればいいのかなと思いましたが 左クリックに対応するイベントハンドラ名が分かりません。 問題解決に有効な情報をお持ちの方 お力をお貸しください。 よろしくお願いします(><)

  • イベントハンドラ関数について

    現在VC++/CLR 2005 でプログラミングをしています。 基本的な事柄かもしれませんが、質問させてください  以下の2つのボタンのイベントハンドラ関数があった場合 //ボタン1のイベントハンドラ関数 private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) String^ str = textBox1->Text } //ボタン2のイベントハンドラ関数 private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { } ボタン2をクリックしたときの動作とボタン1の動作を同じにしたいと思っています。 その場合は private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) String^ str = textBox1->Text } //ボタン2のイベントハンドラ関数 private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { String^ str = textBox1->Text } のようにボタン2のイベントハンドラ関数をボタン1と同じように書けばいいのですが イベントハンドラ関数の処理が膨大になった場合を考えて省略する 書き方は無いのでしょうか?(以下の場合ですとエラーが起こってしまいます。) private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { button1_Click(); } 宜しくお願いします

  • 【MFC】キャンセルボタン処理が実装できない

    VC++2005(MFC)にて下記サイトを参考にMDIアプリケーションを作成しています。 http://www.alpha-net.ne.jp/users2/uk413/vc/VCT_MDI1.html 手順として、プロジェクトを新規作成し、MFC AppWizard(exe)で 新規プロジェクト名をMDITest1に設定し、アプリケーションの種類はMDI、 ビュークラスCMDITest1Viewの基本クラスはCFormViewとします。 リソースビューより、自動生成されたフォームの上に、 Buttonを配置し、イベントハンドラOnBnClickedButton1()内にて、 IDCANCEL()処理にて、ボタン押下時のウィンドウを閉じる処理を 実装したいのですが、コンパイルエラーが発生します。 基本クラスがCDialogクラスの場合は実装できるような気がするのですが。。 フォームビューだと、キャンセル処理は実装不可能なのでしょうか? また、不可能だとしたらウィンドウを閉じる処理はどのように実装すればよいのでしょうか? 解決策をご存知の方おられましたら、お手数ですがご教授宜しくお願い致します。

  • 複数のラジオボタンの選択チェック

    Q1とQ2の2問があり、ラジオボタンで回答を選択するようにしていますが、 ラジオボタンを選択しなかった場合、選択を促すようメッセージを表示させるようJavaScriptで以下のように作成してみましたがうまくいきません。 Q1とQ2の両方を選択しなかった場合、「Q1が選択されていません」とメッセージが表示されますが、Q1だけを選択してQ2を選択しなかった場合はメッセージが表示されません。 いろいろ調べてみたのですが、function checkの使い方に問題があるのでしょうか? function check(){ var flag = 0; if(document.form1.Q1.length) { flag = 1; var i; for(i = 0; i < document.form1.Q1.length; i ++){ if(document.form1.Q1[i].checked){ flag = 0; break; } } } if(flag){ window.alert('Q1が選択されていません'); return false; } else{ return true; } var flag = 0; if(document.form1.Q2.length) { flag = 1; var i; for(i = 0; i < document.form1.Q2.length; i ++){ if(document.form1.Q2[i].checked){ flag = 0; break; } } } if(flag){ window.alert('Q2が選択されていません'); return false; } else{ return true; } }

専門家に質問してみよう