MFC环境下Start&Pause&Stop操作

28 篇文章 0 订阅
23 篇文章 0 订阅

要点

描述在Windows/MFC开发环境下,对于Start、Pause、Stop等典型操作的示例代码。

UI

示例效果如下:

Start-Pause-Stop

Start-Pause-Stop

Continue-Pause-Stop

  • Start:从0开始,计算每个整数的平方根,并显示在编辑框中;
  • Pause:暂停计算;Pause之后,可以Continue
  • Stop:停止计算。

要点

  • 用一个线程执行(耗时)任务;
  • ResumeThread()恢复线程的执行,相当于Continue;
  • SuspendThread()把线程挂起,相当于Pause;
  • 对于Stop,直接退出线程函数。

代码

VS2010环境。

资源文件

IDD_STARTPAUSESTOP_DIALOG DIALOGEX 0, 0, 293, 84
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "StartPauseStop"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    PUSHBUTTON      "Start",IDC_START,34,19,68,18
    PUSHBUTTON      "Pause",IDC_PAUSE,116,19,68,18
    PUSHBUTTON      "Stop",IDC_STOP,198,19,68,18
    EDITTEXT        IDC_MSG,35,52,230,17,ES_AUTOHSCROLL | ES_READONLY
END

头文件

这里没有特意考虑private或public。

class CStartPauseStopDlg : public CDialogEx
{
    //...

private:
    HANDLE m_hThread;
    BOOL m_bStopped;
    DWORD m_dwCurrent;
    CString m_sMsg;

public:
    static DWORD WINAPI ThreadProc(LPVOID lpThreadParameter);
    void Doit();
    void CloseThread();

    afx_msg void OnBnClickedStart();
    afx_msg void OnBnClickedPause();
    afx_msg void OnBnClickedStop();
    afx_msg void OnDestroy();
};

实现文件

省略了部分自动生成的代码。

//...
#include <math.h> // sqrt()

//...

CStartPauseStopDlg::CStartPauseStopDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(CStartPauseStopDlg::IDD, pParent)
    , m_sMsg(_T(""))
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CStartPauseStopDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_MSG, m_sMsg);
}

BEGIN_MESSAGE_MAP(CStartPauseStopDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_START, &CStartPauseStopDlg::OnBnClickedStart)
    ON_BN_CLICKED(IDC_PAUSE, &CStartPauseStopDlg::OnBnClickedPause)
    ON_BN_CLICKED(IDC_STOP, &CStartPauseStopDlg::OnBnClickedStop)
    ON_WM_DESTROY()
END_MESSAGE_MAP()

BOOL CStartPauseStopDlg::OnInitDialog()
{
    //...

    m_hThread = NULL;
    m_bStopped = FALSE;
    m_dwCurrent = 0;
    GetDlgItem(IDC_PAUSE)->EnableWindow(FALSE);
    GetDlgItem(IDC_STOP)->EnableWindow(FALSE);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CStartPauseStopDlg::OnBnClickedStart()
{
    m_bStopped = FALSE;

    if (NULL == m_hThread) {
        m_hThread = ::CreateThread(NULL, 0, ThreadProc, this, 0, NULL);
    } else {
        ::ResumeThread(m_hThread);
    }

    GetDlgItem(IDC_START)->EnableWindow(FALSE);
    GetDlgItem(IDC_PAUSE)->EnableWindow(TRUE);
    GetDlgItem(IDC_STOP)->EnableWindow(TRUE);
}

void CStartPauseStopDlg::OnBnClickedPause()
{
    GetDlgItem(IDC_START)->EnableWindow(TRUE);
    GetDlgItem(IDC_START)->SetWindowText(_T("Continue"));
    GetDlgItem(IDC_PAUSE)->EnableWindow(FALSE);

    ::SuspendThread(m_hThread);
}

void CStartPauseStopDlg::OnBnClickedStop()
{
    m_bStopped = TRUE;
    GetDlgItem(IDC_START)->EnableWindow(TRUE);
    GetDlgItem(IDC_START)->SetWindowText(_T("Start"));
    GetDlgItem(IDC_PAUSE)->EnableWindow(FALSE);
    GetDlgItem(IDC_STOP)->EnableWindow(FALSE);

    ::ResumeThread(m_hThread); // Let the thread can exit by itself
    CloseThread();
    m_dwCurrent = 0;
}

void CStartPauseStopDlg::OnDestroy()
{
    CDialogEx::OnDestroy();

    CloseThread();
}

DWORD WINAPI CStartPauseStopDlg::ThreadProc(LPVOID lpThreadParameter)
{
    CStartPauseStopDlg* pObj = (CStartPauseStopDlg*)lpThreadParameter;

    HANDLE hSleepEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    for (;;) {
        if (pObj->m_bStopped) {
            //::AfxMessageBox("User stopped the task.");
            break;
        }   

        pObj->Doit();

        ::WaitForSingleObject(hSleepEvent, 2000);
    }

    return 0;
}

void CStartPauseStopDlg::Doit()
{
    double d = sqrt(m_dwCurrent * 1.0);

    m_sMsg.Empty();
    m_sMsg.Format("sqrt(%d) = %lf", m_dwCurrent, d);
    m_dwCurrent++;

    //UpdateData(FALSE); //Debug Assertion Failed!
    this->SetDlgItemText(IDC_MSG, m_sMsg); 

    //::AfxMessageBox("Do something ...");
}

void CStartPauseStopDlg::CloseThread()
{
    if (NULL == m_hThread) return;

    m_bStopped = TRUE;
    WaitForSingleObject(m_hThread, INFINITE);
    CloseHandle(m_hThread);
    m_hThread = NULL;
}

后记

示例代码中并没有考虑下面这种情况:在没有Pause&Stop的情况下,后台任务(线程)执行完了,这个时候应该主动去更新Start&Pause&Stop的Enable状态。

——当然,本例中线程是执行一个永无止境的任务。现实中,往往不是这样的。

因此,需要在线程真正完成后台任务的时候,去更新UI或执行类似的任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值