项目积木积累2

1.解决子界面的变量,能传回主界面继续使用:方法是定义一个Global.h和Global.cpp文件:

Global.h中

//文档保存路径-让主子界面发生交互需要的路径信息
extern CString strFolderPath;

Global.cpp

//全局变量的设定 在”Global.h”中对界面需要交互数据进行声明
#include "stdafx.h" //必须包含进来
#include "Global.h"

//文档保存路径-让主子界面发生交互需要的路径信息
CString  strFolderPath = TEXT("");
这个必须包含进来原因见博客: #include”* .h“ 在查找预编译头使用时跳过

之后再子界面中添加Global.h文件,然后在界面中“文档保存位置”按钮,添加消息响应函数

//生成报告保存文档路径选择
void InputMenu::OnBnClickedDocsavefile()
{
	// TODO:  在此添加控件通知处理程序代码
	//把生成的word报告保存到用户想要的指定路径//VARIANT* FileName, 文档保存路径	//    covOptional,  //文档的保存格式
	//创建一个选择文件夹的对话框,返回所选路径  
	TCHAR           szFolderPath[MAX_PATH] = { 0 };
	//CString         strFolderPath = TEXT("");变成全局变量
	// extern CString strFolderPath; 	CString         strFolderPath = TEXT("");
	BROWSEINFO      sInfo;
	::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
	sInfo.pidlRoot = 0;
	sInfo.lpszTitle = _T("请选择一个文件夹保存文档:");
	sInfo.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX;
	sInfo.lpfn = NULL;

	// 显示文件夹选择对话框  
	LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&sInfo);
	if (NULL == lpidlBrowse)
	{
		AfxMessageBox("没有选择路径,请重新选择!");
		while (!lpidlBrowse)
		{
			// 重新显示文件夹选择对话框
			lpidlBrowse = ::SHBrowseForFolder(&sInfo);
			// 重新取得文件夹名  
			if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
			{
				strFolderPath = szFolderPath;
				SetDlgItemText(IDC_FileNameEdit, strFolderPath);
			}
		}
	}
	else
	{
		//取得文件夹名
		if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
		{
			strFolderPath = szFolderPath;
			SetDlgItemText(IDC_FileNameEdit, strFolderPath);
		}
	}
	//释放资源
	if (lpidlBrowse != NULL)
	{
		::CoTaskMemFree(lpidlBrowse);
	}

}
这里,
strFolderPath为全局变量,在这个消息函数中被赋值,子函数调用结束,这个赋值还是有效的,就会带入主界面中:
//生成word
void C海上目标检测跟踪Dlg::OnBnClickedCreateDoCument()
{
	// TODO:  在此添加控件通知处理程序代码
	//CString strExePath, strExePath2; 老狗的代码
	//CString strPath;
	//GetModuleFileName(NULL, strPath.GetBufferSetLength(MAX_PATH + 1), MAX_PATH + 1);
	//int nPos = strPath.ReverseFind(_T('\\'));
	//strExePath = strPath.Left(nPos + 1);		  
	//strExePath2 = strExePath + _T("template.dot");
	//MessageBox(strExePath);//显示debug所在路径
	//MessageBox(strExePath2);//显示获取的指向.dot模板路径

	//MFC获取程序目录相对路径,小心文件是放在项目外面的x64-Debug里面  自己写的
	CString path;
	GetModuleFileName(NULL, path.GetBufferSetLength(MAX_PATH + 1), MAX_PATH);
	path.ReleaseBuffer();
	int pos = path.ReverseFind('\\');
	path = path.Left(pos);
	path = path + _T("\\template2.dot");
	//MessageBox(path);
	COleVariant    covZero((short)0),
		covTrue((short)TRUE),
		covFalse((short)FALSE),
		covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR),
		covDocxType((short)0),
		start_line, end_line,
		dot(path);
		//dot(_T("F:\\template2.dot"));
	CApplication wordApp;
	CDocuments docs;
	CDocument0 docx;
	CBookmarks bookmarks;
	CBookmark0 bookmark;
	CRange range;
	CCell cell;
	if (!wordApp.CreateDispatch(_T("Word.Application")))
	{
		AfxMessageBox(_T("本机没有安装word产品!"));
		return;
	}

	wordApp.put_Visible(FALSE);
	CString wordVersion = wordApp.get_Version();
	docs = wordApp.get_Documents();
	docx = docs.Add(dot, covOptional, covOptional, covOptional);
	bookmarks = docx.get_Bookmarks();

	bookmark = bookmarks.Item(&_variant_t(_T("标题1")));
	range = bookmark.get_Range();
	range.put_Text(_T("这是标题1"));

	bookmark = bookmarks.Item(&_variant_t(_T("标题2")));
	range = bookmark.get_Range();
	range.put_Text(_T("这是标题2"));

	bookmark = bookmarks.Item(&_variant_t(_T("序号1")));
	range = bookmark.get_Range();
	range.put_Text(_T("1"));

	bookmark = bookmarks.Item(&_variant_t(_T("姓名1")));
	range = bookmark.get_Range();
	range.put_Text(_T("王二小"));

	bookmark = bookmarks.Item(&_variant_t(_T("年龄1")));
	range = bookmark.get_Range();
	range.put_Text(_T("10"));

	//把生成的word报告保存到指定路径
	//CString strSavePath = _T("C:");
	//strSavePath += _T("\\test.docx");
	//docx.SaveAs(COleVariant(strSavePath), covOptional, covOptional, covOptional, covOptional,
	//	covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);

	//把生成的word报告保存到用户想要的指定路径//VARIANT* FileName, 文档保存路径	//    covOptional,  //文档的保存格式
	//创建一个选择文件夹的对话框,返回所选路径  
	//TCHAR           szFolderPath[MAX_PATH] = { 0 };
	//CString         strFolderPath = TEXT("");

	//BROWSEINFO      sInfo;
	//::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
	//sInfo.pidlRoot = 0;
	//sInfo.lpszTitle = _T("请选择一个文件夹保存文档:");
	//sInfo.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX;
	//sInfo.lpfn = NULL;

	//// 显示文件夹选择对话框  
	//LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&sInfo);
	//if (NULL == lpidlBrowse)
	//{
	//	AfxMessageBox("没有选择路径,请重新选择!");
	//	while (!lpidlBrowse)
	//	{
	//		// 重新显示文件夹选择对话框
	//		lpidlBrowse = ::SHBrowseForFolder(&sInfo);
	//		// 重新取得文件夹名  
	//		if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
	//		{
	//			strFolderPath = szFolderPath;
	//			
	//		}
	//	}
	//}
	//else
	//{
	//	//取得文件夹名
	//	if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
	//	{
	//		strFolderPath = szFolderPath;
	//	}
	//}
	////释放资源
	//if (lpidlBrowse != NULL)
	//{
	//	::CoTaskMemFree(lpidlBrowse);
	//}

	//获取时间戳
	CTime currTime;
	currTime = CTime::GetCurrentTime();
	CString strTime;
	strTime.Format(_T("%.4d-%.2d-%.2d-%.2d-%.2d-%.2d"), currTime.GetYear(), currTime.GetMonth(), currTime.GetDay(), currTime.GetHour(), currTime.GetMinute(), currTime.GetSecond());
	CString strSavePath;
	strSavePath = strFolderPath + "\\"+ strTime + _T(".docx");
	docx.SaveAs(COleVariant(strSavePath), covOptional, covOptional, covOptional, covOptional,
		covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);


	// 退出word应用
	docx.Close(covFalse, covOptional, covOptional);
	wordApp.Quit(covOptional, covOptional, covOptional);
	range.ReleaseDispatch();
	bookmarks.ReleaseDispatch();
	wordApp.ReleaseDispatch();

	AfxMessageBox(_T("test.docx生成成功!"));
}

