【问题标题】:How to stop while loop by pressing a button in MFC dialog如何通过按下 MFC 对话框中的按钮来停止 while 循环
【发布时间】:2021-01-21 04:57:44
【问题描述】:

我正在使用 C++ 在 Visual Studio 2017 上开发基于对话框的 MFC 应用程序。

在我的应用程序中,我有一个显示文本的窗口。当我按下“开始”按钮时,我正在使用无限循环向它写入数字,并且我想在按下“停止”按钮时停止这个过程。窗口如下所示:

为此,在Start 按钮处理程序中,我使用while 循环来计算并在应用程序窗口中打印计数器。每次进入 while 循环时,我都会检查是否像这样按下了 ICD_BUTTON2(即停止按钮 ID):

void CEditableListControlDlg::OnBnClickedButton1()
{
     int counter = 0;
     while ((WM_COMMAND != IDC_BUTTON2)) {
            counter++;
            m_editCtrl.SetWindowTextA(std::to_string(counter).c_str());
     }
}

我没有在Stop 按钮处理程序中输入任何代码。

但我的应用程序停止响应,我需要使用任务管理器将其关闭。可能是什么问题呢?也许这不是检查是否收到按钮单击消息的正确方法?

谢谢。

【问题讨论】:

  • 我的橡皮鸭想知道WM_COMMANDIDC_BUTTON2 如何在循环中改变它们的值
  • WM_COMMANDIDC_BUTTON2 是常量。你基本上是在写while (12 != 34) ...
  • 恕我直言,这需要在工作线程中完成吗?因此,在“开始”按钮中,您启动工作线程,将句柄传递给窗口,以便它可以发布消息以使用数字进行更新。然后,当您按下停止按钮时,您会杀死工作线程......否则,在按钮处理程序中使用 while 只会阻塞系统。或者使用 cmets 中建议的计时器方法。
  • @AndrewTruckle 工作线程对我来说听起来有点矫枉过正。恕我直言,计时器在这里更合适。但毕竟我们不知道 OP 实际上 试图实现什么。因为只是增加一个数字对我来说听起来毫无意义。

标签: c++ visual-studio user-interface mfc dialog


【解决方案1】:

这里最重要的是你阻塞了主线程。即使您更正了停止按钮上的错误检查,您也不会得到预期的结果。原因是当一个事件被触发时,一个按钮被按下,主线程需要处理那个事件。你的循环在路上,why the suggestion of using a timer。这就是为什么你必须终止进程才能结束它。

如果你真的需要做一些非常激烈的事情,那么可能需要一个线程,但我认为这不是你的目标。

//在.h中

UINT_PTR timer;

//在.cpp中

//initialize timer to null in constructor or CEditableListControlDlg::Create

//you may want to disable the this button while the timer is active
//but don't start another timer if active!
void CEditableListControlDlg::OnBnClickedButton1()
{
    if(timer)
        return;
    //200 millisecond events.
    timer= SetTimer( ID_TIMER, 200, NULL );
}

void CEditableListControlDlg::OnTimer( UINT nIDEvent ) 
{
    //if you have more than one timer, if(nIDEvent == ID_TIMER)...;
    counter++;
    m_editCtrl.SetWindowTextA(std::to_string(counter).c_str());
    CWnd::OnTimer( nIDEvent );
}

//you may want to disable the this button while the timer is inactive
void CEditableListControlDlg::OnBnClickedButton2()
{
    if(timer)
        KillTimer(timer);
    timer= nullptr;
}

【讨论】:

    【解决方案2】:

    我看不到计时器如何解决在后台处理某些内容时允许 UI 操作的问题。计时器方式将最多处理一个帽子计时器事件的工作单元。

    单独的线程是一个合适的解决方案,但对于这种情况可能太多了。

    中间方法是在您繁忙的while 循环中“泵送”消息,详情请参阅: https://docs.microsoft.com/en-us/cpp/mfc/idle-loop-processing?view=vs-2019

    【讨论】:

      【解决方案3】:

      每个 GUI 程序在某处都有一个消息循环,用于检查来自操作系统的传入消息并对其做出反应。通过自己创建无限循环,您可以阻止这种情况发生 - 这就是您需要任务管理器来关闭程序的原因。它还会阻止诸如窗口重绘之类的事情。

      MFC 提供了一个OnIdle 函数,当消息循环无关时调用该函数。你可以使用这个函数来做后台工作,比如增加你的计数器。有关详细信息,请参阅 Microsoft 的文档 Idle Loop Processing

      【讨论】:

        【解决方案4】:

        要允许主消息循环处理 GUI 事件(如单击停止按钮),请在您的 while 循环中添加并调用此函数 PumpMessages()

        void CEditableListControlDlg::PumpMessages()
        {
            // Must call Create() before using the dialog
            ASSERT(m_hWnd!=NULL);
        
            MSG msg;
            // Handle dialog messages
            while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
            {
              if(!IsDialogMessage(&msg))
              {
                TranslateMessage(&msg);
                DispatchMessage(&msg);  
              }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2015-07-19
          • 1970-01-01
          • 2016-08-06
          • 1970-01-01
          • 2020-06-01
          • 2012-07-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多