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
}