在主界面c..Dlg.cpp中添加全局变量头文件,会发现全局变量strFolderPath变量,会使用到子界面里赋值后的数据。

印证这个思路:我们通过调试,设置断点

先点击运行到第一步,在点击运行到选入路径,并且为strFolderPath添加“监视”,可以看到全局变量strFolderPath在子界面中确实赋值了,然后我们利用主程序中定时器,在那里设置断点,观察运行到主程序中,strFolderPath会不会发生改变

会发现“监视”的全局变量,没有发生改变,确实实现了主子界面的数据传输

2.解决当我点开子界面,选择好路径以后,查掉子界面的右上角关闭按钮,再次打开,发现之前选好的路径编辑框选好的信息,不复存在,解决办法是:在子界面的初始化程序中,添加如下代码:

	//"文档保存位置"下的编辑框,能实时更新路径信息,并且不丢失上次使用痕迹
	SetDlgItemText(IDC_FileNameEdit, strFolderPath);
	UpdateData(FALSE);
但是,改变了编辑框的内容并不会自动更新对应的变量的值,同样,改变了变量的值也不会自动刷新编辑框的内容。若要保持一致,需要使用UpdateData()函数更新:
若编辑框的内容改变了,则应使用语句UpdateData(TRUE) 获取对话框数据

