2014-05-15 140 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'可用于计算处理的视频帧,其余代码可用于处理视频帧,而第二个按钮则可用于'停止处理'......这只是我现在头脑中的一个例子,但你可以想象许多其他人。 :) ............我也明白,线程将是更好的方法,但很多时候你没有奢侈的改变已经功能的应用程序的体系结构:( –