您的位置:首页 > 其它

单线程实习进度条,以及多线程实现进度条(对文件的遍历)

2015-04-14 18:17 429 查看
最近在实现一个遍历文件夹,并把进度同步显示在进度条上的小程序。因为对MFC还不熟悉, 所以花了几天的时间研究实现遍历文件夹与进度条的同步实现。最简单的一种进度条的实现方法是单线程的,点一下按钮进度条动一下的方式,这种实现步骤如下:

(一)、单线程进度条实现

首先,添加Progress控件,然后给它添加变量m_pro。其次,添加两个按钮控件:开始、前进。然后,添加两个button事件。



void CDemo05Dlg::OnButton1() //开始按钮
{
// TODO: Add your control notification handler code here
m_pro.SetRange(0,100);
m_pro.SetStep(5);
m_pro.SetPos(10);
}
void CDemo05Dlg::OnButton2() //前进按钮
{
// TODO: Add your control notification handler code here
m_pro.StepIt();
}


(二)、多线程进度条实现:遍历文件夹,同时进度条显示遍历进度



标题

遍历文件夹是一个可大可小的程序,当遍历的路径中文件个数很多时,遍历全部的文件需要耗很长时间,为了不让用户错误的认为系统进入死机的状态,我们给程序加入进度条。但是如果直接添加进度条,在程序中控制他的进度,结果进度条只向前进一步,仍然像死机状态。那该怎么办呢?原因是,我们处理比较大的计算程序时,程序和进度条显示实在同一个进程中进行的,这样程序会先处理计算程序,导致进度条无法实时更新。

解决办法就是把处理大程序的这段逻辑让一个单独的线程去处理,并利用postmessage或sendmessage给主界面发送消息,让主界面去更新进度条。

具体代码和步骤如下。

首先,文本框、按钮、静态文本框、进度条等控件,然后在cpp文件中定义一个关联事件:

#define WM_UPDATEDATA WM_USER + 1999 //定义事件

BEGIN_MESSAGE_MAP(CDemo05Dlg,CDialog)
ON_MESSAGE(WM_UPDATEDATA,&CDemo05Dlg::OnUpdateData)//让事件与程序关联
END_MESSAGE_MAP


标题

第二步,在头文件中进行函数和变量的声明

afx_msg LRESULT OnUpdateData(WPARAM wParam,LPARAM lParam);

LRESULT onUpdateData(WPARAM wParam,LPARAM lParam);

static UINT MyThread(LPVOID pParam);//必须定义为static,线程函数可以且必须是全局函数或者是静态成员函数。

CWinThread *m_pMyThread;

int ProcessLogFile(CString filepath);

void setProcess(int value);

CString filePath;

int FileSearch(CString root);

int iProRange;//统计文件个数

CString m_FilePath;//全局变量,保存最初的文件路径

CProgressCtrl m_ProgCtrl;//进度条变量

CStatic m_Num;

int iCount;//统计机器码文件

CString szNum;

CString szFilepath;//FileSearch函数中使用

标题

第三步、实现关联程序(返回类型一定要是LRESULT)

//线程处理进度条

LRESULT CDemo05Dlg::OnUpdateData(WPARAM wParam,LPARAM lParam)

{

int iTemp = (int )wParam;

m_ProgCtrl.SetPos(iTemp);//设置进度条的值

UpdateData(FALSE);//实时更新主界面

return 0;

}

标题

第四步、创建一个独立的线程处理大程序

在OnInitial函数中,对m_pMyThread初始化:

m_pMyThread = NULL;

在【遍历文件夹】按钮下,创建线程:

