禁用CMFCRibbonBar的按鈕(變灰)

昨天很糾結,一直上網搜索如何令CMFCRibbonBar的按鈕變灰,剛開始以爲獲得了按鈕的指針,裏面一定有方法或者接口達到我想要的功能,剛開始以爲那些按鈕和Checkbox等元素是我們普通的控件元素,誰知道用SPY++查了一下,這些都不是繼承於CWnd的元素,只是一張一張的圖片。後來在認真看了一下MSDN就寫了如下代碼獲得裏面的某一按鈕元素。

CArray<CMFCRibbonBaseElement* ,CMFCRibbonBaseElement*> arButtons;
m_wndRibbonBar.GetElementsByID(IDC_BUTTON_BRIMIN,arButtons);
arButtons.ElementAt(0)->SetVisible(enableTag);
誰知道寫了這些後,發覺一點效果都沒有,那時就納悶了。接着就打開MFC的源碼一句一句調試,發現原來是保護成員裏的m_bIsDisable的控制量控制,那可簡單了,只需要設成TRUE嗎,那就搜搜哪一個接口能更改這個值,誰知道還沒有呢,這是就想到有沒有方法能更改保護成員的值呢,想到更改這個值是編譯器有一個選項阻止了這樣的動作,沒道理要更改這個配置嘛,後來在網上搜到一個很強大的宏如下:

My Approch :

 

#define PROTECTED_CAST_DECL (CLASS_TYPE ,MEMBER_TYPE ,MEMBER_NAME )          /
template <typename ClassType , typename MemberType >                   /
class C ##MEMBER_NAME ##Accessor                                        /
{                                                                    /
	class CAccessor : public ClassType                                 /
	{                                                                /
		 friend class C ##MEMBER_NAME ##Accessor ;                       /
	};                                                               /
public :                                                              /
	static MemberType & GetMember (ClassType * pClass )                 /
	{                                                                /
		return ((CAccessor *)pClass )->MEMBER_NAME ;                    /
	}                                                                /
};

 

#define PROTECTED_CAST (CLASS_TYPE ,CLASS_OBJECT_PTR ,MEMBER_TYPE ,MEMBER_NAME ) (C ##MEMBER_NAME ##Accessor <CLASS_TYPE , MEMBER_TYPE >::GetMember (CLASS_OBJECT_PTR ))

 

Sample :

   以下示例代碼展示了 PROTECTED_CAST 的使用方法,代碼在 VC++ 2008 下測試通過。

class CPrivateMemberWrapper

{

protected :

         int m_iValue ;

         double m_dValue ;

         string m_sValue ;

public :

         CPrivateMemberWrapper (int i , double d , const char * lps ):

           m_iValue (i ), m_dValue (d ), m_sValue (lps )

         {}

         ~CPrivateMemberWrapper () {}

};

PROTECTED_CAST_DECL (CPrivateMemberWrapper , int , m_iValue )

PROTECTED_CAST_DECL (CPrivateMemberWrapper , double , m_dValue )

PROTECTED_CAST_DECL (CPrivateMemberWrapper , string , m_sValue )
這樣確實可以令到那個按鈕變灰,但是畢竟這是投機取巧的方法。後來又想到當這個元素沒有綁定特定的事件時也是呈現灰色狀態的,就想那有沒有能動態增刪事件綁定的方法,誰知道感覺這麼一個簡單的方法,居然還搜不到所要的答案,沒辦法了,看來只有按照自己的思路寫一下吧,看了一下,BeginMessage和EndMessage的宏,瞭解到消息鏈表也只是一個有結尾項的數組,那我所要實現的只不過是在這個數組上面增刪項目(瘋了,沒辦法就什麼都要嘗試),代碼如下:

const AFX_MSGMAP* message = this->GetMessageMap();
AFX_MSGMAP_ENTRY* mePtr = const_cast<AFX_MSGMAP_ENTRY*>((const_cast<AFX_MSGMAP*>(message))->lpEntries);
if(enableTag)
{
	//綁定消息
	int reduce = 1;
	bool haveTag = false;
	while(mePtr->nSig != AfxSig_end)
	{
		if(mePtr->nID == IDC_BUTTON_BRIMIN)
		{
			haveTag = true;
			break;
		}
		++mePtr;
	}
	if(!haveTag)
	{
		mePtr[reduce] = mePtr[0];
		AFX_MSGMAP_ENTRY tmpMA[] = {ON_COMMAND(IDC_BUTTON_BRIMIN, &CMainFrame::OnButtonBrimin){0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }};
		*mePtr = tmpMA[0];
	}
}
else
{
	//移除消息綁定
	int reduce = 0;
	int index = 0;
	while(mePtr->nSig != AfxSig_end)
	{
		if(mePtr->nID == IDC_BUTTON_BRIMIN)
		{
			++reduce;
		}

		*mePtr = *(mePtr + reduce);
		++mePtr;
		++index;
	}
}
經測試這樣確實能動態增刪事件綁定,而且按鈕也會變灰,好像達到了要求,哎,不過本人還是比較糾結爲什麼這樣的方法網上沒有貼出來,肯定是或多或少有點問題,所以還是不滿足,就繼續找資料,又找了一個早上,纔在一篇文章裏看到必須要響應ON_UPDATE_COMMAND_UI或者ON_UPDATE_COMMAND_UI_RANGE事件達到這樣的功能,而且那裏的作者還寫着是基礎知識,後悔自己基礎唔牢固,鬱悶了,寫了一年多C++的我也完全沒了解過這個事件。後來就改成了這樣

ON_UPDATE_COMMAND_UI_RANGE(ID_BUTTON_BRIMIN,ID_BUTTON_TEST, &CMainFrame::OnUpdateIdrRibbonI)

void CMainFrame::OnUpdateIdrRibbonI(CCmdUI *pCmdUI)
{
	BOOL enableTag = (BOOL)czDevs->czSelSect.size();
	pCmdUI->Enable(enableTag);\\還能設置SetChecked等功能呢
}
這樣就完美解決了這個問題,原來這兩個消息是用來更新像菜單、工具欄、狀態欄、屬性窗口等UI界面的。哎,應該以後不會再犯如何更改m_bIsDisable的成員了。



發佈了13 篇原創文章 · 獲贊 14 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章