我会尽量保持简单。我们假设我们创建了以下非常简单的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;
}
}
}
注意:整体问题要复杂得多,但这个例子就像保持案例的本质一样简单。任何帮助将不胜感激。
答案 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";
}
}
希望这对其他人有所帮助。如果看起来没有任何优化(特别是线程休眠),我将非常感谢您在阅读代码后想到的任何提示或评论。