連続してボタンを押すと多重実行されてしまう問題の解決方法

このQ&Aのポイント
  • VC++2008ExpressEditionを使用してプログラムを作成し、ボタンを連続して押すと多重実行される問題が発生しています。
  • 解決方法として、関数内でフラグ変数を使用し、多重実行を防止する手法があります。
  • また、関数が実行中はボタンを無効化し、自分で作成したアイテムを操作できないようにすることで解決できます。
回答を見る
  • ベストアンサー

ボタン操作

VC++2008ExpressEditionを使用してプログラムを作成しています。 Windowsフォームアプリケーションを作成し、そこに、TextBoxとButtonを放り込み、ボタンを押すと以下のようなコードが実行されるようにしました。   System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {     static bool flug=false;     if(flug)return;     flug=true;     button1->Enabled=false;     button1->Text=L"実行中";     button1->Update();     int i;     for(i=0;i<200;i++){       int t=clock();       while(10>clock()-t);       textBox4->Text+=L"aaraeaewa"+i+L"\r\n";       textBox4->SelectionStart = textBox4->Text->Length;       textBox4->ScrollToCaret();     }     button1->Enabled=true;     flug=false;     button1->Text=L"実行";   } このように設定したボタンを何回も連続して押すと、この関数を実行中は多重実行されないことを想定しているのですが、やってみると多重実行されてしまいます。 どの様にすれば多重実行しないように出来るのでしょうか? また、この関数を実行中は自分で作成したアイテムを操作することが、一切できなくなってしまうのですが、何か解決方法は無いでしょうか? 宜しくお願いします。

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

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

