| | | | Browse by category |
Problem
I have cells containing several choices. I don't want to display them in a combobox. Is there a way that the user is able to select items from the choice-list by clicking on spin-buttons?
Cause
Action
Yes, you can derive a class from CGXSpinEdit and display the choice-list entry associated with the zero-based index value. You need to override GetControlText() and GetValue().
If you implement the following class CSpinListControl:
// header (.h) file
class CspinListControl: public CGXSpinEdit |
||||||
DECLARE_CONTROL(CSpinListControl) | ||||||
public: | ||||||
// Constructor & Destructor CspinListControl(CGXGridCore* pGrid, UINT nID); // Overrides // Attributes |
||||||
// TRUE if control should store zero-based index as value; // FALSE if control should store choice list entry as value. |
||||||
// Generated message map functions | ||||||
protected: | ||||||
//{{AFX_MSG(CSpinListControl) //}}AFX_MSG DECLARE_MESSAGE_MAP() |
||||||
}; | ||||||
// implementation (.cpp) file
////////////////////////////////////////////////////////////////// IMPLEMENT_CONTROL(CSpinListControl, CGXSpinEdit) CspinListControl::CSpinListControl(CGXGridCore* pGrid, UINT nID) |
||||||
: CGXSpinEdit(pGrid, nID) | ||||||
{ | ||||||
m_bUseIndexValue = FALSE; | ||||||
// TRUE if control should store zero-based index as value. // FALSE if control should store choice list entry as value. |
||||||
}
BEGIN_MESSAGE_MAP(CSpinListControl, CGXSpinEdit) |
||||||
//{{AFX_MSG_MAP(CSpinListControl)
//}}AFX_MSG_MAP |
||||||
END_MESSAGE_MAP()
// GetControlText |
||||||
if (!CGXSpinEdit::GetValue(sResult)) | ||||||
return FALSE; | ||||||
if (m_bUseIndexValue && m_pStyle && m_pStyle->GetIncludeChoiceList()) { |
||||||
CString sMatch = sResult;
// finds exact string or the first string with the same prefix if (nIndex != -1) |
||||||
wsprintf(sResult.GetBuffer(20), _T("%d"), nIndex); sResult.ReleaseBuffer(); |
||||||
} else |
||||||
sResult.Empty(); | ||||||
}
return TRUE; |
||||||
}
BOOL CSpinListControl::GetControlText(CString& strResult, ROWCOL nRow, ROWCOL nCol, LPCTSTR pszRawValue, const CGXStyle& style) |
||||||
CString sItem;
if (m_bUseIndexValue) |
||||||
// determine index short nIndex = -1; if (pszRawValue && _tcslen(pszRawValue) > 0) |
||||||
nIndex = (short) _ttoi(pszRawValue); | ||||||
else if (style.GetIncludeValue() && _tcslen(style.GetValueRef()) > 0) | ||||||
nIndex = style.GetShortValue(); | ||||||
if (nIndex != -1) | ||||||
GetChoiceListItem(sItem, style.GetChoiceListRef(), nIndex); | ||||||
// base class version will format the text as specified in mask pszRawValue = sItem; |
||||||
}
// Now, we can format this entry. |
||||||
}
void CSpinListControl::OnClickedButton(CGXChild* pChild) |
||||||
BOOL bActive = IsActive();
if (!bActive && !OnStartEditing()) |
||||||
return; | ||||||
SetActive(TRUE);
NeedStyle(); CString strText; // empty cell, when user pressed alpahnumeric key |
||||||
LONG lValue ;
// style if ( m_bStartValue && strText.IsEmpty() ) |
||||||
lValue = m_nStartValue ; | ||||||
else { |
||||||
// Non-Null cell if (m_bUseIndexValue) |
||||||
lValue = _ttol(strText); | ||||||
else { |
||||||
CString sMatch = strText;
// finds exact string or the first string |
||||||
}
if (pChild == m_pUpArrow) |
||||||
if (!m_bMaxBound || lValue < m_nMaxBound) | ||||||
lValue++; | ||||||
else if (m_bWrap && m_bMinBound) | ||||||
lValue = m_nMinBound; | ||||||
} else { |
||||||
if (!m_bMinBound || lValue > m_nMinBound) | ||||||
lValue--; | ||||||
else if (m_bWrap && m_bMaxBound) | ||||||
lValue = m_nMaxBound; | ||||||
} | ||||||
}
if (m_bMinBound) |
||||||
lValue = max(m_nMinBound, lValue); | ||||||
if (m_bMaxBound) | ||||||
lValue = min(m_nMaxBound, lValue); | ||||||
if (m_bUseIndexValue) { |
||||||
wsprintf(sz, _T("%ld"), lValue); SetValue(sz); |
||||||
} else { |
||||||
CString sItem; GetChoiceListItem(sItem, m_pStyle->GetChoiceListRef(), lValue); SetValue(sItem); |
||||||
}
SetModify(TRUE); |
||||||
}
// eventually destroys and creates CEdit with appropriate window style |
||||||
Refresh(); | ||||||
else | ||||||
UpdateEditStyle(); | ||||||
CGXControl::OnClickedButton(pChild); | ||||||
}
void CSpinListControl::OnInitChildren(ROWCOL nRow, ROWCOL nCol, const CRect& rect) |
||||||
nRow, nCol; const int nEditBtnWidth = 13; // CRect rect = CGXControl::GetCellRect(nRow, nCol, (LPRECT) &r, m_pStyle); // init arrow buttons m_pUpArrow->SetRect(CRect(rectBtn.left, rectBtn.top, rectBtn.right, rectBtn.top+rectBtn.Height()/2)); m_pDownArrow->SetRect(CRect(rectBtn.left, rectBtn.top+rectBtn.Height()/2, rectBtn.right, rectBtn.bottom)); |
||||||
}
// override the Draw method only if you want that the spin-buttons |
||||||
pStandardStyle, style; CGXSpinEdit::Draw(pDC, rect, nRow, nCol, style, pStandardStyle); // Normal, spin-buttons are not drawn for inactive cells. |
||||||
for (int i = 0; i < GetCount(); i++) { |
||||||
CGXChild* pChild;
if ((pChild = GetChild(i)) != NULL) |
||||||
pChild->Draw(pDC, !Grid()->IsPrinting()); | ||||||
} | ||||||
} | ||||||
} |
You can register the control and user attribute in the OnInitialUpdate() routine of your grid class with:
// Register all controls and user attributes for the view // IDS_CTRL_SPINLIST is a string resource // you have to add to your application. RegisterControl(IDS_CTRL_SPINLIST, new CspinListControl(this, IDS_CTRL_SPINLIST)); |
and later apply it to cells with:
SetStyleRange(CGXRange(4,4,10,4), | |||
CGXStyle() | |||
.SetControl(IDS_CTRL_SPINLIST) .SetUserAttribute(GX_IDS_UA_SPINBOUND_MIN, "0") .SetUserAttribute(GX_IDS_UA_SPINBOUND_MAX, "4") .SetUserAttribute(GX_IDS_UA_SPINBOUND_WRAP, "1") .SetUserAttribute(GX_IDS_UA_SPINSTART, "0") .SetChoiceList("one two three four five") |
|||
); |
You can determine the index of the selected choice in the cell with:
int nIndex = _ttoi(GetValueRowCol(nRow, nCol)); |