2014-05-15 179 views
1

我目前正在建設一個Windows窗體應用程序,我已經拿到了下一個問題, 因爲語法即時通訊使用不會讓我做,我不能聲明一個變量全球性的,另外,我需要聲明的變量它自己的方法,最後,它必須循​​環,以便它能夠計數。這是我到目前爲止:我該如何解決這個循環?

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { 
      int i; 
      m_bIsTimerOn = true; 
      while (m_bIsTimerOn) 
       { 
         i++; 
         label1->Text = (i.ToString()); 
       } 
     } 

private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { 
      m_bIsTimerOn = false; 
      timer1->Enabled = false; 
     } 

m_bIsTimerOn是一個全局布爾值。正如你可能在這裏看到的,我的問題是如果我按下按鈕1,程序就停留在while循環中。我想知道,當你按下button2 while循環時,我也想知道這是否可能。如果你可以在C++中迴應,那也可以。

預先感謝您。

回答

1

我想你想增加i而計時器上。如果您需要更新i每個時鐘滴答那麼它很容易,刪除環(和可變BTW)和根本內部定時器更新Tick事件:

private: 
    int _i; 

    void button1_Click(Object^ sender, EventArgs^ e) { 
     _i = 0; 
     timer1->Enabled = true; 
    } 

    void _timer1_Tick(Object^ sender, EventArgs^ e) { 
     label1->Text = (i++).ToString(); 
    } 

    void button2_Click(Object^ sender, EventArgs^ e) { 
     timer1->Enabled = false; 
    } 

如果從計時器則蜱我必須獨立更新你必須把它在事件處理程序移動到BackgroundWorker或只是爲Application::Idle:

void OnIdle(Object^ sender, EventArgs^ e) { 
     label1->Text = (_i++).ToString(); 
    } 

    void button1_Click(Object^ sender, EventArgs^ e) { 
     _i = 0; 
     Application::Idle += gcnew EventHandler(this, Form1::OnIdle); 
     timer1->Enabled = true; 
    } 

    void button2_Click(Object^ sender, EventArgs^ e) { 
     Application::Idle -= gcnew EventHandler(this, Form1::OnIdle); 
     timer1->Enabled = false; 
    } 

至於最後要注意的:你甚至可以讓您的環路是,只是後您的label1->Text = (i.ToString());但這可能會消耗投入Application::DoEvents()通話很多CPU,放慢速度我們的應用程序,並打開您的代碼重新進入,我真的會避免這樣的事情...

+0

我不能用我喜歡這樣,因爲我使用的語法不會允許我使用它這樣。我提供的代碼只是一個示例。我需要用與它相同的方法制作。 – Thealon

+0

@Thealon我添加了最後一段(和第二個解決方案),但讓我說「我正在使用的語法」是非常好奇的句子。 UI是單線程的,然後保持緊密的循環運行,而用戶仍然可以調用其他方法是一個壞主意。也許你最好發佈一些更類似於你真正使用的代碼:設計上的一些改變會使它更好(讀作:如果你的循環執行的東西多於它應該移動到**單獨的線程* *正確同步)。 –

+0

我添加的語法,我認爲它不會幫你 – Thealon

0

您的程序處於無限循環,因爲while循環阻止消息得到處理,因此您的button2_Click不會被調用。

while (m_bIsTimerOn) 
{ 
    i++; 
    label1->Text = (i.ToString()); 

    Application.DoEvents(); // causes the application to handle pending events 
} 

所以,現在,如果按第二個按鈕,m_bIsTimerOn將成爲假,你的循環將終止:爲了使您的應用程序能夠處理出現的消息,在環路加Application.DoEvents()。

+0

-1我在答覆中發佈了相同的解決方案,並註明**請勿使用**。爲什麼?因爲它會使他的代碼重入。用戶可以再次點擊button1(例如)來異步製作其他不好的東西。花一些時間閱讀[本文](http://blog.codinghorror.com/is-doevents-evil/)。有些東西要避免99.99%的時間(這不是0。01) –

+0

親愛的@Adriano,我非常理解與這種方法相關的問題(如果這種方法是單獨使用的)。我也知道,大多數情況下,問題中提供的代碼不是完整的問題,而只是幫助其他人理解問題並提供解決方案的一個片段;因此我只提供了一個可以在這樣的地方使用的解決方案。 –

+0

一個例子可能是,在讀取和處理大型視頻文件時,變量'i'可用於計算處理的視頻幀,其餘代碼可用於處理視頻幀,而第二個按鈕則可用於'停止處理'......這只是我現在頭腦中的一個例子,但你可以想象許多其他人。 :) ............我也明白,線程將是更好的方法,但很多時候你沒有奢侈的改變已經功能的應用程序的體系結構:( –