Objective Grid: Implementing a spin-list control

Article ID: 473
Last updated: 25 Apr, 2018
Article ID: 473
Last updated: 25 Apr, 2018
Revision: 3
Views: 2706
Posted: 12 Jan, 2001
by Meltreger B.
Updated: 25 Apr, 2018
by Meltreger B.

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
BOOL GetControlText(CString& strResult, ROWCOL nRow, ROWCOL nCol, LPCTSTR pszRawValue, const CGXStyle& style);
BOOL GetValue(CString& sResult);
void OnClickedButton(CGXChild* pChild);
void OnInitChildren(ROWCOL nRow, ROWCOL nCol, const CRect& rect);
void Draw(CDC* pDC, CRect rect, ROWCOL nRow, ROWCOL nCol, const CGXStyle& style, const CGXStyle* pStandardStyle);

// Attributes
BOOL m_bUseIndexValue;

// 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

//////////////////////////////////////////////////////////////////
// CspinListControl control

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
//
// Convert the value which is stored in the style object into
// the text which should be displayed in the cell.
//
BOOL CSpinListControl::GetValue(CString& sResult)
{

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
int nIndex = FindStringInChoiceList(sMatch, sResult, m_pStyle->GetChoiceListRef(), FALSE);

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.
return CGXSpinEdit::GetControlText(strResult, nRow, nCol, pszRawValue, style);

}

void CSpinListControl::OnClickedButton(CGXChild* pChild)
{

BOOL bActive = IsActive();

if (!bActive && !OnStartEditing())

return;
SetActive(TRUE);

NeedStyle();

CString strText;
GetValue(strText);

// empty cell, when user pressed alpahnumeric key
if (!IsReadOnly() || !m_pStyle->GetIncludeChoiceList())
{

LONG lValue ;

// style
TCHAR sz[20];

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
// with the same prefix
lValue = FindStringInChoiceList(sMatch, strText, m_pStyle->GetChoiceListRef(), FALSE);

}

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);
OnModifyCell();
SetSel(0, -1);

}

// eventually destroys and creates CEdit with appropriate window style
if (!bActive)

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
CRect rectBtn;
rectBtn.IntersectRect(rect, CRect(rect.right-2-nEditBtnWidth, rect.top, rect.right-1, rect.bottom-1));

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
// are also visible for inactive cells.
void CSpinListControl::Draw(CDC* pDC, CRect rect, ROWCOL nRow, ROWCOL nCol, const CGXStyle& style, const CGXStyle* pStandardStyle)
{

pStandardStyle, style;
CGXSpinEdit::Draw(pDC, rect, nRow, nCol, style, pStandardStyle);

// Normal, spin-buttons are not drawn for inactive cells.
// The following code forces that they will be drawn.
if (!Grid()->IsCurrentCell(nRow, nCol))
{

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));

This article was:   Helpful | Not helpful
Report an issue
Article ID: 473
Last updated: 25 Apr, 2018
Revision: 3
Views: 2706
Posted: 12 Jan, 2001 by Meltreger B.
Updated: 25 Apr, 2018 by Meltreger B.

Others in this category