• 締切済み

VC++ 2005 MFC ボタンの無効化

VC++ 2005 MFC ボタンの無効化 現在スレッドを使ったプログラムを作成しています。 あるボタンを押すと、 親スレッド 1、RS232C受信スレッドを作成 2、RS232Cにデータを送信 3、WaitSingleObjectでイベント待ち 4、受信状態に応じた処理 子スレッド 1、サムチェック等確認して、受信が完了すれば   受信データを格納してCEventのSetEventを発行 というような処理の部分があるのですが、待っている間にウィンドウ内にある ボタンが押せてしまいます。厳密には、イベント待ちを抜けた時点で待っている 間に押せてしまったボタンの処理が走ってしまうのですが。 EnableWindow(FALSE)をやっても駄目でした。 何かいい方法がありませんか??すいませんがよろしくお願いします。

みんなの回答

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

>ちなみにワーカスレッドでイベントを待ってイベント受信でEnableWindow >っていう形になるのでしょうか?? >どこで何をしてっていうのが、すいません想像付いていません。 ボタンのイベントハンドラに入ったら… ・EnableWindow(FALSE)として、ボタンを無効化します。 ・ワーカースレッドを起動します。  (ワーカースレッドにはボタンのHWNDを引き渡すようにします)  スレッド起動時に引き渡せるのはLPVIODが1つだけですが、  構造体のアドレスを渡すこともできますので、必要なデータを詰めた構造体のアドレスでも渡して下さい。  # その構造体の寿命には注意。イベントハンドラ内のローカル変数だと危険です。  # 動的確保して渡してワーカースレッド中で解放する等の工夫を。 ・ワーカースレッドの起動が完了したらイベントハンドラは終了します。 ワーカースレッドは…元質問の「親スレッド」の内容を内包します。 終了してスレッドを終了する際に、EnableWindow(TRUE)でボタンを有効化します。 子スレッドはそのままでよいでしょう。 注意点としては…ワーカースレッドが終了する前にウィンドウを閉じられた場合の対策が必要。 BeginThread()ではCランタイムライブラリの使用が危険になる。 MFCの場合CWndなどはスレッドMatthewで受け渡しはできない(はず)。 などなど……。 まぁ、検索してみると、UIスレッドとワーカースレッドで切り離ししているサンプルとか見つかる… でしょう。たぶん。 # よくあるネタですし。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

親スレッドの1~4までの処理が「イベントハンドラ内で」実行しているのであれば、 当然の動作です。 # イベントハンドラからの戻りが遅ければ、OSによって「応答なし」のラベルを付与して貰えるでしょう。 ボタンクリックが発生 ->WM_COMMANDでイベント通知 ->EnableWindow(FALSE)で、ボタンを無効化 ->ループ処理などでイベント処理(この間もマウスボタン押下できますが、ソレはキューに溜められる(*1)) ->EnableWindow(TRUE)で、ボタンを有効化 ->キューに溜まってる処理を続行 ->*1でのマウスボタン押下のメッセージから、ボタン押下を検出、WM_COMMANDがキューに入る(EnableWindow(TRUE)で有効化されているから) ->WM_COMMANDでまたまた通知 ボタン押下でループ処理を実行するワーカースレッドを起こして、そのスレッド側でEnableWindow()を使ってボタンの有効/無効をコントロールした方が良いでしょう。 なお、ワーカースレッド実行中にウィンドウが閉じられてしまう。という可能性もありますのでご注意を。

nori1112
質問者

補足

返事が遅くなって申し訳ありません。 確かにそういった動きをしています。 EnableWindowではなくフラグでも同様の動きをしてしまいます。 ちなみにワーカスレッドでイベントを待ってイベント受信でEnableWindow っていう形になるのでしょうか?? どこで何をしてっていうのが、すいません想像付いていません。

  • reset_cat
  • ベストアンサー率68% (94/138)
回答No.1

