• 締切済み

Qダイアログ アプリで 複数のボタンの制御(続き)

先ほど回答していただき、修正しましたが 動作に変化はありませんでした。 私の質問方法が悪かったのかしれませんが 解決したい箇所は次の通りです //ConBtnのイベント void CKm370ReaderDlg::OnBnClickedBtnCon() { // TODO: ここにコントロール通知ハンドラー コードを追加します。 CANCEL = false; m_ListCtrl.ClearBox(); ConBtn->EnableWindow(FALSE); CanBtn->EnableWindow(TRUE); <--ここで即 CanBtnを有効にしたい   Exit = false;    while(!Exit) { switch(sequence) {  case 0: while(Polling()) { if(CANCEL) { Exit = True; break; }   }     break;      case 1: : } } 現状では、CanBtnが有効にならないので while(!Exit) { }の処理がすべて終わった時点でCanBtnが有効になっています。 再度、ご検討のほどよろしくお願いいたします。

みんなの回答

回答No.2

ボタンがグレー表示のままということだけであれば、UpdateWindowで表示の更新はできます。 でも、やりたいことはそうではないですよね。ボタンをクリックしたら即座に処理をしたいんですよね。 そうであれば、UpdateWindowではだめですし、ましてやSleep(0)なんてまったく意味を持ちません。 原因は、メッセージループが動いていないからです。ボタンのクリックも、クリックされたというメッセージが処理されて初めてハンドラが呼び出されます。OnBnClickedBtnCon()はメッセージループから(中間にいくつかの関数を介して)呼び出されているので、ここの処理を抜けない限りはメッセージループは処理を続行できません。なので、ループが終了してハンドラを抜けると、画面の更新などが再開されて、ボタンが有効になったように見えるのです。 これを解決するには、画面の処理を行うUIスレッドと、画面を直接いじらないワーカースレッドの複数のスレッドを動かすマルチスレッドプログラミングを行う必要があります。今回の場合、 while(Polling()) { ... } の部分は直接画面をいじらない(CANCELという変数を参照しているだけ)ので、この部分を別スレッドにして、スレッドを起動したらOnBnClickedBtnCon()から抜けるようにすれば、メッセージループの処理が再開されます。 タイマーを使用する方法もありますが、処理によってはうまくいかないかもしれませんし、SetTimerで設定するタイマーの精度は低くて、30msなんて間隔では遅延が発生する可能性が高いです。(ちなみに30ms=0.03秒です。念のため) もし、タイマーで何とかなる処理なのであれば、マルチメディアタイマーの使用を検討したほうがいいでしょう。 また、CANCELは見たところグローバル変数でしょうから、volatileは必要ありません。Polling()内部で変更される可能性を考慮して、最適化によるコード削除はされないはずです。

すると、全ての回答が全文表示されます。
回答No.1

Sleep(0); を、無限ループの内側に入れてみよう。 Sleep(0)を入れる事で、Windowsは、実行中のイベント処理を中断して、状態が変化したコントロール(オブジェクト)を再描画し、無限ループ中も他のボタンのクリックを受け付けるようになる筈です。 逆に言うと、Sleepが無ければ、ConBtnのイベントを終了するまで(関数からreturnするまで)、ボタンの状態が変わっても再描画されないし、クリックする事も出来ません。 あと「Exit」と言う変数と「CANCEL」と言う変数は「意味が同じ」なので「どちらか1つ」で良い筈です。 また、イベント内で不意に値が変わる変数は記憶クラスを「volatile」で宣言しないと、正常に処理されません。 Cコンパイラは「CANCEL = falseと代入してから、if(CANCEL) で評価するまで、一切、代入が行なわれていない」と判断すると、プログラムを最適化して「if(CANCEL)」を「if(false)」に書き換えてしまいます。 すると「if(false)」以降は「実行されない無駄なプログラム」だと判断して、if文そのものが「無かったこと」になってしまいます。 つまり while(Polling()) { if(CANCEL) { Exit = True; break; } } の部分は while(Polling()) { } に書き変えられてしまうのです。 これを防ぐため、CANSEL変数は、記憶クラスを「volatile」にしなければなりません。

すると、全ての回答が全文表示されます。

関連するQ&A