イベント内でループをしているため メッセージポンプが機能しないのが原因でしょう そのため ボタンのClickメッセージがWindowsのメッセージキューに残ってしまい Clickイベントが終了してからもう一度呼ばれるといったことが繰り返されます forループの中で Application::DoEvents() を実行するようにしてみましょう     for(i=0;i<200;i++){       int t=clock();       while(10>clock()-t);       textBox4->Text+=L"aaraeaewa"+i+L"\r\n";       textBox4->SelectionStart = textBox4->Text->Length;       textBox4->ScrollToCaret();       // これを追加 ClickイベントなどのWindowsメッセージを処理       Application::DoEvents();     }

glarelance
質問者

お礼

解答有り難うございました 確かにこのようにすると、再描画がかけられるのでできました。

その他の回答 (2)

  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.3

蛇足な追記。    static bool flug=false; 「何かの目印」と言う意味での変数なら、変数名は「flug」ではなく「flag」です。

  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.2

>この関数を実行中は多重実行されないことを想定しているのですが、やってみると多重実行されてしまいます。 余計なフラグ判定が原因。     static bool flug=false;     if(flug)return;     flug=true; と     flug=false; を削ってみましょう。 ボタン1が押された瞬間、関数の入り口でボタン1のEnabledをfalseにすれば、処理が終わるまで「押そうと思っても絶対に押せない」ので、多重実行はしない「筈」です。 もちろん、関数の出口でEnabledをtrueに戻すのも忘れないように。 要は、自分自身のEnabledプロパティが再入フラグの代わりになるのです。

glarelance
質問者

お礼

解答有り難うございます。 このフラグは無くて出来なかったから付けたものなので付いていても消えていても、無理でした。

関連するQ&A

  • スレッド

    VC++2008ExpressEditionを使用してプログラムを作成しています。 Windowsフォームアプリケーションを作成し、そこに、TextBoxとButtonを放り込み、ボタンを押すと以下のようなコードが実行されるようにしました。 関数testfuncはhoge::Form1::testfuncという風な場所で定義されています。 logBoxは、Form1のコンストラクタのTODOの部分で作成しています。   public: static System::Windows::Forms::TextBox^ logBox;   void testfunc(){     int i;     for(i=0;i<200;i++){       int t=clock();       while(10>clock()-t);       logBox+=L"aaraeaewa"+i+L"\r\n";       logBox->SelectionStart = logBox->Text->Length;       logBox->ScrollToCaret();     }   }   System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {     button1->Enabled=false;     button1->Text=L"実行中";     button1->Update();     ThreadStart^ trddel=gcnew ThreadStart(this,&hoge::Form1::testfunc);     Thread ^trd=gcnew Thread(trddel);     trd->Start();     button1->Enabled=true;     button1->Text=L"実行";   } この関数をボタンを押して実行すると、testfunc関数の logBox->SelectionStart = logBox->Text->Length; の部分で、 'System.InvalidOperationException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました。 追加情報: 有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'logBox' がアクセスされました。 という風なエラーが出ます。 読んだ感じだと、元々のスレッドで作成したコントロールを新しく作ったスレッドからコントロールすることは出来ないって感じのことが書かれているのですが、どの様にすればこれは回避できるようになるのでしょうか?

  • actionscript3.0でボタン操作無効化

    flashのHPを作っております。 (mc)ボタンを配置しクリックすると画面の背景が変わる操作をしたいと思っており(top、new、main・・・など) 下記のHPのような http://www.mediacreator.jp/tutorials/show_tutorial.asp?id=69&pn=3 操作ボタンを作っております。 上記HPは2.0で製作されているため、3.0に改変し、 アクションを下のようにしました。 var buttonNames= new Array("button1", "button2", "button3", "button4"); button1.buttonMode = true; button2.buttonMode = true; button3.buttonMode = true; button4.buttonMode = true; button1.addEventListener(MouseEvent.CLICK, button1click); button2.addEventListener(MouseEvent.CLICK, button2click); button3.addEventListener(MouseEvent.CLICK, button3click); button4.addEventListener(MouseEvent.CLICK, button4click); function resetButton(buttonName){ for(var i = 0; i < buttonNames.length; i++){ if(buttonNames[i] != buttonName){ this[buttonNames[i]].gotoAndStop(1); this[buttonNames[i]].enabled = true; } } } function button1click(event:MouseEvent):void { resetButton(button1); this.gotoAndStop(2); this.enabled = false; } function button2click(event:MouseEvent):void { resetButton(button2); this.gotoAndStop(2); this.enabled = false; } function button3click(event:MouseEvent):void { resetButton(button3); this.gotoAndStop(2); this.enabled = false; } function button4click(event:MouseEvent):void { resetButton(button4); this.gotoAndStop(2); this.enabled = false; } コンパイルエラーは無くなったのですが、ボタン自体が動いてくれません。 どこが間違っているか分かる方、お教え下さい!

  • Visual C++ 2008 EEでボタンの判定、結果を配列に格納

    OSはXPでViaual C++ 2008 Express EditionのWindowsフォームアプリケーションにて一つのフォームで全132問に答えるというものを作成しています。フォームには[戻る]、[次へ進む]、[チェック除外]ボタンと「はい」、「いいえ」、「どちらでもない」のラジオボタン、問題文とタイマーのラベル、テキストボックス(問題番号を入力すると[戻る]ボタンが[移動]ボタンに変わり、入力した問題に進む)があります。最初に変数qに1を入れ、[次へ進む]を押すとqに1がプラスされswitch文で2問以降に進む(ラベルのみ切り替わる)というもので、最後の問題に行くと[次へ進む]ボタンが[終了]ボタンに変わります。ただし、全ての問題に解答していなければ終了できないようにしています。この解答結果をCSVに(はいなら1、いいえなら2、どちらでもないなら3)出力したいと考えているのですが、ラジオボタンにチェックを入れ、[次へ進む]ボタンを押したときのみ「インデックスが配列の境界外です」というエラーが表示されてしまいます。コードは以下の通りですが、どこを直せばよいのか分からないのでご教授願います。 private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { endflag = 0; this->button2->Text = "次へ進む"; if(flag == 1){ q = jump; flag = 0; this->button1->Text = "戻る"; this->textBox1->Text = ""; }else{ q--; } if(q == 1){ this->button1->Enabled = false; } switch(q){ case 1:                          ・                          ・                          ・                          case 132                           endflag = 1; break; }                            }: private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { String^ s = rtrstrg(); if(endflag == 1){ if(s == "") { MessageBox::Show("全ての質問に答えて下さい。","エラー"); } else if(MessageBox::Show("終了しますか?", "確認", MessageBoxButtons::OKCancel, MessageBoxIcon::Question) == System::Windows::Forms::DialogResult::OK) { this->Close(); } } q++; this->button1->Enabled = true; switch(q){ case 2:                      ・                      ・                      ・                      case 132                       endflag = 1;    break; }                      }: private: System::Void button3_Click(System::Object^ sender, System::EventArgs^ e) { this->radioButton1->Checked = false; this->radioButton2->Checked = false; this->radioButton3->Checked = false; } private: System::Void chg(System::Object^ sender, System::EventArgs^ e) { bool result = int::TryParse(textBox1->Text, jump); if(jump > 0 && jump <= 132){ if(jump != q){ this->button1->Text = "移動"; this->button1->Enabled = true; flag = 1; } } else{ textBox1->Text = ""; this->button1->Text = "戻る"; flag = 0; } } private: System::String^ rtrstrg() { String^ s; for(int i=1; i<=QSTNB; i++) { s += this->rtrdt(i); if(s->EndsWith("×")) { return ""; } } return s->Remove(s->Length - 1); } private: System::String^ rtrdt(int qstn) { //配列の宣言 array<RadioButton^>^ arb = gcnew array<RadioButton^>(SZBH); for(int i=0; i<SZBH; i++) { arb[i] = dynamic_cast<RadioButton^>(this->Controls->Find("radioButton"+(qstn*SZBH-SZBH+1+i), true)[0]); } return this->chck(arb); } private: System::String^ chck(array<RadioButton^>^ arb) { for(int i=0; i<arb->Length; i++) { if(arb[i]->Checked == true) { return i + 1 + ","; } } return "×"; }

  • VB2008 textbox入力判断について

    こんばんは、いつもお世話になりました。 VB2008で "ストップワォッチ"と"タイムダウン"のプログラムを作っています。 要望: 1 TextBox1.textが入力しない時、ストップワォッチを実行 (OK) 2 TextBox1.textが入力する時、TextBox1.textの値からタイムダウンを実行 (OK) 3 TextBox1.textの値をクリアされた時、再度ストップワォッチを実行 4 TextBox1.textに文字列入力された時、数字に変更してから タイムダウンを実行 (例:全角12:56 →12:56) 5 TextBox1.textが入力エラーの場合は プログラムを抜け、何もしないこと 下記のソースでしたら、3と4,5はまだできていません。 宜しくお願いします。 ---------------------------------------------------- 'TextBox1.textが入力しない時、ストップワォッチを実行 If TextBox1.Modified = False Then Timer1.Enabled = True datStart = Now() Me.Button1.Enabled = False Me.Button3.Enabled = False End If 'TextBox1.textが入力する時、TextBox1.textの値からタイムダウンを実行 If TextBox1.Modified = True Then dTime = TextBox1.Text Timer2.Interval = 1000 Timer2.Enabled = True End If 'TextBox1.textの値を再度クリアされた時、ストップワォッチを実行 If Len(TextBox1.Text) = 0 Then TextBox1.Modified = False End If -------------------------------------------------------------- 以上

  • AxMediaPlayerの再生終了の取得方法

    いつもお世話になっております。 AxMediaPlayerを使って音声を再生し、 再生し終わったらデフォルトの状態に 戻したいのですが、再生終了を確認 することができません。 例えば、デフォルトでButton2.Enabled = False となっていて、再生中はTrue、再生終了でFalse に戻そうとして Button2.Enabled = True AxMediaPlayer1.Play()     Button2.Enabled = False としても、再生と同時にまたFalseに 戻ってしまいます。 なにか良い方法はないでしょうか。 よろしくお願いします。

  • C# 簡単なシューティング 自機移動について

    かなりの初心者で困っています。 簡単なシューティングを作ろうとおもっています。 使用ソフトはVisualC#2005です。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } //自機(右移動) private void button3_Click(object sender, EventArgs e) { if (timer1.Enabled == false) { timer2.Enabled = false; timer1.Enabled = true; } else { timer1.Enabled = false; timer3.Enabled = false; timer4.Enabled = false; } } private void timer1_Tick(object sender, EventArgs e) { pictureBox1.Left = pictureBox1.Left + 2; } //自機(左) private void button4_Click(object sender, EventArgs e) { if (timer2.Enabled == false) { timer1.Enabled = false; timer2.Enabled = true; } else { timer2.Enabled = false; timer3.Enabled = false; timer4.Enabled = false; } } private void timer2_Tick(object sender, EventArgs e) { pictureBox1.Left = pictureBox1.Left - 2; } //自機(上) private void button1_Click(object sender, EventArgs e) { if (timer3.Enabled == false) { timer4.Enabled = false; timer3.Enabled = true; } else { timer1.Enabled = false; timer2.Enabled = false; timer3.Enabled = false; } } private void timer3_Tick(object sender, EventArgs e) { pictureBox1.Top = pictureBox1.Top - 2; } //自機(下) private void button2_Click(object sender, EventArgs e) { if (timer4.Enabled == false) { timer3.Enabled = false; timer4.Enabled = true; } else { timer1.Enabled = false; timer2.Enabled = false; timer4.Enabled = false; } } private void timer4_Tick(object sender, EventArgs e) { pictureBox1.Top = pictureBox1.Top + 2; } } } 自機は画像(PictureBox)でボタンによって上下左右に移動します。 FormのSizeは800,630です。 自機の移動がボタンなのでキー入力によって操作できるようにしたいのですが、 それと、自機の移動範囲を画面からでないようにしたいです。 あまりC#を理解できてない上でつくったのでおかしな点が多々あると思います。 教えていただける方がいると助かります。

  • 【Excel VBA】ユーザーフォーム テキストボックスの有効・無効について

    Excel2003を使用しています。 ユーザーフォームにテキストボックスを11個とコマンドボタンを2個配置しています。 TextBox9に“0000”(文字列です)が入力されたら、TextBox10を有効に、それ以外は無効に設定したく、TextBox10のEnabledプロパティをFalse、LockedプロパティをTrueにして、コードを下記のように書いたのですが、うまくいきません。どこか、間違っているでしょうか? コードは該当部分だけ、載せています。よろしくお願いします。 -------------------------------------------------- If TextBox9.Text = "0000" Then TextBox10.Enabled = True TextBox10.Locked = False TextBox10.BackStyle = fmBackStyleOpaque Else TextBox10.Enabled = False TextBox10.Locked = True TextBox10.BackStyle = fmBackStyleTransparent End If

  • BackgroundWorkerについて(C#)

    C#でBackgroundWorkerを使ったプログラムを試しています。 Windows Form上にButtonとProgressBarを設置して以下のプログラムを 動作させると、プログレスバーが終了するまえに”終了”が出てしまいますが これはどうしてでしょうか? よろしくお願いいたします。 using System; using System.ComponentModel; using System.Threading; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { button1.Enabled = false; Random rand = new Random(); BackgroundWorker bgWorker = new BackgroundWorker(); bgWorker.DoWork += ((sender2, e2) => { for (int i = 0; i < 10; i++) { Thread.Sleep((int)(rand.NextDouble() * 500)); bgWorker.ReportProgress((i + 1) * 10); } }); bgWorker.RunWorkerCompleted += ((sender2, e2) => { button1.Enabled = true; bgWorker.Dispose(); MessageBox.Show("終了"); }); bgWorker.ProgressChanged += ((sender2, e2) => { progressBar1.Value = e2.ProgressPercentage; }); bgWorker.WorkerReportsProgress = true; bgWorker.RunWorkerAsync(); } } }

  • スピンボタンとテキストボックスの連動

    Excel2000.2003 [UserForm]に [SpinButton1] と[SpinButton2] 及び [TextBox]を縦6 横10の表らしきものを作り パソコン初心者にも使える様、また 入力ミスを防ぐ為に [SpinButton1.2]で必要な箇所[TextBox]の 配置のVisibleをFalse⇔Trueに変え表示するようにしたいのです ---------------------------------------------------------  [TextBox1]     [TextBox2] [SpinButton1]    [SpinButton2] ------------------------------------------- [Text 3][Text 9][Text15][…][…][…][][][][] [Text 4][Text10][Text16][…][…][…][][][][] [Text 5][Text11][Text17][…][…][…][][][][] [Text 6][Text12][Text18][…][…][…][][][][] [Text 7][Text13][Text19][…][…][…][][][][] [Text 8][Text14][Text20][…][…][…][][][][] ---------------------------------------------- [Text 1]は[SpinButton1]の値を表示します(初期値1) [Text 2]は[SpinButton2]の値を表示します(初期値1) [Text 3]は[SpinButton1][SpinButton2]が共に初期値1の為 デフォルトとして表示します。 SpinButton1を増減することにより、例えば SpinButton1="2"の場合 SpinButton2の値を考慮しながら [Text 3][Text 9][Text15][…][…][…][][][][] [Text 4][Text10][Text16][…][…][…][][][][]  VisibleがFalse⇔Trueに変わり  例えば、SpinButton1="2"の場合 SpinButton2を増減すると 列配置の 例えば SpinButton2="1"の場合 SpinButton1の値を考慮しながら [Text 9][Text15][…][…][…][][][][] VisibleがセットでFalse⇔Trueに変わるようにしたいのです。 意味解りますか? どなたか助けてください。

  • コンボボックスの変更に応じてテキストボックスの有効を切り替える(ExcelVBA2007)

    お世話になります。 Excel VBA 2007で質問です。 今、  Label1 ComboBox1 TextBox1  Label2 ComboBox2 TextBox2 ・・・  Label100 ComboBox100 TextBox100 のようなフォームがあるとします。 ComboBox1~100は「Any」「is」「is not」のいずれかの値が取れ、初期値はAnyとします。 TextBox の Enabled プロパティの初期値は False とします。 やりたいことは、 ComboBox が「Any」でない場合(is または is not のいずれかの場合)にのみその右隣の TextBox の Enabled プロパティを True にしたいのです。 いま、ComboBox30 を Any から is に切り替えたとします。 すると、TextBox30.Enabled を False から True にしたいのです。 ここで、ComboBox30 を is から is not に切り替えたとします。 TextBox30.Enabled は True のままです。 ここで、ComboBox30 を is not から Any に切り替えたとします。 すると、TextBox30.Enabled を True から False にしたいのです。 ComboBox のイベントハンドラで Sub ComboBox30_Change ()  If ComboBox30.Value = "Any" Then   TextBox30.Enabled = "False"  Else   TextBox30.Enabled = "True"  End If End Sub のように書けばいいことは分かっているのですが、その場合は数字だけ変えたイベントハンドラを100個書かなければなりません。 このイベントハンドラを1個にすることはできるでしょうか。 (コンボボックス100個のうちどれかが変更されたら、変更されたコンボボックスの番号を知りながら呼び出されるハンドラ) 次善の策として、 Sub ComboBox30_Change ()  userSubroutine End Sub のように書くこともできるかと思いますが、この場合、どのコンボボックスが変更されたか(どのイベントハンドラが起動されたか)を知って、userSubroutine に渡さなければなりません。 よろしくお願いします!