1、MFC主窗口调用子窗口显示问题
①主窗口显示问题可以在init初始化函数中
②子窗口显示问题可以利用消息事件PAINT来进行初始化(可以添加一个成员变量flag,让消息事件只执行一次)
2、线程的创建、打开文件、显示图片
①一个窗口都会有一个.h和一个.cpp文件
②在头文件中添加
//类中成员函数 CWinThread* pThread; //创建线程对象, //类外 struct threadInfo //线程执行参数 { CDC *pDC; CRect rect; }; UINT PlayVideo(LPVOID lpParam); //线程执行函数
③在源程序中添加(IDC_VideoFrame是控件的ID)
threadInfo Info; //结构体变量 Info.pDC = GetDlgItem(IDC_VideoFrame)->GetDC();//保存根据ID获得窗口指针再获取与该窗口关联的上下文指针 GetDlgItem(IDC_VideoFrame)->GetClientRect(&Info.rect); //获得控件窗口大小 pThread = AfxBeginThread(PlayVideo, &Info);//启动线程
UINT PlayVideo(LPVOID lpParam) { threadInfo* pInfo = (threadInfo*)lpParam; HDC hdc = pInfo->pDC->GetSafeHdc();// 获取设备上下文句柄 CString csFilter = "AVI Files(*.AVI)|*.AVI||"; CFileDialog FileDlg(true, NULL, NULL, OFN_HIDEREADONLY, csFilter); if (FileDlg.DoModal() == IDOK) {// 选择了文件名 bIsRunning = true; strFileName = FileDlg.m_ofn.lpstrFile; if (FileDlg.m_ofn.nFileExtension == 0) { // 无文件后缀 strFileName = strFileName + ".avi";// 加文件后缀 } CvCapture *capture = cvCreateFileCapture(strFileName); //函数给指定文件中的视频流分配和初始化CvCapture结构。 double fps = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); //获得摄像头或者视频文件的指定属性。 vfps = 1000 / fps; //计算每帧播放的时间 int countframe = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT); m_ctrlSlider.SetRange(0, countframe); //初始化滑块范围 m_ctrlSlider.SetPos(0); //初始化滑块位置 CvvImage cimg; while (bIsRunning) { m_ctrlSlider.SetPos(num); if (num <= countframe - 2) { cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, num); frame = cvQueryFrame(capture); //从摄像头或者文件中抓取一帧,然后解压并返回这一帧 //if (!frame)break; cimg.CopyOf(frame, frame->nChannels);//从img复制图像到当前的对象中 cimg.DrawToHDC(hdc, &pInfo->rect); Sleep(vfps - 25); num++; while (flag == 1){ } } else{ num = 0; m_ctrlSlider.SetPos(0); } } cvReleaseCapture(&capture);//释放由cvCaptureFromFile 或者cvCaptureFromCAM申请的CvCapture结构。 } else{ // 没有选择文件 strFileName = "../video.png";// 显示一张警告图片 IplImage *image = cvLoadImage(strFileName); CvvImage cimg; cimg.CopyOf(image, image->nChannels); cimg.DrawToHDC(hdc, &pInfo->rect); } return 0; }④滑块的使用,我在以前的博客上写过
⑤线程创建,不一定要建立结构体存储和创建一个函数。也可以定义两个变量即可,如显示一张图片
CDC *pDC; CRect rect; pDC = GetDlgItem(IDC_ImgShow)->GetDC();//保存根据ID获得窗口指针再获取与该窗口关联的上下文指针 GetDlgItem(IDC_ImgShow)->GetClientRect(&rect); //获得picture控件窗口大小 HDC hdc = pDC->GetSafeHdc();// 获取设备上下文句柄 CvvImage cimgg; IplImage *image = cvLoadImage(address); cimgg.CopyOf(image, image->nChannels); cimgg.DrawToHDC(hdc, &rect);
3、选择保存路径
BROWSEINFO bi; bi.hwndOwner = NULL; bi.pidlRoot = NULL; bi.pszDisplayName = NULL; bi.lpszTitle = NULL; bi.ulFlags = 0; bi.lpfn = NULL; bi.iImage = 0; LPCITEMIDLIST pidl = SHBrowseForFolder(&bi); if (!pidl) return; TCHAR szDisplayName[255]; SHGetPathFromIDList(pidl, szDisplayName); CString path(szDisplayName); //路径path下,创建一个目录 str = ((LPCTSTR)strFileNameAuto); int position = str.find_last_of("\\"); string spiltName = str.substr(position + 1, str.length() - position - 1); string s = "\\"; concatNameAuto = (LPCTSTR)path + s + spiltName; reportPathAuto = concatNameAuto; if (_access(concatNameAuto.c_str(), 0) == 0){ //如果文件存在,返回0,不存在,返回-1。 myDeleteDirectory(concatNameAuto); } CreateDirectory(concatNameAuto.data(), 0);//不存在则创建
void myDeleteDirectory(string directory_path) //删除一个文件夹下的图片,嵌套文件夹不行 { try { __finddata64_t file; intptr_t handle = _findfirst64(string(directory_path + "\\*").data(), &file); if (handle == -1) {} else { do { //file.attrib用于表示文件的属性,_A_SUBDIR表示子文件夹 if (file.attrib == _A_SUBDIR) { //文件名为. or .. if (string(file.name).compare(".") == 0 || string(file.name).compare("..") ==0) { continue; //查找下一个文件名 } else{} } //用来检索子串在字符串中首次出现的位置 else if (strstr(file.name, ".bmp") || strstr(file.name, ".BMP") || strstr(file.name, ".JPG") || strstr(file.name, ".jpg")) { string abc = directory_path + "/" + file.name; DeleteFile(abc.c_str()); } }while((_findnext64(handle, &file) == 0)); } RemoveDirectory(directory_path.c_str()); _findclose(handle); } catch (exception& e) {} }
4、复选框的使用
①复选框的使用很简单,就是一个简单的标记,若单击或者选中的时候进行标记即可。
②复选框圆圈和正方形的区别是,前者只能单选,后者可以多选。
5、下拉框的使用
①为Conbobox添加变量
②是通过右键控件添加变量(m_chosecom)
③初始化
//主界面时,在init中下 //子界面时,在PAINT消息函数中写 m_chosecom.AddString("hello"); m_chosecom.AddString("world");④控件函数中可以判断选择的值(先获取id,再获取str)
CString str; int nSel = m_chosecom.GetCurSel(); m_chosecom.GetLBText(nSel, str);
6、编辑框的使用
CEdit* pBoxOne;
pBoxOne = (CEdit*)GetDlgItem(IDC_EDIT1); //ID
pBoxOne->SetWindowText("hello world"); //赋值
7、按钮的显示和隐藏
GetDlgItem(IDC_BUTTON1)->ShowWindow(SW_HIDE); GetDlgItem(IDC_BUTTON1)->ShowWindow(SW_SHOW);
8、String和CString的区别及转换
①一个头文件是《iostream》
②一个头文件是《afx.h》
strs.c_str()、_T()、LPCTSTR可以实现转化
9、视频流的截取
①ffmpeg下载地址:https://ffmpeg.zeranoe.com/builds/
②包含三个版本,都需要下载,Static提供exe,Shared提供dll和exe 、Dev提供include
③Static和Shared二选一即可(一个是完全封装成exe,一个是不完全封装,一般选择Static即可)
④创建工程,配置环境(配置库include、配置链接库lib,都是dev提供)
⑤调节字符编码
⑥ffmpeg.exe拷贝到运行目录下(源码所在目录,要么使用Static中exe,要么使用Shared中的dll和exe)
Static和Shared中都有ffmpeg.exe但是大小不一样,前者大一些。要么直接使用Static中的exe,要么把Shared中的dll和exe都拷贝到源码相当路径下。
⑦源码
vector<string> vecShowPic; //保持在一个位置 string str ="..\\test.avi"; string path = "..\\pic"; //pic文件夹必须事先创建好 vecShowPic.clear(); string ass = "ffmpeg.exe -i " + str + " -f image2 -an -r 0.1 " + path + "/image%03d.jpg "; system(ass.c_str()); //抽帧结束 //读取路径,放在vector中 CFileFind cf; CString filePath; CString fileName; path += "\\"; path += "*.*"; BOOL res = cf.FindFile(path.c_str()); while (res) { res = cf.FindNextFileA(); filePath = cf.GetFilePath(); fileName = cf.GetFileName(); if (!cf.IsDirectory() && !cf.IsDots()) { if (fileName.Right(3) == "jpg"){ vecShowPic.push_back((LPCTSTR)filePath); } } } cf.Close();