I can't get more than 32 items to work correctly in CGXCheckListComboBox. This is this because of the fact that you are using a bitmapped integer( 32 bit long) to pass the choices around. How can I get around this?
There are many alternatives when you subclass CGXCheckListComboBox. Here are two solutions we found very convenient:
Subclass CGXCheckListComboBox and store the checked state in a hash table that you attach to the style object through SetItemDataPtr.
Subclass CGXCheckListComboBox and store each choice list entry separated by a comma as value in the cell.
Solution a: Subclass CGXCheckListComboBox and store the checked state in a hash table that you attach to the style object through SetItemDataPtr..
//.h file
//CMyCheckListComboBox control
class CMyCheckListComboBox : public CGXCheckListComboBox
{
DECLARE_CONTROL(CMyCheckListComboBox)
public:
CMyCheckListComboBox(CGXGridCore* pGrid, UINT nEditID = 0, UINT nListBoxID = 0);
// Overridden these methods
virtual void OnStoreDroppedList(CListBox* lbox);
virtual void OnFillDroppedList(CListBox* lbox);
};
//.cpp file
#include <afxtempl.h> //include this for CMap template defenition
IMPLEMENT_CONTROL(CMyCheckListComboBox,CGXCheckListComboBox)
CMyCheckListComboBox::CMyCheckListComboBox(CGXGridCore* pGrid, UINT nEditID, UINT nListBoxID)
: CGXCheckListComboBox(pGrid, nEditID, nListBoxID)
{
}
void CMyCheckListComboBox::OnStoreDroppedList(CListBox* lbox)
{
CGXStyle style = Grid()->LookupStyleRowCol(m_nRow, m_nCol);
CGXCheckListComboLBox* checklbox = (CGXCheckListComboLBox*) lbox;
ASSERT(checklbox->IsKindOf(RUNTIME_CLASS(CGXCheckListComboLBox)));
//This is the CMap template that you should attach to the style object through SetItemDataPtr
CMap<int,int, BOOL,BOOL> *myMap;
myMap = (CMap<int, int, BOOL, BOOL>*)style.GetItemDataPtr();
if(myMap == NULL)
myMap = new CMap<int, int, BOOL, BOOL>;
// Save the selection
// enable choices
//Clean up the existing map before you store the new value into it
myMap->RemoveAll();
for (int n = 0; n < m_nCount; n++)
{
if (checklbox->GetCheck(n) == 1)
{
myMap->SetAt(n,TRUE);
}
}
style.SetItemDataPtr(myMap);
Grid()->SetStyleRange(CGXRange(m_nRow,m_nCol),style);
}
void CMyCheckListComboBox::OnFillDroppedList(CListBox* lbox)
{
const CGXStyle& style = Grid()->LookupStyleRowCol(m_nRow, m_nCol);
CGXCheckListComboLBox* checklbox = (CGXCheckListComboLBox*) lbox;
ASSERT(checklbox->IsKindOf(RUNTIME_CLASS(CGXCheckListComboLBox)));
CMap<int,int, BOOL,BOOL> *myMap;
myMap = (CMap<int, int, BOOL, BOOL>*)style.GetItemDataPtr();
//You should have attached a CMap template of type CMap<int,int, BOOL,BOOL> to the style
// fill with Choices
if (style.GetIncludeChoiceList())
{
CString s = style.GetChoiceListRef();
CString sItem;
// skip first entry in choice list because this is the text to be displayed in the cell
int n = GXGetNextLine(s, sItem);
m_nCount = 0;
while (!s.IsEmpty() && n != -1)
{
n = GXGetNextLine(s, sItem);
lbox->AddString(sItem);
m_nCount++;
}
}
// enable choices
if (myMap)
{
BOOL b=FALSE;
for (int n = 0; n < m_nCount; n++)
{
b=FALSE;
myMap->Lookup(n,b);
checklbox->SetCheck(n, b);
}
}
}
Register your control:
RegisterControl(GX_IDS_CTRL_CHECKLIST_COMBOBOX,
new CMyCheckListComboBox(this, 9000,9001/*random id*/));
Set the control in the cell like this:
LPCTSTR szMultiChoiceList =
_T("Click Me\n")
_T("One\n")
_T("Two\n")
_T("Three\n")
_T("Four\n")
_T("Five\n")
_T("Six\n")
_T("Seven\n")
_T("Eight\n")
_T("Nine\n")
_T("Ten\n");
CMap<int,int, BOOL,BOOL> *myMap = new CMap<int,int, BOOL,BOOL>;
myMap->SetAt(1,TRUE);
SetStyleRange(CGXRange().SetRows(nRow+1),
CGXStyle()
.SetControl(GX_IDS_CTRL_CHECKLIST_COMBOBOX)
.SetChoiceList(szMultiChoiceList)
.SetItemDataPtr(myMap)
);
This will check the item "Two".(list is 0 based).
You can retrieve the checked state of the control using:
CGXStyle style = LookupStyleRowCol(m_nRow, m_nCol);
CMap<int,int, BOOL,BOOL> *myMap = style.GetItemDataPtr();
BOOL b=FALSE;
if(myMap->Lookup(1,b) && b)
TRACE("Item 1 is checked");
Solution b: Subclass CGXCheckListComboBox and store each choice list entry separated by a comma as value in the cell.
Override OnFillDroppedList and OnStoreDroppedList as follows:
void CMyCheckListComboBox::OnFillDroppedList(CListBox* lbox)
{
const CGXStyle& style = Grid()->LookupStyleRowCol(m_nRow, m_nCol);
CGXCheckListComboLBox* checklbox = (CGXCheckListComboLBox*) lbox;
ASSERT(checklbox->IsKindOf(RUNTIME_CLASS(CGXCheckListComboLBox)));
// fill with Choices
if (style.GetIncludeChoiceList())
{
CString s = style.GetChoiceListRef();
CString sItem;
// skip first entry in choice list because this is the text to be displayed in the cell
int n = GXGetNextLine(s, sItem);
m_nCount = 0;
while (!s.IsEmpty() && n != -1)
{
n = GXGetNextLine(s, sItem);
lbox->AddString(sItem);
m_nCount++;
}
}
// enable choices
if (style.GetIncludeValue())
{
CString s = style.GetValueRef();
int n = 0;
CString sItem;
while (!s.IsEmpty() && n != -1)
{
n = GXGetNextLine(s, sItem);
checklbox->SetCheck(_ttoi(sItem), TRUE);
}
}
}
void CMyCheckListComboBox::OnStoreDroppedList(CListBox* lbox)
{
CGXCheckListComboLBox* checklbox = (CGXCheckListComboLBox*) lbox;
ASSERT(checklbox->IsKindOf(RUNTIME_CLASS(CGXCheckListComboLBox)));
// Save the selection
// enable choices
CString sValue;
TCHAR sz[20];
for (int n = 0; n < m_nCount; n++)
{
if (checklbox->GetCheck(n) == 1)
{
wsprintf(sz, _T("%d\n"), n);
sValue += sz;
}
}
Grid()->SetValueRange(CGXRange(m_nRow, m_nCol), sValue);
}
Register your control:
RegisterControl(GX_IDS_CTRL_CHECKLIST_COMBOBOX,
new CMyCheckListComboBox(this, 9000,9001/*random id*/));
Set the control in the cell like this:
SetStyleRange(CGXRange().SetRows(nRow+1),
CGXStyle()
.SetControl(GX_IDS_CTRL_CHECKLIST_COMBOBOX)
.SetChoiceList(szMultiChoiceList)
.SetValue("Two\nFour\n")
);
This will check the item "Two" and "Four".
You can retrieve the checked state of the by looping through the value (with GXGetNextLine). This will return all checked items.