若变量的值改变了,则应使用语句UpdateData(FALSE) 初始化对话框控件

3.在x64编译环境下,多字符集下,实现全屏截图,对话框截图,或者某个窗口特定部分截图,读下列博客:

MFC下截取窗口特定部分并保存为图片  MFC怎么截取指定区域的图像思路     CImage类   MFC 获取指定窗口截图(大小可调)

//截全屏 或者截对话框 源代码
void C截图功能Dlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	CClientDC dc(this);//只截对话框,用这句
	//HWND hwnd = ::GetDesktopWindow();//截整个屏幕,用从这往下4句
	//HDC hdc = ::GetDC(hwnd);
	//CDC dc;
	//dc.Attach(hdc);
	CRect rc;
	GetClientRect(&rc);//只截对话框,用这句
	//rc.SetRect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));//截整个屏幕,用这句
	int iBitPerPixel = dc.GetDeviceCaps(BITSPIXEL);
	int iWidth = rc.Width();
	int iHeight = rc.Height();
	CDC memDC;
	memDC.CreateCompatibleDC(&dc);

	CBitmap memBitmap, *oldBitmap; // 建立和屏幕兼容的bitmap

	memBitmap.CreateCompatibleBitmap(&dc, iWidth, iHeight);
	oldBitmap = memDC.SelectObject(&memBitmap);//将memBitmap选入内存DC

	memDC.BitBlt(0, 0, iWidth, iHeight, &dc, 0, 0, SRCCOPY); // 调解高度宽度

	BITMAP bmp;
	memBitmap.GetBitmap(&bmp);// 获得位图信息 

	FILE *fp = fopen("test3.bmp", "wb");
	BITMAPINFOHEADER bih;
	memset(&bih, 0, sizeof(bih));  // 位图信息头
	bih.biBitCount = bmp.bmBitsPixel;
	bih.biCompression = BI_RGB;//表示不压缩
	bih.biHeight = bmp.bmHeight;
	bih.biPlanes = 1;//位平面数,必须为1
	bih.biSize = sizeof(BITMAPINFOHEADER);
	bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;
	bih.biWidth = bmp.bmWidth;
	BITMAPFILEHEADER bfh;
	memset(&bfh, 0, sizeof(bfh));
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // 到位图数据的偏移量

	bfh.bfSize = bfh.bfOffBits + bmp.bmWidthBytes * bmp.bmHeight;// 文件总的大小
	bfh.bfType = (WORD)0x4d42;//必须表示"BM"

	fwrite(&bfh, 1, sizeof(BITMAPFILEHEADER), fp);//写入位图文件头
	fwrite(&bih, 1, sizeof(bih), fp);//写入位图信息头

	byte * p = new byte[bmp.bmWidthBytes * bmp.bmHeight];//申请内存保存位图数据
	GetDIBits(memDC.m_hDC, (HBITMAP)memBitmap.m_hObject, 0, iHeight, p, (LPBITMAPINFO)&bih, DIB_RGB_COLORS);//获取位图数据
	fwrite(p, 1, bmp.bmWidthBytes * bmp.bmHeight, fp);//写入位图数据
	delete[] p;

	fclose(fp);

	memDC.SelectObject(oldBitmap);
}
//实时截图picture控件显示的图片
void C海上目标检测跟踪Dlg::OnBnClickedSavepicture()
{
	// TODO:  在此添加控件通知处理程序代码
	CRect rcPlot;
	GetDlgItem(IDC_VIDEO)->GetWindowRect(&rcPlot); //获取IDC_VIEW在整个屏幕中的像素位置  
	ScreenToClient(&rcPlot);//获取IDC_VIEW在父窗口中的位置  

	HDC hDC = ::GetWindowDC(GetDlgItem(IDC_VIDEO)->GetSafeHwnd());
	HDC hDCMem = ::CreateCompatibleDC(hDC);// 建立和屏幕兼容的bitmap   

	HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rcPlot.Width(), rcPlot.Height());
	HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hDCMem, hBitmap);////将memBitmap选入内存DC   

	::BitBlt(hDCMem, 0, 0, rcPlot.Width(), rcPlot.Height(), hDC, 0, 0, SRCCOPY);// 调解高度宽度   
	::SelectObject(hDCMem, hOldBitmap);
//CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,而且这些文件格式可以相互转换
	ATL::CImage image;//当这里CImage不明确时候,前面添加ATL::就好
	image.Attach(hBitmap); //将位图加入图片表中  

	CString strFilter = _T("位图文件(*.bmp)|*.bmp|JPEG 图像文件|*.jpg|GIF 图像文件|*.gif|PNG 图像文件|*.png||");
	CFileDialog dlg(false, _T("bmp"), _T("曲线.bmp"), NULL, strFilter);
	if (IDOK == dlg.DoModal())
	{
		image.Save(dlg.GetPathName());
	}
}

IDC_VIDEO-可以是Picture控件,这样就能实现实时截picture控件中的图片  其中需要在C..Dlg.cpp文件中添加头文件:
//多字符集下使用CImage类处理图片 需要包含#include <atlimage.h>头文件
#include <atlimage.h>

4.需要实现能实时截图picture控件中的图片,这就需要能生成多个图片文件,等于拥有无数个文件名===一般采用时间戳来做文件名,这样就不会发生重名现象,与此同时运用之前的经验,能显示文件选择框,来选择文件位置

//实时截图picture控件显示的图片
void C海上目标检测跟踪Dlg::OnBnClickedSavepicture()
{
	// TODO:  在此添加控件通知处理程序代码
	CRect rcPlot;
	GetDlgItem(IDC_VIDEO)->GetWindowRect(&rcPlot); //获取IDC_VIEW在整个屏幕中的像素位置  
	ScreenToClient(&rcPlot);//获取IDC_VIEW在父窗口中的位置  

	HDC hDC = ::GetWindowDC(GetDlgItem(IDC_VIDEO)->GetSafeHwnd());
	HDC hDCMem = ::CreateCompatibleDC(hDC);// 建立和屏幕兼容的bitmap   

	HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rcPlot.Width(), rcPlot.Height());
	HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hDCMem, hBitmap);////将memBitmap选入内存DC   

	::BitBlt(hDCMem, 0, 0, rcPlot.Width(), rcPlot.Height(), hDC, 0, 0, SRCCOPY);// 调解高度宽度   
	::SelectObject(hDCMem, hOldBitmap);
//CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,而且这些文件格式可以相互转换
	ATL::CImage image;//当这里CImage不明确时候,前面添加ATL::就好
	image.Attach(hBitmap); //将位图加入图片表中  

	//创建一个选择文件夹的对话框,返回所选路径  
	//TCHAR           szFolderPath[MAX_PATH] = { 0 };
	////CString         strFolderPath_Picture = TEXT("");变成全局变量

	//BROWSEINFO      sInfo;
	//::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
	//sInfo.pidlRoot = 0;
	//sInfo.lpszTitle = _T("请选择一个文件夹保存截图:");
	//sInfo.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX;
	//sInfo.lpfn = NULL;

	//// 显示文件夹选择对话框  
	//LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&sInfo);
	//if (NULL == lpidlBrowse)
	//{
	//	AfxMessageBox("没有选择路径,请重新选择!");
	//	while (!lpidlBrowse)
	//	{
	//		// 重新显示文件夹选择对话框
	//		lpidlBrowse = ::SHBrowseForFolder(&sInfo);
	//		// 重新取得文件夹名  
	//		if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
	//		{
	//			strFolderPath_Picture = szFolderPath;
	//			
	//		}
	//	}
	//}
	//else
	//{
	//	//取得文件夹名
	//	if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
	//	{
	//		strFolderPath_Picture = szFolderPath;
	//	}
	//}
	////释放资源
	//if (lpidlBrowse != NULL)
	//{
	//	::CoTaskMemFree(lpidlBrowse);
	//}
		
	//获取时间戳
	CTime currTime;
	currTime = CTime::GetCurrentTime();
	CString strTime;
	strTime.Format(_T("%.4d-%.2d-%.2d-%.2d-%.2d-%.2d"), currTime.GetYear(), currTime.GetMonth(), currTime.GetDay(), currTime.GetHour(), currTime.GetMinute(), currTime.GetSecond());
	CString strSavePath;
	strSavePath = strFolderPath_Picture + "\\" + strTime + _T(".bmp");
	image.Save(strSavePath);

	AfxMessageBox(_T("截图成功!"));
}

