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 }