ボタンクリックイベントハンドラに有効判定処理をいれて、その処理が開始したら、その処理が終了するまでクリックイベントを無視する方法はどうですか? こんな感じです。 void CTestDialog::OnBtn1() { if(btn1.IsWindowEnabled()) { btn1.EnableWindow(FALSE); // ボタンクリック時処理 btn1.EnableWindow(TRUE); } }

関連するQ&A

  • VC++ メインループでのイベント監視方法

    こんにちは。 VC++2008Expressでプログラムをしようと思っている初心者です。 以下、変な疑問があり、お尋ねしたいと思います。 よろしくお願いします。 Windowsアプリケーション Win32API クラスで別スレッドを作成して、そのスレッドからのイベントを WinMainループで受け取る方法ですが 通常皆様はどういう風にするのでしょうか? クラスは、その他のプログラムでも流用可能で様々なアプリに対応しやすいようにしあげたいのですが。。 別スレッドでイベント発生時にWinMainにどのように教えるのが普通のやり方なんでしょうか? 僕の考えでは、WinMain関数内のループ内で常時イベント発生していないか 以下のように監視させるか eventloop el; while(GetMessage(&msg,NULL,0,0)) {   TranslateMessage(&msg);   DispatchMessage(&msg);      if(el::boolEvent){     イベント処理へ   } } とするのが良いか? これだとクラスの関数、変数の使い方さえ分かるようにしておけば流用は簡単 なのかなと思いますが。。 メインのループ内にこんな監視を入れるようなプログラムをみたことないので ナンセンスなのではと思います。 次に考えられるのは、クラスのイベント発生で作成したSendMessageを送って メッセージ処理でイベント処理をさせるのが良いのかなって思いますが これだと、流用するときに対応したMessage(キュー?ですかね)を作成しないといけなく 私的に分かりにくいなーって思います。。。 変なことで悩んで先に進まないのですが、皆様はどのようにコーディングされるのでしょうか? ちなみにイベントというのは、RS232Cで受信があって、そのデータを加工したあとで メモリに格納して格納しましたよってイベントです。 どうかよろしくお願いします。

  • クラスでスレッド作成

    VC++2008Express WIN32APIでRS232Cの通信用クラスを作成しています。 RS232Cの受信用スレッドを作成して 1ポートの受信処理をするようにはできます。 ですが ポート追加するたびにクラスをインスタンス化して受信用スレッドを 作成したいのですが、スレッド作成するには使用する変数などを staticにしないといけないため、クラスを複数インスタンス化できません。 どのような手法でクラスから複数スレッドを作成することができるのでしょうか? 分かりにくい説明ですが、参考になるものなどありましたら、 よろしくお願いします。

  • WaitForMultipleObjectのイベントの処理について

    はじめまして。 現在.NET 2003環境のVC++にて開発を行っています。 そこで知恵をかして頂きたいのですが、 WaitForMultipeObjects関数で待機している場合、 引数で指定している複数のイベントオブジェクトが ほぼ同時にシグナル化した場合、イベントの取りこぼし が発生する場合ってあるのでしょうか。 <例> スレッドA     スレッドB      スレッドC           for(;;){ SetEvent([0])     res = WaitFor...  SetEvent([1])             SleepEx(100, FALSE);           } ・スレッドBが複数のイベントを待機 ・スレッドA、Cがイベント発行 ・この場合、A、Cでほぼ同時にイベントが発生された場合、  (1)A(またはC)発行のイベントを取りこぼす  (2)A(またはC)発行のイベントを処理したのち、   のこりのイベントを再度処理する(for(;;)でループしている為) 取りこぼしの可能性があるとしたら、対応方法もできれば 知りたいです。 以上、よろしくお願い致します。

  • VC++.NETを使用したRS232c通信プログラム

    RS232c通信をVC++.NETを用いてPSoCマイコンと通信を行うGUIを作成しようとしています。PSoCとハイパーターミナルを用いた送受信の通信は成功しました。そこで受信ボタンをクリックすると、PSoCから送られてくる文字列を受信してエディットコントロールに表示させるという、ダイアログボックスベースで作成したアプリケーションを作っているんですが、文字列をうまく受信してくれません.現状は「・・・」といった文字をエディットコントローラに表示しており、実際は「welcome」という文字列をPSoCより受信しなければならないんですが・・・。 RS232c通信用のAPIは以下のサイトより使わせてもらっています↓http://7ujm.net/C++/Rs232c.h.html 自分が作成したプログラムはボタンをクリックすることで発生するイベントハンドラ関数内に以下のプログラムを書いているだけです。↓ void CMy090630Dlg::OnBnClickedButton1() { RS232c rs; rs.Connect();//ポートcom5と接続を開始する char w[100]; rs.Read_CRLF(w,100);//PSoCより文字列を受信 m_edit1.SetWindowText(w);//エディットコントロールに  受信文字列を表示させる } VC++をはじめたばかりの初心者で、言葉の間違いなどあるかもしれませんが、教えてください。

  • VC++ Workerスレッドを強制終了させる方法

    VC++6.0でwinアプリを作っています。 ダイアログベースで、ボタンを押すとワーカースレッドを実行し、ここでデータ処理をしています。 もし、スレッド中でデータ処理時間がかかってしまうと、これをスレッド外で強制的に終了させたいですが、出来るのでしょうか。 よろしくお願いします。

  • VC++でのスレッド間アクセス

    WindowsXP、VC++ 2005 ExpressEditionを使用しています。 2台のパソコンをケーブルで繋いでチャットシステムを作ろうとしているのですが、 「有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール '(コントロール名)' がアクセスされました。」 というエラーが出てしまいます。 ハイパーターミナルを使ってデータの送受信を確認した所、データの送信、受信共に出来ています。 問題はコントロールにアクセスできないところだと分かってはいるのですが、具体的にどのような書き方をしてデータを渡せばいいのか分かりません。 デリゲートではないかと見当をつけて、C#なら見つけたものの、それをどうVC++の書き方にすればいいか分からないので困っています。 また、デリゲートを使えばいいのかさえ手探り状態なので、どなたかご教授ください。

  • ムービークリップのボタンの無効化について

    お世話になっております。 actionscript3でFLASHサイトを製作しております。 マウスオーバー、マウスアウト、マウスクリックのイベント機能を付与したムービークリップ型のボタンがあり、ボタンモードを有効にしています。 button.buttonMode = true; マウスオーバーの際はムービークリップの指定のフレームからアニメーション処理を行っています。 button.addEventListener(MouseEvent.MOUSE_OVER, btnOver); function btnOver(event:MouseEvent):void { button.gotoAndPlay(2); } このボタンを、あるイベントが実行された時にボタンとしての機能をなくし、尚且つマウスオーバー、マウスアウトのアニメーション処理も無効化したいと思い、以下の処理を行いました。 ボタンモードは無効になりましたが、マウスオーバー、マウスアウト、クリック処理は無効にならず、動作してしまいます。 button.buttonMode = false; button.mouseEnabled = false; button.enabled = false; 上記の方法とは別にイベント処理を削除しようと思い、removeEventListener処理を行いましたが、「TypeError: Error #2007: パラメータ listener は null 以外でなければなりません。」というエラーが表示されてしまいました。 指定の仕方が間違っているのだと思いますが、何方かご教授いただけないでしょうか? また、上記の方法以外で無効化する手段があればご教授いただければと思います。 宜しくお願いいたします。

  • シリアル受信の取りこぼし

    C++で作成したシリアルの受信処理について 1.受信イベントを検知 2.ReadFileでデータ読み取り 3.データ解析 の動作をスレッドの中で行うようにしているのですが 大量のデータを受け取る時に、データの取りこぼしが発生します。 取りこぼしを防ぐ処理方法や設定などはないでしょうか

  • VC++のサービスプログラム

    現在、VC++でサービスプログラムを作成しています。 メインプロセスから3つのスレッドを起動後、終了イベントをCreateEvent()で生成し、そのイベントをWaitForSingleObject()でプログラムの終了待ちをしているのですが、サービス起動後、エクスプローラを開いたりすると画面が一定時間フリーズし応答がなくなってしまします。 この事象の原因がわかる方いますでしょうか? ちなみにWaitForSingleObject()はINFINITEでしていしています。 また、画面のフリーズは放っておくと一定時間で解除されます。

  • 「キャンセル」ボタン付きの処理中ダイアログ

    Windowsアプリで、ある時間のかかる処理を キャンセルボタン付処理中ダイアログを表示し、途中で処理をキャンセル可能にしたいと考えています。 ここの過去ログから上記はマルチスレッドにする必要があると拝見しました。http://oshiete1.goo.ne.jp/kotaeru.php3?q=96951 <メイン画面の開始ボタン処理> ------------------ void C_SampleDlg::OnStart(){  CWinThread *cwt;  C_CancelDlg dlgCancel(this);  cwt = AfxBeginThread(Sample_Proc, &InputParams);  cwt->m_bAutoDelete = FALSE;  cwt->ResumeThread();  EnableWindow(FALSE);  dlgCancel.Create();  dlgCancel.ShowWindow(SW_SHOW);  while(TRUE){   if(dlgCancel.CheckCancel() == TRUE){    // キャンセルが押された時    EnableWindow(TRUE);    dRcd = WaitForSingleObject(cwt->m_hThread, INFINITE);    if(dRcd == WAIT_OBJECT_0)     return;   }   dRcd = WaitForSingleObject(cwt->m_hThread, 0);   if(dRcd == WAIT_OBJECT_0){    dlgCancel.DestroyWindow();    EnableWindow(TRUE);    break;   }  }  return; } <プロシージャ> ---------------------------------- UINT Sample_Proc(LPVOID pParam){  C_SampleDlg->やりたい処理関数呼び出し  ::AfxEndThread(0);  return 0; } 以降別ソース ================================== <C_SampleDlg::やりたい処理関数> ↑ここでdlgCancel.CheckCancel() == TRUEかどうか 判定したい場合、グローバル関数を使うか、または呼出し元で作成したインスタンスをパラメタとして渡して使うべきなのでしょうか。文字数の関係で分かりにくいところもありますが、よろしくお願いします。 ※dlgCancel.CheckCancel()はC_CancelDlgクラスのプロテクト変数を内部で操作しています。

専門家に質問してみよう