Is there a way to specify the format for of cells?
Objective Grid 6.0 introduces the new CGXStyle::SetFormat for number formatting. Check out the class reference on this attribute. When using CGXStyle::SetFormat make sure the value type for the cells that you want to format is GX_VT_NUMERIC. See CGXStyle::SetValueType.
Here is an example how to use this new attribute:
SetExpressionRowCol(nRow, 1, _T("General"));
SetExpressionRowCol(nRow+1, 1, _T("7777.77"));
SetStyleRange(CGXRange(nRow+1, 1), CGXStyle().SetFormat(GX_FMT_GEN).SetPlaces(15));
SetExpressionRowCol(nRow, 2, _T("Fixed"));
SetExpressionRowCol(nRow+1, 2, _T("7777.77"));
SetStyleRange(CGXRange(nRow+1, 2), CGXStyle().SetFormat(GX_FMT_FIXED).SetPlaces(4));
SetExpressionRowCol(nRow, 3, _T("Scientific"));
SetExpressionRowCol(nRow+1, 3, _T("7777.77"));
SetStyleRange(CGXRange(nRow+1, 3), CGXStyle().SetFormat(GX_FMT_FLOAT).SetPlaces(4));
Sometimes, you may be interested in formatting cells on your own without using the CGXStyle::SetFormat attribute. You then have the option to a) override GetStyleRowCol and StoreStyleRowCol or b) to subclass a control from CGXEditControl.
a) You could override the GetStyleRowCol method and change the value in your overridden method:
BOOL CMyGrid::GetStyleRowCol(ROWCOL nRow, ROWCOL nCol, CGXStyle& style,...)
{
if (!CGXGridCore::GetStyleRowCol(nRow, nCol, style, ...)
return FALSE;
if (nCol == yourSpecifcCol)
{
// get value with style.GetValueRef()
char s[20];
wsprint(s, "$%g", value);
style.SetValue(s);
}
return TRUE;
}
BOOL CMyGrid::StoreStyleRowCol(ROWCOL nRow, ROWCOL nCol, const CGXStyle* pStyle,...)
{
if (nCol == yourSpecifcCol && pStyle->GetIncludeValue())
{
CGXStyle style = *pStyle;
CString s = style.GetValueRef();
// remove $ from value
style.SetValue(s);
return CGXGridCore::StoreStyleRowCOl(nRow, nCol, &style,..);
}
return CGXGridCore::StoreStyleRowCOl(nRow, nCOl, pStyle, ...);
}
b) You can derive a class from CGXEditControl and format the value as it should be displayed in the cell. The format can be stored in an user attribute.
If you implement the following class CNumericEditControl:
// header (.h) file
class CNumericEditControl: public CGXEditControl
{
DECLARE_CONTROL(CNumericEditControl)
public:
// Constructor & Destructor
CNumericEditControl(CGXGridCore* pGrid, UINT nID);
protected:
// Overrides
BOOL GetControlText(CString& strResult, ROWCOL nRow, ROWCOL nCol, LPCTSTR pszRawValue, const CGXStyle& style);
BOOL ValidateString(const CString& sEdit);
// Generated message map functions
protected:
//{{AFX_MSG(CNumericEditControl)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// implementation (.cpp) file
///////////////////////////////////////////////////////////////////
// CNumericEditControl control
IMPLEMENT_CONTROL(CNumericEditControl, CGXEditControl)
CNumericEditControl::CNumericEditControl(CGXGridCore* pGrid, UINT nID)
: CGXEditControl(pGrid, nID)
{
}
BEGIN_MESSAGE_MAP(CNumericEditControl, CGXEditControl)
//{{AFX_MSG_MAP(CNumericEditControl)
//}}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 CNumericEditControl::GetControlText(CString& sResult, ROWCOL nRow, ROWCOL nCol, LPCTSTR pszRawValue, const CGXStyle& style)
{
// base class version will store current text in sResult
if (!CGXEditControl::GetControlText(sResult, nRow, nCol, pszRawValue, style))
return FALSE;
if (!sResult.IsEmpty())
{
// gather information
// ... value
double d = atof(style.GetValueRef());
// ... format
CString sFormat;
style.GetUserAttribute(IDS_UA_NUMEDITFORMAT, sFormat);
// Now, format the text
_stprintf(sResult.GetBuffer(128), sFormat, d);
sResult.ReleaseBuffer();
}
return TRUE;
}
BOOL CNumericEditControl::ValidateString(const CString& sEdit)
{
// cycle through string and check each character if it is a digit
for (int n = 0; n < sEdit.GetLength(); n++)
{
if (!isdigit(sEdit[n]) && sEdit[n] != '.')
return FALSE;
}
return TRUE;
}
You can register the control and user attribute in the OnInitialUpdate() routine of your grid class
// Register all controls and user attributes for the view
// IDS_CTRL_NUMEDIT and IDS_UA_NUMEDITFORMAT are string resource
// ids you have to add to your application.
RegisterControl(IDS_CTRL_NUMEDIT, new CNumericEditControl(this, IDS_CTRL_NUMEDIT));
GetParam()->GetStylesMap()->AddUserAttribute(IDS_UA_NUMEDITFORMAT);
and later apply it to cells with
SetStyleRange(CGXRange(4,3,10,5),
CGXStyle()
.SetControl(IDS_CTRL_NUMEDIT)
.SetUserAttribute(IDS_UA_NUMEDITFORMAT, "%.3f")
.SetHorizontalAlignment(DT_RIGHT)
);
The user can also change the numeric formatting of cells with the Format|Cells dialog if he clicks on the “User” property sheet.
See also the date control in the dbfbrows sample. It implements a date control for international dates.
If you want that the full number is displayed, when the cell is in edit mode, you should also override SetValue(). For example if the cell is formatted to show 2 decimal place. When user input 1.23456 and hit enter, the cell should show 1.23. When the user edit that cell (by F2 or click on the text in the cell), 1.23456 (the full number) should be displayed.
void CNumericEditControl::SetValue(LPCTSTR pszRawValue)
{
// Convert the value to the text which should be
// displayed in the current cell and show this
// text.
if (m_hWnd)
SetWindowText(pszRawValue);
}