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变量,会使用到子界面里赋值后的数据。
印证这个思路:我们通过调试,设置断点


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,然后在生成的文件中把基类修改为你的基类,包括类的定义,和消息映射.