我会尽量保持简单。假设我们创建了以下非常简单的 GUI。它包含两个按钮:
更新:我可以发布漂亮的图片! :)
我创建了两个静态变量:
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;
}
}
}
然后,在点击按钮 [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;
}
}
}
注意:整体问题要复杂得多,但这个例子尽可能简单,以保持案例的本质。任何帮助将不胜感激。
最佳答案
好的,经过一些研究后,我使用了 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";
}
}
希望这对其他人有帮助。如果有什么地方似乎没有优化(尤其是线程休眠),我将不胜感激您在阅读代码后想到的任何提示或评论。
关于c++ - 在托管 C++ GUI 中通过另一个事件结束/中断/切换一个事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29818838/