2015-04-23 23 views
1

我會盡量保持它儘可能簡單。假設我們創建了以下非常簡單的GUI。它包含兩個按鈕:通過託管C++ GUI中的另一個事件結束/中斷/切換一個事件

Image of my GUI 更新:我可以張貼漂亮的圖像! :)
我創建了兩個靜態變量:

public: static int counter = 0; // our output 
public: static int action = 0; // info about action status 

點擊[開始]按鈕後,下面的代碼被觸發:

private: System::Void start_btn_Click(System::Object^ sender, System::EventArgs^ e) { 

    // Change the action value so it is visible in the form 
    action = 1; 

    std::string str_value; 
    String^ managed_str_value; 

    for (int i = 0; i < 10000000; i++) { 

     // Update the counter: 
     counter = i; 

     // I want to break the loop and print the value of 'counter' 
     //in 'output_txt' textbox once I click the 'STOP' button 
     if (action == 0) { 

      // Conversion from int to managed string: 
      std::ostringstream str_streamer; 
      str_streamer << counter; 
      str_value = str_streamer.str(); 
      managed_str_value = gcnew String(str_value.c_str()); 

      // Print in the textbox: 
      this->output_txt->Text = managed_str_value; 

      // Finish the loop: 
      break; 
     } 
    } 
} 

然後,點擊按鈕[STOP]後,我剛動作的值設置爲0這樣的:

private: System::Void stop_btn_Click(System::Object^ sender, System::EventArgs^ e) { 

    // On stop_btn click, I just switch action value to 0, which I expect 
    // to be noticed inside loop started by 'start_btn' 
    action = 0; 
} 

我習慣了這樣的事件在LabVIEW編寫的一些項目處理,該工作就像一個魅力一樣,但是在這裏,點擊[START]按鈕讓我等待處理這個簡單循環的結束,並凍結計算時的GUI,結果 - 這讓我沒有機會在處理(這是必要的)。

另一個問題(我認爲是與這個問題有關)是:爲什麼在將代碼打印到output_txt(如下所示)後,我看不到每個新值在我的文本框中更新?

private: System::Void start_btn_Click(System::Object^ sender, System::EventArgs^ e) { 

    // Change the action value so it is visible in the form 
    action = 1; 

    std::string str_value; 
    String^ managed_str_value; 

    for (int i = 0; i < 10000000; i++) { 

     // Update the counter: 
     counter = i; 

     // Now I try to print the result every time I switch the counter: 
     std::ostringstream str_streamer; 
     str_streamer << counter; 
     str_value = str_streamer.str(); 
     managed_str_value = gcnew String(str_value.c_str()); 

     this->output_txt->Text = managed_str_value; 

     // I want to break the loop once I click the 'STOP' button 
     if (action == 0) { 

      // Finish the loop: 
      break; 
     } 
    } 
} 

注意:總體問題要複雜得多,但這個例子就像保持案例本質一樣簡單。任何幫助將不勝感激。

+1

理解UI編程的事件驅動本質是非常重要的。 UI線程不會繪製文本框,並且在被for()循環佔用時不會檢測到Stop按鈕。它一次只能做一件事。長時間運行的代碼需要由工作線程執行,BackgroundWorker和Task類可以幫助您編寫這種類型的代碼。 –

+0

我認爲使用BackgroundWorker應該這樣做......添加新線程似乎很奇怪,只是爲了不使圖形界面混亂(即使在本示例中如此簡單)計算。我的想法是它應該由內部算法來管理,但我顯然是錯誤的。正如我在Windows窗體上工作,任何有用的鏈接或教程,將不勝感激。 – irchris102

回答

0

好吧,經過一些研究後,我使用了BackgroundWorker(可在Windows Forms工具列表中找到)。現在它像一個魅力。我將我的解決方案發布到問題上,以便其他人可以從中受益。

BackgroundWorker的有定義的三個事件:

// Background Worker 
// What is being processed 
private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) { 

     for (int i = counter; i < 1000000; i++) { 

      // Sleep to prevent stack overflow (I think) 
      System::Threading::Thread::Sleep(10); 

      // Update the counter: 
      counter = i; 

      // Reporting progress: 
      backgroundWorker1->ReportProgress(counter); 

      // This happens when we trigger cancellation of work 
      // for Background Worker 
      if (backgroundWorker1->CancellationPending) { 
       e->Cancel = true; 
       backgroundWorker1->ReportProgress(0); 
       return; 
      } 
     } 
    // Final result 
    e->Result = counter; 
} 

// How do we report progress 
private: System::Void backgroundWorker1_ProgressChanged(System::Object^ sender, System::ComponentModel::ProgressChangedEventArgs^ e) { 

     // Conversion from int to managed string: 
     std::ostringstream str_streamer; 
     str_streamer << e->ProgressPercentage; 
     std::string str_value = str_streamer.str(); 
     String^ managed_str_value = gcnew String(str_value.c_str()); 

     // Display current status 
     this->output_txt->Text = managed_str_value; 
} 

// What happens after work is done 
private: System::Void backgroundWorker1_RunWorkerCompleted(System::Object^ sender, System::ComponentModel::RunWorkerCompletedEventArgs^ e) { 
    if (e->Cancelled) { 

     // Conversion from int to managed string 
     std::ostringstream str_streamer; 
     str_streamer << counter; 
     std::string str_value = str_streamer.str(); 
     String^ managed_str_value = gcnew String(str_value.c_str()); 

     // Print current value 
     this->output_txt->Text = managed_str_value; 
    } 
    else { 
     this->output_txt->Text = e->Result->ToString(); 
    } 
} 

這是當我點擊我的兩個按鈕(啓動/停止)我做的:

// START button 
private: System::Void start_btn_Click(System::Object^ sender, System::EventArgs^ e) { 

     if (!backgroundWorker1->IsBusy) { 

      // Start the execution asynchronously 
      backgroundWorker1->RunWorkerAsync(); 
     } 
     else { 
      this->output_txt->Text = "Busy processing, please wait"; 
     } 
} 

// STOP button 
private: System::Void stop_btn_Click(System::Object^ sender, System::EventArgs^ e) { 

    if (backgroundWorker1->IsBusy) { 

     // Cancel work in progress 
     backgroundWorker1->CancelAsync(); 
    } 
    else { 
     this->output_txt->Text = "No operation in progress"; 
    } 
} 

希望這將是其他人的幫助。如果有什麼東西看起來不是最優化的(特別是線程睡眠),那麼在閱讀代碼之後,我會很感激你的任何提示或意見。

相關問題