【资源下载】http://download.csdn.net/detail/jliuj/8031879
暑假期间,在学校做项目。项目中,有需要实现类似播放器的模块。本科非计算机专业出身,大一下也上过MFC的训练课程。但是那时候很苦逼啊,还没电脑。。在以前甚至很少接触电脑。所以听课的时候完全是云里雾里的,尽管也想学好,那种情况下,也只是想想而已。后来也折腾过MFC,没有专门训练、不具有针对性,学习效率可谓低下至极有了笔记本之后,狂补各种计算机方面的知识,从电脑小白也慢慢长成了电脑小黑了。因为大一学习C++,第一次接触到编程,后来也尝试各种编程,C/C++、Matlab、Python、Java,各种语言虽有涉猎,却博而不精,甚至连广度也不广。在CSDN上看到一些大牛的本科经历,实在有点自惭形秽……总的来说,本科期间,也没怎么玩,也没成为老师心中的“好学生”。但是,感谢那时候的折腾,不断的试错,也让自己有了点喜好吧,也增长了一些见识。起码到目前小硕阶段,还是有点用途的……唉,人到了年级,难免要啰嗦吐槽一下,各位看官见谅哈!
昨天老师又开始催了,说以后要阅读文献和做项目,"两手都要抓,两手都要硬"。并且每两周要开一次会,做一个阶段性的总结。本来还可以很慵懒的,三天打鱼两天晒网,以后就不行了。
扯远了,言归正题。本文主要目的是总结MFC中多线程编程的经验,一步步实现停表功能。
相信有过编程经历的同学都知道,当编写MFC的界面程序,点击按钮,常常会有一段时间的界面”卡死“的状况。在跟这个按钮对应的操作(Function)没有执行结束时,MFC没法响应用户的其他操作。当要实现“播放”-”暂停“-”结束“等跟播放器相关的功能模块时,普通的程序就显得无能为力了。这是就需要多线程来实现。
新建基于对话框的应用程序Mythread
1.实现时钟功能
(1)添加静态文本框,ID:IDC_CLOCK,标题:空
(2)在CMyThreadDlg::OnInitDialog()中,添加定时器
SetTimer(1,500,NULL); //设置500ms定时器
(3)为对话框添加定时器消息响应函数
void CMyThreadDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
static int halfsecond=0; //静态变量
CTime t=CTime::GetCurrentTime();
CString str=t.Format("%H:%M:%S");
if(halfsecond)
{
str.Replace(":"," "); //半秒闪烁
}
GetDlgItem(IDC_CLOCK)->SetWindowText(str);
halfsecond = ++halfsecond%2;
CDialog::OnTimer(nIDEvent);
}
2.实现停表功能
#include<time.h>
(1)首先添加按钮
开始:IDC_BTN_WATCH_STU_QG
清零:IDC_BTN_WATCH_RESET
(2)为对话框添加线程成员变量
CWinThread* pThdWatch(
#include <AFXWIN.H>)
以及
BOOL状态变量
m_bWatchPaused
、
m_bWatchWorking
,
并在 BOOL CMyThreadDlg::OnInitDialog()中对状态变量初始化
m_bWatchPaused = FALSE;
m_bWatchWorking = FALSE;
(3)双击开始按钮,添加消息响应函数OnBtnWatchStuQg
static INT mymiseconds = 0; //用于保存临时时间
static clock_t start,now; //时间
//
//自定义线程函数
UINT _StartWatch(LPVOID lparam)
{
CMyThreadDlg *pDlg = (CMyThreadDlg*) lparam; //对话框指针变量
int duration=0;
CString strWatch;
while(TRUE) / 循环
{
MSG msg; //消息变量
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(msg.message == WM_THREAD_WATCH_RESET)
//运行状态时,产生了WM_THREAD_WATCH_RESET消息
{
pDlg->m_bWatchWorking = FALSE;
pDlg->m_bWatchPaused = FALSE;
pDlg->GetDlgItem(IDC_BTN_WATCH_STU_QG)->SetWindowText("Start");
pDlg->GetDlgItem(IDC_EDIT_WATCH)->SetWindowText("0");
mymiseconds = 0;
return 0; // thread completed successfully
}
else
{
DispatchMessage(&msg);
}
}
Sleep(1);
now = clock();
duration = 1000*(now - start)/CLOCKS_PER_SEC + mymiseconds;
strWatch.Format("%d",duration);
pDlg->GetDlgItem(IDC_EDIT_WATCH)->SetWindowText(strWatch);
}
}
void CMyThreadDlg::OnBtnWatchStuQg()
{
// TODO: Add your control notification handler code here
//一共3种状态:①停止(!m_bWatchWorking)
//②运行(m_bWatchWorking && !m_bWatchPaused)
//③暂停(m_bWatchWorking && m_bWatchPaused)
if(!m_bWatchWorking) //停止状态,需要启动线程,并设置按钮字体为"Pause"
{
start = clock();
pThdWatch = AfxBeginThread(_StartWatch,this); //启动线程
GetDlgItem(IDC_BTN_WATCH_STU_QG)->SetWindowText("Pause");
m_bWatchWorking = TRUE;
m_bWatchPaused = FALSE;
}
else if(m_bWatchWorking && !m_bWatchPaused) 运行非暂停状态,将暂停(挂起),并设置按钮字体为"Start"
{
mymiseconds += 1000*(now-start)/CLOCKS_PER_SEC;
pThdWatch->SuspendThread(); //挂起线程
GetDlgItem(IDC_BTN_WATCH_STU_QG)->SetWindowText("Start");
m_bWatchWorking = TRUE;
m_bWatchPaused = TRUE;
}
else if(m_bWatchWorking && m_bWatchPaused) 挂起状态,将运行,并设置按钮字体为"Pause"
{
start = clock();
pThdWatch->ResumeThread(); //激活线程
GetDlgItem(IDC_BTN_WATCH_STU_QG)->SetWindowText("Pause");
m_bWatchWorking = TRUE;
m_bWatchPaused = FALSE;
}
}
(4)自定义停止消息
①在Dlg.h中添加自定义消息
#define WM_THREAD_WATCH_RESET 0x1404 //自定义消息
②在
OnBtnWatchReset()中,添加传递消息响应以及状态设置的语句
//
void CMyThreadDlg::OnBtnWatchReset()
{
// TODO: Add your control notification handler code here
if(pThdWatch)
{
::PostThreadMessage(pThdWatch->m_nThreadID, WM_THREAD_WATCH_RESET,0,0); //Post消息
//==>暂停时的停止响应
m_bWatchWorking = FALSE;
m_bWatchPaused = FALSE;
GetDlgItem(IDC_BTN_WATCH_STU_QG)->SetWindowText("Start");
GetDlgItem(IDC_EDIT_WATCH)->SetWindowText("0");
mymiseconds = 0;
}
}
③在线程启动的循环函数中,添加消息处理函数
UINT _StartWatch(LPVOID lparam)
{
循环体{
MSG msg; //消息变量
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(msg.message == WM_THREAD_WATCH_RESET)
//==>运行状态时,产生了WM_THREAD_WATCH_RESET消息,进行一些操作
{
pDlg->m_bWatchWorking = FALSE;
pDlg->m_bWatchPaused = FALSE;
pDlg->GetDlgItem(IDC_BTN_WATCH_STU_QG)->SetWindowText("Start");
pDlg->GetDlgItem(IDC_EDIT_WATCH)->SetWindowText("0");
mymiseconds = 0;
return 0; // thread completed successfully
}
else
{
DispatchMessage(&msg);
}
}
}
}