但是需要,与子界面中的“截图保存”按钮与“截图显示路径”编辑框发生数据交互,这就需要定义全局变量,来实时传送,并且需要他保留上次使用痕迹,于是在两处分别添加如下代码:

//对Picture控件 实时截图保存
void InputMenu::OnBnClickedSavepicture()
{
	// TODO:  在此添加控件通知处理程序代码
	//创建一个选择文件夹的对话框,返回所选路径  
	TCHAR           szFolderPath[MAX_PATH] = { 0 };
	//CString         strFolderPath_Picture = TEXT("");变成全局变量

	BROWSEINFO      sInfo;
	::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
	sInfo.pidlRoot = 0;
	sInfo.lpszTitle = _T("请选择一个文件夹保存截图:");
	sInfo.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX;
	sInfo.lpfn = NULL;

	// 显示文件夹选择对话框  
	LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&sInfo);
	if (NULL == lpidlBrowse)
	{
		AfxMessageBox("没有选择路径,请重新选择!");
		while (!lpidlBrowse)
		{
			// 重新显示文件夹选择对话框
			lpidlBrowse = ::SHBrowseForFolder(&sInfo);
			// 重新取得文件夹名  
			if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
			{
				strFolderPath_Picture = szFolderPath;
				SetDlgItemText(IDC_FileName_Picture, strFolderPath_Picture);
				//IDC_FileName_Picture-截图保存显示路径的编辑框
				//若变量的值改变了,则应使用语句UpdateData(FALSE) 初始化对话框控件
				UpdateData(FALSE);
			}
		}
	}
	else
	{
		//取得文件夹名
		if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
		{
			strFolderPath_Picture = szFolderPath;
			SetDlgItemText(IDC_FileName_Picture, strFolderPath_Picture);
			//若变量的值改变了,则应使用语句UpdateData(FALSE) 初始化对话框控件
			UpdateData(FALSE);
		}
	}
	//释放资源
	if (lpidlBrowse != NULL)
	{
		::CoTaskMemFree(lpidlBrowse);
	}
}
	//"截图保存位置"下的编辑框,能实时更新路径信息,并且不丢失上次使用痕迹
	SetDlgItemText(IDC_FileName_Picture, strFolderPath_Picture);
	UpdateData(FALSE);
思考:但是完成上述功能后,发现,当我开始未在子界面中进行选择路径时候,我去点击“生成报告”按钮,以及“保存截图”按钮,他也是生成的,只不过这个东西,不知道去了哪里,应该是了默认的一个地方,这个可能涉及逻辑方面,怎么让用户在未进行子界面输入输出设置,不能去点击这里按钮呢?这个是一个问题

5.解决了函数中一个整型变量,能显示到编辑框中

方法:第一步,需要在OnInitDialog()主函数中,初始化数据,让编辑框开始显示为0


同时需要注意:itoa函数的第三个参数表示转换的进制,数字10代表十进制

但是在有些编译器下会报错,故采用_itoa_s形式,替换过来就好

第二步:需要定义一个全局变量:

同时参照相关博客,一句代码获得整个视频文件的总帧数:用opencv查看视频信息(视频的宽度、高度、帧率和总得帧数)


第三步:在定时器中添加如下代码:特别小心

