• 締切済み

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()内部で変更される可能性を考慮して、最適化によるコード削除はされないはずです。

  • chie65535
  • ベストアンサー率43% (8466/19280)
回答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

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

    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クラスのプロテクト変数を内部で操作しています。

  • カメラアプリの排他制御(android)

    はじめまして。android初心者の学生です。 androidでカメラアプリを作っていますが、エラーで落ちてしまいます。 端末はgalaxy note IIIです。 画面タッチでオートフォーカスを呼び出し、フォーカスが終わったらパシャリ。というシンプルなものなのですが・・・ 具体的には 「オートフォーカス最中に3回程タッチすると、たまにフリーズして落ちる」 といった状況です。そこで多重撮影を防止するため、排他制御とやらをしたいのですが・・・うまくいかず困っています。オートフォーカス中にタッチしても、オートフォーカスを呼び出さない・・・というところまでは作った(考えた)つもりです。が、恐らくおかしなソースになっていると思われます。 @Override public boolean onTouchEvent(MotionEvent event) { switch(event.getAction()&MotionEvent.ACTION_MASK){            case MotionEvent.ACTION_DOWN: if(mTouch==false) camera.autoFocus(this); break; case MotionEvent.ACTION_CANCEL: break; } return true; } public synchronized void onAutoFocus(boolean success, Camera camera) { mTouch = true; camera.autoFocus(mAutoFocusListener); } private Camera.AutoFocusCallback mAutoFocusListener = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { camera.takePicture(null, null, mPictureListener); } }; private Camera.PictureCallback mPictureListener = new Camera.PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { BitmapFactory.Options options = new BitmapFactory.Options(); Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length, options); MediaStore.Images.Media.insertImage(getContext().getContentResolver(), bmp, "", null); camera.startPreview(); mTouch = false; }; できるのなら一度画面に触れたら、タッチを無効にしたいです。 初歩的な問題だとは思いますが、ご指南いただけたらと思います。 よろしくお願いします。

  • C#でラジオボタンを設定に記録する方法

    すみません、どなたかご存知のかた教えてください。 C#でグループボックスの上に20個くらいのラジオボタンが並んでいて、どれかをチェックした時設定として保存し、プログラムを再起動した時チェック状態を復元したいのですが、どのようにすれば良いでしょうか? Properties.Settings.Defaultで型をSystem.Windows.Forms.RadioButtonにして(RadioButton)senderを記憶するようにしてみましたが(プログラムが分かって無いからですが)だめでした。 現在はProperties.Settings.Defaultの型をstringにして、次のような形で動かしていますが、なんとかシンプル(スマート)にしたいのです。 private void Form1_Load(object sender, EventArgs e) { switch (Properties.Settings.Default.SelectedProgram) { case "Func1": radioButtonFunc1.Checked = true; break; case "Func2": radioButtonFunc2.Checked = true; break; case "Func3": radioButtonFunc3.Checked = true; break; default: break; } } //各ラジオボタン共通 private void radioButtonSelect_Click(object sender, EventArgs e) { string RadioButtonText = null; RadioButton _RadioButton = (RadioButton)sender; if (_RadioButton.Checked == true) { RadioButtonText = _RadioButton.Text; Properties.Settings.Default.SelectedProgram = RadioButtonText; switch (RadioButtonText) { case "Func1": textBox1.Text = "a"; break; case "Func2": textBox1.Text = "b"; break; case "Func3": textBox1.Text = "c"; break; default: break; } } } //プログラム開始ボタン private void buttonStart_Click(object sender, EventArgs e) { string RadioButtonText = null; foreach (RadioButton prgText in groupBox1.Controls) { if (prgText.Checked) { RadioButtonText = prgText.Text; break; } } switch (RadioButtonText) { case "Func1": Func1(); break; case "Func2": Func2(); break; case "Func3": Func3(); break; default: break; } } private void Func1() { } private void Func2() { } private void Func3() { }

  • PICのマシンのプログラムについての質問です。

    #include <16f873a.h> #fuses HS,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NOLVP #define use_portb_lcd TRUE #use delay (clock=10000000) #include <lcd.c> void port_ini(void); void lcd_express(int); void motor_drive(int); main() { int mode; port_ini(); while(1){ mode = (input_a() & 0b00000110); lcd_express(mode); motor_drive(mode); } } void port_ini(void) { setup_adc_ports(NO_ANALOGS); setup_counters(RTCC_INTERNAL,RTCC_DIV_2); port_b_pullups(FALSE); set_tris_a(0xff); set_tris_b(0x00); set_tris_c(0x00); output_b(0x00); output_c(0x00); lcd_init(); } void lcd_express(int disp) { lcd_gotoxy(1,1); lcd_putc("<DC-motor mode>"); delay_ms(5); lcd_gotoxy(1,2); switch(disp){ case 0:{ lcd_putc("- Go!Go! -"); break; } case 2:{ lcd_putc("- L-Bend -"); break; } case 4:{ lcd_putc("- R-Bend -"); break; } case 6:{ lcd_putc("- R-Turn!-"); break; } default: break; } } void motor_drive(int mode) { switch(mode){ case 0:{ output_c(0b00110000); break; } case 2:{ output_c(0b00111000); break; } case 4:{ output_c(0b01110000); break; } case 6:{ output_c(0b01010000); delay_ms(800); while(!(4==(input_a() & 0b00000110))){} output_c(0b00101000); delay_ms(100); break; } default:break; } } この文でlcdに何も表示しないようにしたいのですがどこを消せばいいのでしょうか? あと、void文などもできれば消して動かせるようにしたいのですが、どのようにすればいいでしょうか? ちなみにプログラムは、SW1・2を押しているときに、それぞれ片方タイヤを回転させ、両方押しているときに両方回転させて前進、両方押していないときは後退するというプログラムです。 ×字の台に張られた黒いテープをたどって最終的に真ん中でとまるという競技のプログラムです。 できればlcd関連のプログラムをすべて消したいです。

  • actionscript 3.0 勉強中のもです。

    actionscript 3.0 勉強中の者です。以下のプログラムにてインスタンス(人の形をした)が方向キーで動くものを制作したのですが、このインスタンスにあらかじめ、シンボル内の編集にて、左右対称の画像を 同じタイムライン内に、例えば5フレームづつ内にそれぞれ配置し、ループ状態にして、プレビューした時に行進しているような様子を設定したのですが、プレビューをしてみると、キーを押す前は元気よく行進しているのですが、ボタンを押してインスタンスを動かしたとたんに行進をやめてしまいます。行進を続けさせながら、方向キーの操作を行うにはどのようにすればよろしいでしょうか?よろしくお願い致します。 var bKeyUp:Boolean = false; var bKeyDown:Boolean = false; var bKeyLeft:Boolean = false; var bKeyRight:Boolean = false; stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeydown); stage.addEventListener(KeyboardEvent.KEY_UP, onKeyup); function onKeydown(e:KeyboardEvent) { switch (e.keyCode) { case Keyboard.UP: bKeyUp = true; break; case Keyboard.DOWN: bKeyDown = true; break; case Keyboard.LEFT: bKeyLeft = true; break; case Keyboard.RIGHT: bKeyRight = true; break; default: break; } trace("UP : " + bKeyUp + "\n" + "DOWN : " + bKeyDown + "\n" + "LEFT : " + bKeyLeft + "\n" + "RIGHT: " + bKeyRight + "\n" ); } function onKeyup(e:KeyboardEvent) { switch (e.keyCode) { case Keyboard.UP: bKeyUp = false; break; case Keyboard.DOWN: bKeyDown = false; break; case Keyboard.LEFT: bKeyLeft = false; break; case Keyboard.RIGHT: bKeyRight = false; break; default: break; } trace("UP : " + bKeyUp + "\n" + "DOWN : " + bKeyDown + "\n" + "LEFT : " + bKeyLeft + "\n" + "RIGHT: " + bKeyRight + "\n" ); } const PLAYER_SPEED:uint = 4; var pSpeed:int = PLAYER_SPEED; player2.addEventListener(Event.ENTER_FRAME, playerActions); function playerActions(e:Event) { if (bKeyUp == true) { player2.y -= pSpeed; player2.gotoAndStop("up"); } if (bKeyDown == true) { player2.y += pSpee これにどのような追加をしたらよろしいでしょうか? 何卒お願い致します。

    • ベストアンサー
    • Flash
  • MFCタブコントロールのグラデーション描画

    現在、VC++2010・MFC環境でMFCのタブコントロールのウィンドウ部(?)をグラデーション描画にしたいと考えています。 完成予想としては、Excelのメニュー(?)みたいな感じでグラデーションがかかるような感じにしたいのですが、現在、グラデーションの描画は何とか(たぶん無理やり)できましたが、タブを切替たり、ダイアログ自体が非アクティブ/アクティブを繰り返すとちらついてしまいます。 ソースは以下のようになっています。 ----------------------------------------------------------------- void CTabGradDlg::OnTcnSelchangeTab(NMHDR *pNMHDR, LRESULT *pResult) { // TODO: ここにコントロール通知ハンドラー コードを追加します。 int sel = m_xcTab.GetCurSel(); m_edit1.ShowWindow(SW_HIDE); m_edit2.ShowWindow(SW_HIDE); m_button1.ShowWindow(SW_HIDE); m_button2.ShowWindow(SW_HIDE); switch(sel) { case 0: m_edit1.ShowWindow(SW_SHOW); m_button1.ShowWindow(SW_SHOW); break; case 1: m_edit2.ShowWindow(SW_SHOW); m_button2.ShowWindow(SW_SHOW); break; } Invalidate(); *pResult = 0; } void CTabGradDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CDialogEx::OnActivate(nState, pWndOther, bMinimized); // TODO: ここにメッセージ ハンドラー コードを追加します。 switch( nState ) { case WA_INACTIVE : // 非アクティブ break; case WA_ACTIVE : // (マウスをクリックする以外の方法) アクティブ case WA_CLICKACTIVE : // (マウス クリック)アクティブ Invalidate(); break; } } ----------------------------------------------------------------- Invalidate();が原因でちらついていることまでは分かっているのですが、 なぜちらつくのか?ということと、対処方法もしくは別の方法はないのか? 別の方法があればどういったことなのか?ということが知りたいです。 初心者(小学生並み)にもわかるように教えていただければ幸いです。 宜しくお願いします。

  • マルチスレッドについて・・・

    先日マルチスレッドについて質問させていただいたものですが、助言のもと動かしてうまくいったように見えたのですが、ロードしていない部分がありました。 今回はスレッドの中身もかいておきます。 ご助力お願いいたします。 unsigned int WINAPI GameMain::loadthread(void *lpx) { GameMain* gm = (GameMain*)lpx; gm->GInit();   //ロード return 0; } HRESULT GameMain::LoadScreen() { // スレッドの生成 static bool onlyonce_createthread = FALSE; if(onlyonce_createthread ==FALSE) { hTh = (HANDLE)_beginthreadex( NULL, 0, &loadthread, this, 0, (unsigned*)&thID ); onlyonce_createthread =TRUE; } // ローディング画面の描画 static bool loopflg = TRUE; while(loopflg) { int threadCondition = CheckThread( hTh ); switch(threadCondition) { case THREAD_RUNNING: if(graphloaded_flg ==TRUE) //2D画像のロードが終わったら { EnterCriticalSection( &m_criticalSection ); float keep_item = (float)(load_item/MAX_LOAD_ITEM); LeaveCriticalSection( &m_criticalSection ); d2d_control->GaugeDraw(0, 0, keep_item); //画像の描画関数 } break; case THREAD_EXIT: loopflg =FALSE; break; case THREAD_ERROR: return E_FAIL; break; } } float keep_item = (float)(load_item/MAX_LOAD_ITEM); d2d_control->GaugeDraw(0, 0, keep_item);  //画像の描画関数 return S_OK; }

  • マルチスレッドでの画像描画

    マルチスレッドを使ってロード画面を作ろうとしているのですが、 上手く画像が描画更新してくれません。 スレッドの中身は下記の通りです。よろしくお願いします。 HRESULT GameMain::LoadScreen() { // スレッドの生成 static bool onlyonce_createthread = FALSE; if(onlyonce_createthread ==FALSE) { hTh = (HANDLE)_beginthreadex( NULL, // SECURITY_ATTRIBUTES 構造体へのポインタ 0, // 新規スレッドのスタックサイズ &loadthread, // スレッドの実行開始アドレス this, // 新規スレッドに渡される引数リスト 0, // 新規スレッドの初期状態 (unsigned*)&thID ); // スレッドのIDを格納するためのDWORD型変数へのポインタ onlyonce_createthread =TRUE; } // ローディング画面の描画 static bool loopflg = TRUE; while(loopflg) { int threadCondition = CheckThread( hTh ); switch(threadCondition) { case THREAD_RUNNING: if(graphloaded_flg ==TRUE) { EnterCriticalSection( &m_criticalSection ); load_item = (float)(load_item/MAX_LOAD_ITEM); LeaveCriticalSection( &m_criticalSection ); d2d_control->GaugeDraw(0, 0, load_item); Sleep(100); } break; case THREAD_EXIT: loopflg =FALSE; break; case THREAD_ERROR: return E_FAIL; break; } } return S_OK; }

  • 関数の終了について

    関数の呼び出し元の後続処理へ行かない方法を探しています。 void 関数1() {    while(true)    {       if(○○) break;    }  } void 関数2() {    関数1();    ***後続処理*** }

  • 多重ループの抜け方

    例えば2重ループで、内側のループと外側のループも抜けたいとき、 while(true){  boolean flag = false;  …  while(true){   if(/* ある条件を満たした時 */) {    flag = true;    break;   }  }  if(flag){ break; } } としているのですが、このループが3段、4段になるときもこのような方法しかないのでしょうか?C言語のgotoみたいなことはできないですよね・・? (goto自体使わない方がいいと言われていますが・・)

    • ベストアンサー
    • Java

専門家に質問してみよう