zoukankan      html  css  js  c++  java
  • 【2012年终总结】之一 opencv + ds采集摄像头视频 MFC点点滴滴

    1、MFC单文档多文档程序 不让MFC来更新菜单

    1 在CMainFrame::CMainFrame中添加
    2 
    3 m_bAutoMenuEnable = FALSE;

    标题栏图标的更改

    1 //cuihao, 标题栏图标;
    2 CCameraMonitorApp *pApp = (CCameraMonitorApp*)AfxGetApp();
    3 HICON hIcon = pApp->LoadIcon(IDI_ICON3);
    4 SetIcon(hIcon, TRUE);
    5 SetIcon(hIcon, FALSE);

     ------------------------------------------------------------------------------------------------------------------------

    使菜单可用/不可用, 通过菜单项的位置来让菜单可用或不可用

    1 GetMenu()->GetSubMenu(2)->EnableMenuItem(1, MF_BYPOSITION | MF_GRAYED | MF_DISABLED);
    2 
    3 GetMenu()->GetSubMenu(3)->EnableMenuItem(2, MF_BYPOSITION | MF_ENABLED);

    更改菜单项的Caption或者ID

    如果只想要修改菜单的文字则ID要和原来的一样,原来的菜单ID也为ID_OF_MENUITEM, 修改后的caption为strNewStringCaption

    1 GetMenu()->GetSubMenu(1)->ModifyMenu(2, MF_BYPOSITION | MF_STRING, ID_OF_MENUITEM, strNewStringCaption);

      ------------------------------------------------------------------------------------------------------------------------

     修改MFC单文档多文档的窗口标题栏

     1 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
     2 {
     3 if( !CFrameWnd::PreCreateWindow(cs) )
     4 return FALSE;
     5 // TODO: 在此处通过修改
     6 //cuihao, CREATESTRUCT cs 来修改窗口类或样式
     7 cs.style &= ~FWS_ADDTOTITLE;
     8 cs.lpszName = _T("视频监控"); 
     9 
    10 return TRUE;
    11 }
    12 
    13  

    MFC单文档多文档,让程序一开始最大化运行

    1 void CMainFrame::ActivateFrame(int nCmdShow)
    2 {
    3 // TODO: 在此添加专用代码和/或调用基类;
    4 
    5 nCmdShow = SW_SHOWMAXIMIZED; //cuihao,最大化运行;
    6 
    7 CFrameWnd::ActivateFrame(nCmdShow);
    8 }

      ------------------------------------------------------------------------------------------------------------------------

     如果MFC文档有多个view类,那么获取当前有焦点的view类

    1 CView* CFrameWnd::GetActiveView( ) const;

    如果要获取指定的view类的指针,那么可以:先获得该view类的句柄,然后通过句柄获得指针

    1 CWnd* FromHandle(HWND hWnd);

    如果要遍历所有view类,如下

    1 virtual POSITION GetFirstViewPosition() const;
    2 virtual CView* GetNextView(POSITION& rPosition) const;

      ------------------------------------------------------------------------------------------------------------------------

     改变窗口的位置、大小,Z序

    SetWindowPos

    eg.  

    //最大化视频;

     1 void CMainFrame::OnMenuMaxvideo()
     2 {
     3 // TODO: 在此添加命令处理程序代码;
     4 
     5 static bool bModify[MAX_CAMERAS_NUM] = {false};
     6 
     7 int nCode = CCameraMonitorView::m_nCurrentCode; 
     8 
     9 CCameraMonitorView* pView = NULL; 
    10 pView = (CCameraMonitorView*)FromHandle(CCameraMonitorView::m_hWndCameraMonitor);
    11 if (NULL == pView)
    12 {
    13 AfxMessageBox(_T("pView is NULL, CMainFrame::OnMenuMaxvideo"));
    14 return;
    15 }
    16 
    17 //最大化;
    18 if (false == bModify[nCode])
    19 { 
    20 CRect rectMax;
    21 pView->GetWindowRect(&rectMax);
    22 int x = rectMax.TopLeft().x;
    23 int y = rectMax.TopLeft().y;
    24 int cx = rectMax.Width();
    25 int cy = rectMax.Height();
    26 BOOL ret = pView->GetDlgItem(videoPicturesCtrl[nCode])->SetWindowPos(&wndTopMost, 0, 0, cx, cy, SWP_SHOWWINDOW |SWP_NOZORDER);
    27 
    28 HideAllNonActiveWindows(nCode, true); //隐藏其他视频窗口,如果不隐藏则最大化视频显示时其他视频窗口会被刷出来,很难看;
    29 
    30 }
    31 
    32 //还原;
    33 else
    34 {
    35 int x = CCameraMonitorView::m_rectVideos[nCode].left;
    36 int y = CCameraMonitorView::m_rectVideos[nCode].top;
    37 int cx = CCameraMonitorView::m_rectVideos[nCode].Width();
    38 int cy = CCameraMonitorView::m_rectVideos[nCode].Height();
    39 BOOL ret = pView->GetDlgItem(videoPicturesCtrl[nCode])->SetWindowPos(NULL, x, y, cx, cy, SWP_NOZORDER | SWP_SHOWWINDOW);
    40 
    41 HideAllNonActiveWindows(nCode, false);
    42 }
    43 
    44 bModify[nCode] = !bModify[nCode]; 
    45 Invalidate(TRUE); //刷新窗口;
    46 
    47 }

      ------------------------------------------------------------------------------------------------------------------------

     Windows自定义消息函数

       afx_msg LRESULT OnUpdateMenuCommand(WPARAM wParam, LPARAM lParam);

    其中WPARAM为unsigned int,  LPARAM为long

    与之前相关的给窗口发送消息的函数为SendMessage

    SendMessage(
    
    HWND  hWnd,         //目的窗口句柄
    
    UINT    nMessageID, //消息
    
    WPARAM wParam,  //unsigned int 参数
    
    LPARAM   lParam    //long类型参数
    
    )

    其中nMessageID的定义为: #define MY_MESSAGE  WM_USER +  一个数字

    WM_USER的定义为: #define  WM_USER  0X0400, 加上一个数字就能避免和系统消息冲突

    添加消息映射

    ON_MESSAGE(UPDATEUI_MESSAGE, CMainFrame::OnUpdateMenuCommand)

     有时候在不同的情况下要让目的窗口发生不同的变化,这个时候可以使用wParam和lParam这两个参数来传递给目的窗口不同的参数,

    这里有个实例就是让wParam中的某些位的区别 以及 lParam的区别来区分不同的消息类型,从而让目的窗口发生不同的变化

    eg.

      1 /////////////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //说明:::SendMessage(窗口句柄, 消息, wParam, lParam)
      4 // wParam == 0 :线程失败,没有进入实质的采集过程;
      5 // wParam == 0x****0001, lParam == 0x0000 00001 :线程成功,进入实质的采集过程;
      6 // wParam == 0x****0001, lParam == 0x0000 0000 :线程成功,进入实质采集过程,但是创建视频文件写入器失败
      7 // wParam == 0x****0001, lParam == 0x0000 00002 :线程成功,写视频异常;
      8 // wParam == 0x****0002, lParam == 0x0000 00000 :
      9 // 0x**** == code
     10 /////////////////////////////////////////////////////////////////////////////////////////////
     11 
     12 
     13 if (false == camera.OpenCamera(code, false, width, height))
     14 { 
     15 wParam = (code << 16) & 0xffff0000;
     16 wParam |= 0x00000000;
     17 
     18 ::SendMessage(hViewWnd, UPDATEUI_MESSAGE, wParam, 0); //失败,发送消息给主线程;
     19 ::SendMessage(hWndMainFrame, UPDATEUI_MESSAGE, wParam, 0);
     20 
     21 g_bIsRunningArr[min(code, MAX_CAMERAS_NUM)] = false;
     22 CString strInfo(_T("打开摄像头 "));
     23 strInfo += chCode;
     24 strInfo += _T(" 失败!");
     25 MessageBox(NULL, strInfo, _T("提示信息"), MB_OKCANCEL);
     26 return 0;
     27 }
     28 
     29 
     30 
     31 
     32 
     33 
     34 
     35 
     36 LRESULT CMainFrame::OnUpdateMenuCommand( WPARAM wParam, LPARAM lParam )
     37 {
     38 /////////////////////////////////////////////////////////////////////////////////////////////
     39 //
     40 //说明:::SendMessage(窗口句柄, 消息, wParam, lParam)
     41 // wParam == 0 :线程失败,没有进入实质的采集过程;
     42 // wParam == 0x****0001, lParam == 0x0000 00001 :线程成功,进入实质的采集过程;
     43 // wParam == 0x****0001, lParam == 0x0000 0000 :线程成功,进入实质采集过程,但是创建视频文件写入器失败
     44 // wParam == 0x****0001, lParam == 0x0000 00002 :线程成功,写视频异常;
     45 // wParam == 0x****0002, lParam == 0x0000 00000 :线程退出
     46 // 0x**** == code
     47 // wParam == 111(十进制), lParam == 0 :开始采集按钮事件 出错;
     48 /////////////////////////////////////////////////////////////////////////////////////////////
     49 
     50 WORD wLowState = 0; //状态代码;
     51 WORD wHICode = 0; //摄像头ID;
     52 
     53 wLowState = wParam & 0x0000ffff; //取低位两个字节;
     54 wHICode = (wParam >> 16) & 0x0000ffff; //取高位两个字节;
     55 
     56 const WCHAR strStartCapture[] = _T("开始采集");
     57 const WCHAR strEndCapture[] = _T("停止采集");
     58 const WCHAR strStartRecord[] = _T("开始录像");
     59 const WCHAR strEndRecord[] = _T("停止录像");
     60 
     61 int nCode = CCameraMonitorView::m_nCurrentCode; //获得当前摄像头code;
     62 
     63 //获得【视频】菜单;
     64 CMenu *pMenuVideo = NULL;
     65 pMenuVideo = GetMenu()->GetSubMenu(2);
     66 if (pMenuVideo == NULL)
     67 {
     68     AfxMessageBox(_T("pMenuVideo is NULL, CMainFrame::OnUpdateMenuCommand"));
     69     return -1;
     70 } 
     71 //如果当前摄像头code == 返回的摄像头code,则立即更新UI 
     72 if (nCode == wHICode && nCode != 0)
     73 {
     74     //线程在进入采集while之前失败;
     75     if (0 == wParam && 0 ==lParam)
     76     {
     77         //【开始采集】按钮可用,caption为【开始采集】,【开始录像】按钮不可用;
     78        pMenuVideo->ModifyMenu(0, MF_BYPOSITION, ID_MENU_STARTCAPTURE, strStartCapture);
     79     pMenuVideo->EnableMenuItem(0, MF_BYPOSITION | MF_ENABLED);
     80 
     81     pMenuVideo->EnableMenuItem(1, MF_BYPOSITION | MF_GRAYED | MF_DISABLED); 
     82   }
     83 
     84   //线程进入实质的采集过程;
     85   else if (1 == wLowState && 1 == lParam)
     86   {
     87     //【开始采集】按钮可用,caption为【停止采集】,【开始录像】按钮可用,caption为【开始录像】;
     88 
     89     pMenuVideo->ModifyMenu(0, MF_BYPOSITION | MF_STRING, ID_MENU_STARTCAPTURE, strEndCapture);
     90     pMenuVideo->EnableMenuItem(0, MF_BYPOSITION | MF_ENABLED);
     91 
     92     pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strStartRecord);
     93     pMenuVideo->EnableMenuItem(1, MF_BYPOSITION | MF_ENABLED);
     94 
     95 }
     96 
     97   //进入实质采集过程,但是创建视频写入器失败;
     98   else if (1 == wLowState && 0 == lParam)
     99   {
    100     //【开始采集】按钮不变, 【开始录像】按钮caption变为【开始录像】,可用;
    101     pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strStartRecord); 
    102     pMenuVideo->EnableMenuItem(1, MF_ENABLED);
    103   }
    104 
    105   //进入实质采集过程,写视频文件异常;
    106   else if (1 == wLowState && 2 == lParam)
    107   { 
    108     //【开始采集】按钮不变, 【开始录像】按钮caption变为【开始录像】,可用;
    109     pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strStartRecord); 
    110     pMenuVideo->EnableMenuItem(1, MF_ENABLED);
    111   }
    112 
    113   //线程退出;
    114   else if (2 == wLowState && 0 == lParam)
    115   {
    116     //【开始采集】按钮变味【开始采集】, 【开始录像】不可用;
    122    }
    123 
    124 }
    125 
    126 //开始采集 出错;
    127 if (111 == wParam && 0 == lParam)
    128 {
    129   //【开始采集】可用;
    130   pMenuVideo->EnableMenuItem(0, MF_BYPOSITION | MF_ENABLED);
    131 }
    132 else if (112 == wParam && 0 == lParam)
    133 {
    134   // GetDlgItem(IDC_BTN_RECORD)->EnableWindow(TRUE);
    135   //SetDlgItemText(IDC_BTN_RECORD, _T("停止录像"));
    136   pMenuVideo->EnableMenuItem(1, MF_ENABLED);
    137   pMenuVideo->ModifyMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_RECORD, strEndRecord);
    138 }
    139 else if (113 == wParam && 0 == lParam)
    140 {
    141 
    153 }
    154 else if (114 == wParam && 0 == lParam)
    155 { 

    } 166 else if (115 == wParam && 0 == lParam) 167 {

    } 171 else if (116 == wParam && 0 == lParam) 172 {

    } 176 else if (117 == wParam && 0 == lParam) 177 { 179 } 181 182 return 0; 183 }

      ------------------------------------------------------------------------------------------------------------------------

     ------------------------------------------------------------------------------------------------------------------------

     【打开文件】对话框

    GetModuleFileName :  获得包含路径的全文件名称
    PathRemoveFileSpec: 获得去掉文加名及后缀的文件路径

    上面这两个函数可能需要头文件<shlapi.h>

     1 void CMainFrame::OnMenuOpenfile()
     2 {
     3 // TODO: 在此添加命令处理程序代码; 
     4 
     5 static TCHAR szPath[MAX_PATH - 1] = {0};
     6 static bool bOnlyOnce = false;
     7 if (false == bOnlyOnce)
     8 {
     9 bOnlyOnce = true;
    10 GetModuleFileName(NULL, szPath, sizeof(szPath));
    11 PathRemoveFileSpec(szPath);
    12 }
    13 
    14 CString strFileName;
    15 
    16 CFileDialog dlg(TRUE);
    17 dlg.m_ofn.lpstrTitle = _T("打开avi视频文件");
    18 dlg.m_ofn.lpstrFilter = _T("Avi Files(*.avi)\0 *.avi\0All Files(*.*)\0 *.*\0\0");    //文件过滤器
    19 dlg.m_ofn.lpstrInitialDir = szPath;
    20 
    21 if (IDOK == dlg.DoModal())
    22 { 
    23 strFileName = dlg.GetPathName();
    24 
    25 //CString 2 TCHAR*
    26 int iLen = strFileName.GetLength(); 
    27 memset(szPath, 0, sizeof(szPath)); 
    28 lstrcpy(szPath, strFileName.GetBuffer(iLen)); //得到szPath;
    29 strFileName.ReleaseBuffer();
    30 
    31 //CString 2 char* 
    32 char* pVideoFileName = (char*)malloc((iLen * 2 + 1) * sizeof(char));//CString的长度中汉字算一个长度; 
    33 memset(pVideoFileName, 0, 2 * iLen + 1); 
    34 USES_CONVERSION; 
    35 strcpy((LPSTR)pVideoFileName,OLE2A(strFileName.LockBuffer())); //得到pVideoFileName;
    36 
    37 if (NULL == pVideoFileName)
    38 {
    39 assert(pVideoFileName != NULL);
    40 AfxMessageBox(_T("视频文件打开失败!"));
    41 return;
    42 }
    43 else
    44 {
    45 PalyVideo(pVideoFileName); //播放视频;
    46 free(pVideoFileName);
    47 }
    48 
    49 
    50 PathRemoveFileSpec(szPath); //去掉文件名只保留路径;
    51 }
    52 }

     ------------------------------------------------------------------------------------------------------------------------

     MFC静态控件默认不响应键盘鼠标事件,需要激活SS_NOTIFY,可在控件属性里或者用该代码如下

    //使Picture控件响应鼠标事件

    GetDlgItem(IDC_VIDEO0)->ModifyStyle(0, SS_NOTIFY);
    GetDlgItem(IDC_VIDEO1)->ModifyStyle(0, SS_NOTIFY); 
    GetDlgItem(IDC_VIDEO2)->ModifyStyle(0, SS_NOTIFY);

      

     ------------------------------------------------------------------------------------------------------------------------

     获得桌面坐标 GetWindowRect和 客户区坐标GetClientRect

    两者的区别仅仅是起点不同,桌面坐标的起点根据实际情况来,客户区的坐标起点是(0, 0),

    他们之间通过ClientToScreen和ScreenToClient互相转换

     ------------------------------------------------------------------------------------------------------------------------

     开启子线程_begingthreadex

    函数原型

    函数原型:
    unsigned long _beginthreadex(
        void *security,
        unsigned stack_size,
        unsigned ( __stdcall *start_address )( void * ),
        void *arglist, /* 这个就是传给线程函数的参数的指针 */
        unsigned initflag,
        unsigned *thrdaddr );


    线程函数
    UINT __stdcall ShowThread(void *p)


    eg.

     1 UINT retValue = _beginthreadex(NULL, 
     2 0,
     3 ShowThread,  //线程函数
     4 pParams,       //参数
     5 0,
     6 &nThreadID  //线程ID
     7 );
     8 
     9 
    10 if (INVALID_HANDLE_VALUE == (HANDLE)retValue)
    11 {
    12 MessageBox(_T("线程创建可能失败!INVALID_HANDLE_VALUE"));
    13 delete pParams;
    14 pParams = NULL;
    15 return false;
    16 }
    17 else if (NULL == (HANDLE)retValue)
    18 {
    19 MessageBox(_T("线程创建可能失败!NULL"));
    20 delete pParams;
    21 pParams = NULL;
    22 return false;
    23 }
    24 
    25 return true;

     ------------------------------------------------------------------------------------------------------------------------

     TreeView的使用

    MFC单文档程序中:选择资源管理器风格, VIEW类的父类选择CTreeView,则生成的程序中有个CLeftView,

    CLeftView在程序中动态生成,因此取得该控件的方法是  CTreeCtrl& treeCtrl = GetTreeCtrl();

    eg.

     1 void CLeftView::UpdateCameraList()
     2 {
     3     m_hWndLeftView = m_hWnd;
     4 
     5   CTreeCtrl& treeCtrl = GetTreeCtrl();
     6 
     7   treeCtrl.DeleteAllItems();
     8 
     9   CImageList Cil1, Cil2;
    10   CCameraMonitorApp *pApp = (CCameraMonitorApp*)AfxGetApp();
    11   Cil1.Create(16, 16, ILC_COLOR, 2, 2);
    12   Cil1.Add(pApp->LoadIcon(IDI_ICON1));
    13   Cil1.Add(pApp->LoadIcon(IDI_ICON2));
    14 
    15   treeCtrl.SetImageList(&Cil1, TVSIL_NORMAL);
    16 
    17   DWORD dwStyles = GetWindowLong(m_hWnd, GWL_STYLE);
    18   dwStyles |= TVS_EDITLABELS | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT;
    19   SetWindowLong(m_hWnd, GWL_STYLE, dwStyles);
    20 
    21   TCHAR* arrFather[] = {_T("A栋"), _T("B栋"), _T("C栋"), _T("D栋"), _T("E栋"), _T("F栋"), _T("G栋"), _T("H栋"), _T("I栋")};
    22   TCHAR* arrSon[3][2] = {{_T("11"), _T("12")}, {_T("21"), _T("22")}, {_T("31"), _T("32")}};  
    25 
    26    int i = 0;
    27    int j = 0;
    28 
    29   HTREEITEM hRoot, hCur;
    30   TV_INSERTSTRUCT TCItem;
    31   TCItem.hParent = TVI_ROOT;
    32   TCItem.hInsertAfter = TVI_LAST;
    33   TCItem.item.pszText = _T("摄像头列表");
    34   TCItem.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
    35   TCItem.item.lParam = 0;
    36   TCItem.item.iImage = 0;
    37   TCItem.item.iSelectedImage = 1;
    38 
    39   hRoot = treeCtrl.InsertItem(&TCItem); //根节点;
    40 
    41   CCamerasInfo::GetCameraCountNames(); //获得摄像头数量和名字; 
    42   WCHAR wcName[512] = {0};
    43 
    44   for (i = 0; i < CCamerasInfo::s_nCameraCount; ++ i)
    45   {
    46     TCItem.hParent = hRoot;
    47    TCItem.item.pszText = arrFather[i];
    48     TCItem.item.lParam = (i + 1) * 10;
    49     hCur = treeCtrl.InsertItem(&TCItem);
    50     for (j = 0; j < 1; ++ j)
    51     {
    52       TCItem.hParent = hCur;
    53 
    54       //char* 转 wchar_t*
    55       MultiByteToWideChar(CP_ACP, 0, (LPCSTR)CCamerasInfo::s_chCameraNameArray[i], 
    56       sizeof(CCamerasInfo::s_chCameraNameArray[i]), wcName, sizeof(wcName));
    57 
    58       TCItem.item.pszText = wcName;
    59       TCItem.item.lParam = (i + 1) * 10 + (j + 1);
    60       treeCtrl.InsertItem(&TCItem);
    61     }
    62 
    63     treeCtrl.Expand(hCur, TVE_EXPAND);
    64   }
    65   treeCtrl.Expand(hRoot, TVE_EXPAND);
    66 
    67 }

     ------------------------------------------------------------------------------------------------------------------------

    屏幕坐标至客户区域坐标

     1 //Picture0控件双击事件;
     2 void CCameraMonitorView::OnStnDblclickVideo0()
     3 {
     4     // TODO: 在此添加控件通知处理程序代码;
     5 
     6     CRect rect;
     7     GetDlgItem(IDC_VIDEO0)->GetWindowRect(&rect);
     8     ScreenToClient(&rect);;
     9 
    10 
    11     CRect rect2;
    12     GetDlgItem(IDC_VIDEO0)->GetClientRect(&rect2);
    13     GetDlgItem(IDC_VIDEO0)->MapWindowPoints(FromHandle(m_hWnd), rect2);
    14  
    15 
    16 }

      

      

  • 相关阅读:
    hello world !
    从数据库提取数据报错java.sql.SQLException: Column '4' not found.解决方法
    tomcat加载项目无法启动报错(Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/**])解决办法
    tomcat SERVER启动时did not find a matching property错误解决办法
    MVC与SSH(SSM)间的关系
    the resource is not on the build path of a Java project报错解决
    接口的作用
    eclipse error pages打红X的解决方法
    文本提交带单引号引起mysql报错
    五、HTML判断输入长度,体会字体颜色变化
  • 原文地址:https://www.cnblogs.com/cuish/p/2893190.html
Copyright © 2011-2022 走看看