在托管 C++ GUI 中通过另一个事件结束/中断/切换一个事件

End / interrupt / switch one event by another event in managed C++ GUI

我会尽量保持简单。假设我们创建了以下非常简单的 GUI。它包含两个按钮:

更新:我可以 post 漂亮的图片! :)
我创建了两个静态变量:

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

点击[START]按钮后,触发如下代码:

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;
        }
    }
}

然后,在点击按钮[停止]后,我只是将动作的值设置为 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;
        }
    }
}

注:整体问题要复杂得多,但这个例子尽可能简单,以保持案例的本质。任何帮助将不胜感激。

好的,经过一些研究,我使用了 BackgroundWorker(在 Windows 表单工具列表中可用)。现在它就像一个魅力。我 post 我对问题的解决方案,因此其他人可能会从中受益。

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";
    }
}

希望这对其他人有所帮助。如果有什么地方似乎没有优化(尤其是线程休眠),我将不胜感激您在阅读代码后想到的任何提示或评论。