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

时间:2015-04-23 09:12:27

标签: c++ winforms events visual-c++ parallel-processing

我会尽量保持简单。我们假设我们创建了以下非常简单的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]后,我只需将action的值设置为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 个答案:

答案 0 :(得分:0)

好的,经过一些研究,我使用了BackgroundWorker(Windows窗体工具列表中提供)。现在它就像一个魅力。我发布了解决问题的方法,以便其他人可以从中受益。

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

希望这对其他人有所帮助。如果看起来没有任何优化(特别是线程休眠),我将非常感谢您在阅读代码后想到的任何提示或评论。