UpdateData(FALSE);不能乱用,想这里就是完全不需要这句话,然后需要把帧数变化写在当前系统时间显示上面,以免后面还需要添加一些程序
//从C海上目标检测跟踪Dlg属性中添加消息响应函数
//时间定时器
void C海上目标检测跟踪Dlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	//因为随着时间进行,我可能会选择不同视频文件进来
	//UpdateData(FALSE); 变量内容 同步到控件中   这里是不需要这句话
	//原因:UpdateData(FALSE);同步的是关联的变量,而这里我的全局变量TotalNumberflg1,随着不同视频文件进来,而且是全局变量,自己会更新的
	char temp[10];
	_itoa_s(TotalNumberflg1, temp, 10);
	SetDlgItemText(IDC_CountPicture, temp);
	//UpdateData(FALSE);

	CDialog::OnTimer(nIDEvent);
	CString str;
	CTime   theTime = CTime::GetCurrentTime();
	str.Format(_T("%02d:%02d:%02d"), theTime.GetHour(), theTime.GetMinute(), theTime.GetSecond());
	SetDlgItemText(IDC_EDIT_TIME, str);


}

6.在程序中添加多个定时器,参照博客:MFC中使用多个timer定时器    SetTimer函数的用法

	//显示当前系统时间
	SetTimer(1, 1000, NULL);//1000毫秒发生一次定时器事件

什么时候我们需要用到SetTimer函数呢?当你需要每个一段时间执行一件事的的时候就需要使用SetTimer函数 了。使用定时器的方法比较简单,通常告诉WINDOWS一个时间间隔,然后WINDOWS以此时间间隔周期性触发程序。通常有两种方法来实现:发送WM_TIMER消息和调用应用程序定义的回调函数。  

1.1 用WM_TIMER来设置定时器 

先请看SetTimer这个API函数的原型  

UINT_PTR SetTimer(
  HWND hWnd,          // 窗口句柄
  UINT_PTR nIDEvent,      // 定时器ID,多个定时器时,可以通过该ID判断是哪个定时器
  UINT uElapse,         // 时间间隔,单位为毫秒
  TIMERPROC lpTimerFunc     // 回调函数
);

例如  
SetTimer(m_hWnd,1,1000,NULL); //一个1秒触发一次的定时器
在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了

于是SetTimer函数的原型变为:  

UINT SetTimer(

  UINT nIDEvent,

  UINT nElapse,

  void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD)

)  

 当使用SetTimer函数的时候,就会生成一个计时器。函数中nIDEvent指的是计时器的标识 ,也就是名字。nElapse指的是时间间隔 ,也就是每隔多长时间触发一次事件。第三个参数是一个回调函数 ,在这个函数里,放入你想要做的事情的代码,你可以将它设定为NULL,也就是使用系统默认的回调函数,系统默认认的是onTime函数。 这个函数怎么生成的呢?你需要在需要计时器的类的生成onTime函数:在ClassWizard里,选择需要计时器的类,添加WM_TIME消息映射,就自动生成onTime函数了 。然后在函数里添加代码,让代码实现功能。每隔一段时间就会自动执行一次。  

例:  

SetTimer(1,1000,NULL);  

1:计时器的标识; 

1000:时间间隔,单位是毫秒;  

NULL:使用onTime函数。  

当不需要计时器的时候调用KillTimer(nIDEvent);   

例如:KillTimer(1);  

1.2 调用回调函数 

此方法首先写一个如下格式的回调函数(在SetTimer函数表示回调函数TIMERPROC不为空时,需要调用自定义的回调函数 ) 

void CALLBACK TimerProc(

  HWND hWnd,

  UINT uMsg,

  UINT idEvent,

  DWORD dwTime

);
然后再用SetTimer(1,100,TimerProc)函数来建一个定时器,第三个参数就是回调函数地址。

如果要加入两个或者两个以上的timer怎么办?   

继续用SetTimer函数吧,上次的timer的ID是1,这次可以是2,3,4。。。。  

SetTimer(2,1000,NULL);  

SetTimer(3,500,NULL);  

嗯,WINDOWS会协调他们的。当然onTimer函数体也要发生变化,要在函数体内添加每一个timer的处理代码:  

onTimer(nIDEvent)  