void CDemo05Dlg::OnBnClickedBtn()
{
// TODO: 在此添加控件通知处理程序代码
iCount=0;//在遍历函数中统计文件数,chongzhi
m_ProgCtrl.SetPos(0);//重置进度条
GetDlgItem(IDC_EDIT1)->GetWindowTextW(m_FilePath);//获取指定的文件路径

//MyThread为该大程序处理的入口函数,this为入口函数的参数
if (!m_FilePath.IsEmpty())
{
GetDlgItem(IDC_BTN)->EnableWindow(FALSE);//设置遍历按钮不可用
//统计文件个数,设进度条的range
FileSearch(m_FilePath);//统计文件个数,不是线程
m_ProgCtrl.SetRange(0,iProRange);
//创建新线程,实时更新进度条,将当前类this当做参数传递
m_pMyThread = AfxBeginThread(CDemo05Dlg::MyThread, this);

GetDlgItem(IDC_BTN)->EnableWindow(TRUE);

}
else
{
AfxMessageBox(L"请选择路径!");
}


}

统计文件个数函数FileSearch(m_FilePath),如下:

int CDemo05Dlg::FileSearch(CString root)
{
CFileFind fileFinder;
if (root.Right(1)!="/")
{
root+="/";
}
root+="*.*";
BOOL res=fileFinder.FindFile(root);//遍历目录下的文件、文件夹
while (res)
{
res=fileFinder.FindNextFile();
szFilepath=fileFinder.GetFilePath();
if (fileFinder.IsDirectory() && !fileFinder.IsDots())// 找到的是文件夹
{
FileSearch(szFilepath);// 递归
//AfxMessageBox(L"遍历文件夹");
}
else if (!fileFinder.IsDirectory() && !fileFinder.IsDots())// 找到的是文件
{
//获取文件类型
CString fileName = fileFinder.GetFileName();
int dotPos=fileName.ReverseFind('.');
CString fileExt=fileName.Right(fileName.GetLength()-dotPos);
if(fileExt == _T(".txt"))  //若是txt文件
{
CString szFileName = fileName.Left(fileName.GetLength()-4);  //获取文件名
if (szFileName == L"MyTxt")
{
iProRange ++;//统计MyTxt文件个数
}
}
}
}
return iProRange;
}


标题

第五步、实现遍历文件夹逻辑

UINT CDemo05Dlg::MyThread(LPVOID pParam)//注意返回类型为UINT
{
CDemo05Dlg *p=(CDemo05Dlg*)pParam; //获取传参(this)的值,指当前的类,
p->ProcessLogFile(p->m_FilePath);//调用生成函数,静态成员函数不可调用非静态变量,通过p间接调用。
p->szNum.Format(L"%d",p->iCount);
p->m_Num.SetWindowTextW(L"共 "+p->szNum+L"个文件");
return 0;
}


标题

第六步、向主线程发送消息让进度条实时更新

int CRealPipeSoftWareKeyVenderBatch::ProcessLogFile(CString root)
{
CFileFind fileFinder;
if (root.Right(1)!="/")
{
root+="/";
}
root+="*.*";
BOOL res=fileFinder.FindFile(root);//遍历目录下的文件、文件夹
while (res)
{
setProcess(iCount);//调用进度条实时更新函数实时更新进度条
res=fileFinder.FindNextFile();
filePath=fileFinder.GetFilePath();
if (fileFinder.IsDirectory() && !fileFinder.IsDots())// 找到的是文件夹
{
ProcessLogFile(filePath);// 递归
//AfxMessageBox(L"遍历文件夹");
}
else if (!fileFinder.IsDirectory() && !fileFinder.IsDots())// 找到的是文件
{
//获取文件类型
CString fileName = fileFinder.GetFileName();
int dotPos=fileName.ReverseFind('.');
CString fileExt=fileName.Right(fileName.GetLength()-dotPos);
if(fileExt == _T(".txt"))  //若是txt文件
{
CString szFileName = fileName.Left(fileName.GetLength()-4);  //获取文件名
if (szFileName == L"MyTxt")
{
iCount ++;//统计MyTxt文件个数
szNum.Format(L"%d",iCount);
m_Num.SetWindowTextW(L"第"+szNum+L"个");
。
。
。
//此处可进行一些其他的,对找到的文件的操作
。
。
。
}
}
}
}
}


最后,进度条更新函数

void CDemo05Dlg::setProcess(int value)
{
//向主线程发送消息更新进度条
SendMessage(WM_UPDATEDATA, value);
}


好了,运行程序看结果吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