相互聯絡的下拉框控制元件設計
在應用程式的介面中,經常可以看到相互關聯的下拉框組出現。比如查詢條件一類應用,設定查詢條件時,經常是第一個下拉框中含有待查詢的專案,選中其中的一個專案,第二個下拉框中的選項變為對應於該專案型別的運算子,第三個下拉框中的選擇變為對應於該專案的可選值。
一般的,這種關聯關係的處理都是放在下拉框控制元件所在的對話方塊等容器視窗中。通過第一個下拉框的SelectChange通知訊息,根據選中的專案,對後面相關的下拉框進行處理。這樣做的不好之處是,下拉框控制元件之間的相互關係放到容器類中來處理,容器類的程式碼就會顯得比較亂;而且這些下拉框基本失去的重用的可能。
基於上面的分析,我寫了些下拉框類,通過Observer模式來把下拉框控制元件之間的互動放到它們自己的類中來實現,在容器類中,只負責為下拉框的資料來源賦值,並處理它們之間的關係。具體的程式碼大概如下:
typedef map <string, list <string> > OB_MAP; // 觀察者的資料來源型別
typedef map <string, string> SUB_MAP; // 主題的資料來源型別
typedef CMap<CString, LPCTSTR, CString, LPCTSTR> MFC_SUB_MAP; // 主題賦值資料來源型別,為了MFC下賦值方便,採用CMap
// 觀察者下拉框
class CObComboBox : public CComboBox
{
OB_MAP m_mapContent; // 資料來源
void Update(string strKey); // 根據主題所選專案的型別來更新,內部遍歷Map,找到匹配項,呼叫RefreshContent重新生成下拉選項
void AddDataSourceItem(CString strKey, CStringArray& arrItemContent); // 外部設定資料來源中的一個條目
void RefreshContent(list<string> & arrContent); // 根據匹配的字元列表重新生成下拉選項
};
// 主題下拉框
class CSubComboBox : public CComboBox
{
list <CObComboBox*> m_arrObserver; // 觀察者列表
SUB_MAP m_mapContent; // 主題資料來源
void AddObserver(CObComboBox* pOb); // 新增到觀察者列表
void AddDataSource(MFC_SUB_MAP & mapContent); // 外部設定資料來源
void Notify(string strKey); // 通知觀察者更新,內部遍歷觀察者列表,呼叫其Update函式
afx_msg void OnCbnSelchange(); // 處理SelectChange訊息,內部遍歷Map,找到匹配項後,呼叫Notify函式
};
具體的實現,這裡就不贅述了,無非是一些stl和CString/CStringArray之間的操作
外部使用的時候,可以寫成類似下面的函式:
void CXXXDlg::InitCombo(void)
{
// 給第一個下拉框的下拉選項賦值,分別為1和hello,型別為INT和STRING
MFC_SUB_MAP mapContent;
mapContent.SetAt(_T("1"), _T("INT"));
mapContent.SetAt(_T("hello"), _T("STRING"));
m_cbbType.AddDataSource(mapContent);
// 給第二個下拉框,也就是運算子下拉框賦資料來源
CStringArray arrIntOp, arrStringOp;
arrIntOp.Add(_T("=="));
arrIntOp.Add(_T("!="));
arrStringOp.Add(_T("NULL"));
arrStringOp.Add(_T("Contain"));
arrStringOp.Add(_T("NonContain"));
// INT型別的運算子為 ==和!=
m_cbbOperator.AddDataSourceItem(_T("INT"), arrIntOp);
// STRING型別的運算子為 NULL,Contain和NonContain
m_cbbOperator.AddDataSourceItem(_T("STRING"), arrStringOp);
// 給第三個下拉框,也就是可選值下拉框賦資料來源
CStringArray arrInt, arrString;
arrInt.Add(_T("2"));
arrInt.Add(_T("3"));
arrInt.Add(_T("4"));
arrInt.Add(_T("5"));
arrInt.Add(_T("6"));
arrString.Add(_T("a"));
arrString.Add(_T("b"));
arrString.Add(_T("c"));
arrString.Add(_T("d"));
arrString.Add(_T("e"));
// INT型別的可選值為2,3,4,5,6
m_cbbValue.AddDataSourceItem(_T("INT"), arrInt);
// STRING型別的可選值為a,b,c,d,e
m_cbbValue.AddDataSourceItem(_T("STRING"), arrString);
// 最後定義觀察關係
m_cbbType.AddObserver(&m_cbbOperator);
m_cbbType.AddObserver(&m_cbbValue);
}
這樣當第一個下拉框選擇1或者hello時,後兩個下拉框就會根據其選擇來顯示對應的運算子和可選值。而且在主對話方塊CXXXDlg中,只要定義資料來源和關係即可,比較清楚。