我在mfc的CMenuView中添加了一個回應函式,然后添加代碼
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加訊息處理程式代碼和/或呼叫默認值
//CMenu menu;
m_Menu.LoadMenu(IDR_Popup);//m_Menu 在類中宣告(private)
CMenu *pPopup = m_Menu.GetSubMenu(0);
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
CView::OnRButtonDown(nFlags, point);
}
編譯沒有問題,運行到上面加粗的那句時出現如下錯誤,求大神解答
uj5u.com熱心網友回復:
這個問題解決了,原因是我之插入了一個選單(IDR_Popup)但是沒有對選單進行操作,所以會出錯,但是隨之又有一個新問題,就是我定義了一個全域變數m_Menu,這樣運行后,我右擊第一次成功,右擊第二次又出現上述錯誤,但是我在回應函式內宣告一個CMenu變數就一切正常了,這是什么原因uj5u.com熱心網友回復:
下面那個問題也解決了,我要是在這個陳述句pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);后邊加上m_Menu.Detach();那么就一切正常了。
我的猜想是,m_Menu是一個物件,全域變數從第一次右擊滑鼠開始這個物件就創建了,然后下次點擊的時候再一次創建就矛盾了,所以應該呼叫一個解構式,我說的對嗎?望大牛指正
uj5u.com熱心網友回復:
我自己來頂一下uj5u.com熱心網友回復:
嗯。Detachuj5u.com熱心網友回復:
我的vc6什么也沒寫,也沒錯誤,看來2010嚴格了。uj5u.com熱心網友回復:
menu.GetSubMenu( 0 )->TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON, pMsg->pt.x, pMsg->pt.y, this );menu.DestroyMenu();
這樣寫的
uj5u.com熱心網友回復:
恭喜LZ自己解決問題..........uj5u.com熱心網友回復:
那怎么對選單進行操作才能讓加黑部分不報錯呢?uj5u.com熱心網友回復:
加載選單之前,先判斷c++物件是否已經和windows的選單句柄關聯了。重復Attach是會報錯的,因為這樣會造成記憶體泄漏。
if (m_Menu.GetSafeHmenu() == NULL)
{
m_Menu.LoadMenu(IDR_Popup);//m_Menu 在類中宣告(private)
}
CMenu *pPopup = m_Menu.GetSubMenu(0);
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
CView::OnRButtonDown(nFlags, point);
uj5u.com熱心網友回復:
另外一種做法就是,創建和關聯新的menu之前。先把舊的給Destroy掉,注意不要用detach,這樣會走造成記憶體泄漏。
void CTestView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加訊息處理程式代碼和/或呼叫默認值
//CMenu menu;
m_Menu.DestroyMenu();
m_Menu.LoadMenu(IDR_POPUP_EDIT);//m_Menu 在類中宣告(private)
CMenu *pPopup = m_Menu.GetSubMenu(0);
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);
CView::OnRButtonDown(nFlags, point);
}
uj5u.com熱心網友回復:
這些其實都可以看原始碼的。報錯的原因在ASSERT(m_hMenu == NULL);這行代碼。
因為你之前Load過了, m_hMenu已經不為NULL,斷言就報錯了。
_AFXWIN_INLINE BOOL CMenu::LoadMenu(LPCTSTR lpszResourceName)
{ return Attach(::LoadMenu(AfxFindResourceHandle(lpszResourceName,
RT_MENU), lpszResourceName)); }
BOOL CMenu::Attach(HMENU hMenu)
{
ASSERT(m_hMenu == NULL); // only attach once, detach on destroy
if (hMenu == NULL)
{
return FALSE;
}
// Capture menu in object first to ensure it does not leak if the map cannot be allocated/expanded
m_hMenu=hMenu;
CHandleMap* pMap = afxMapHMENU(TRUE); // create map if not exist
ASSERT(pMap != NULL);
pMap->SetPermanent(m_hMenu, this);
return TRUE;
}
要理解好c++的CMenu和 win32的 HMENU區別。
CMenu物件資源釋放的方式, 和HMENU釋放方式是不一樣的。
MFC初學者容易把兩者混淆。
Detach只是把系統選單資源(HEMNU)和c++選單物件的關聯斷開,
真正要釋放系統選單資源還要呼叫 ::DestroyMenu
BOOL CMenu::DestroyMenu()
{
if (m_hMenu == NULL)
return FALSE;
return ::DestroyMenu(Detach());
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/105253.html
標籤:基礎類
