?
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
}
?
?
?
?
??
?
??
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