{  

switch(nIDEvent)  

{  

case 1:..;  

 break;  

case 2:..;  

 break;  

case 3:..;  

 break;  

}  

}

 

在使用定时器时注意SetTimer中表示定义时标识的nIDEvent参数,以及OnTimer或自定义的回调函数中nIDEvent参数,还有KillTimer中的这个参数,如果要用它们对特定的定时器进行操作时,注意保持它们的一致。

一般非类里函数里都会有指向窗口的指针,设置定时器,SetTimer写位置不在被封装在CWnd类中,我们就需要添加句柄

//指向窗口的指针pThis
C海上目标检测跟踪Dlg* pThis = (C海上目标检测跟踪Dlg*)lpParam;

    		//pThis->m_hWnd窗口句柄
		SetTimer(pThis->m_hWnd, N_TIMER_SEC, N_TIME_SEC, NULL);//1000毫秒发生一次定时器事件
		SetTimer(pThis->m_hWnd, N_TIMER_SHOW, N_TIME_SHOW, NULL);//1000毫秒发生一次定时器事件
		/*
		SetTimer(
    _In_opt_ HWND hWnd,//窗口句柄
    _In_ UINT_PTR nIDEvent,//指定了不为零的定时器标识符。
    _In_ UINT uElapse,//指定了定时值;以毫秒为单位。
    _In_opt_ TIMERPROC lpTimerFunc);//指定了应用程序提供的TimerProc回调函数的地址,该函数被用于处理WM_TIMER消息。
                                    //如果这个参数为NULL,则WM_TIMER消息被放入应用程序的消息队列并由CWnd对象来处理。
		*/
//时间定时器
void C海上目标检测跟踪Dlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	switch (nIDEvent)
	{
		case 1:
		{
			//因为随着时间进行,我可能会选择不同视频文件进来
			//UpdateData(FALSE); 变量内容 同步到控件中   这里是不需要这句话
			//原因:UpdateData(FALSE);同步的是关联的变量,而这里我的全局变量TotalNumberflg1,随着不同视频文件进来,而且是全局变量,自己会更新的
			char temp[10];
			_itoa_s(TotalNumberflg1, temp, 10);
			SetDlgItemText(IDC_CountPicture, temp);
			//UpdateData(FALSE);
			CString str;
			CTime   theTime = CTime::GetCurrentTime();
			str.Format(_T("%02d:%02d:%02d"), theTime.GetHour(), theTime.GetMinute(), theTime.GetSecond());
			SetDlgItemText(IDC_EDIT_TIME, str);
		}   
			break;
		case 2:
		{
			n_second++;
			if (n_second == 60)
			{
				n_second = 0;
				n_minute++;
			}
		}
		case 3:
		{
			int  m1, m2, s1, s2;
			m1 = n_minute / 10;
			m2 = n_minute % 10;
			s1 = n_second / 10;
			s2 = n_second % 10;
			CString m_TimePicture;
			m_TimePicture.Format(_T("%d%d:%d%d"), m1, m2, s1, s2);
			SetDlgItemText(IDC_TimePicture, m_TimePicture);
			UpdateData(FALSE);
		}		
			break;
	}	
	CDialog::OnTimer(nIDEvent);

}

在进程里,添加如上程序,同时在切换为"结束"按钮时候,还需要进行归零,同时进行销毁定时器



同时数字,需要宏定义,并且注释好,方便以后,更改


但是这么做会发现,视频播放结束后,仍然会继续计时间,这是我们所不希望的,我们希望播放结束后,计时随之停止



7.设置LVS_EX_CHECKBOXES风格 

    ListView_SetExtendedListViewStyle(m_List.GetSafeHwnd(), m_List.GetExStyle() | LVS_EX_CHECKBOXES);

//MFC中的List控件只能在第一列加自带的Checkbox。
//如果想在其它列加Checkbox,就只能自己描画了
m_list.GetCheck(0);//m_list为列表框关联的变量

m_list.SetCheck(1, TRUE);



8.如何从CListCtrl派生一个新类比如CMyCtrl

比较直接的方法是选择MFC class,派生类选择CListCtrl或CWnd,然后在生成的文件中把基类修改为你的基类,包括类的定义,和消息映射.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值