Styles Architecture
As you probably noticed in the overview of Objective Grid classes, styles are the key to the display of the grid and also define most of its behavior. Let's proceed by taking a look at how the styles architecture is implemented. We can then discuss how it ties in with the drawing of the grid.
Style Implementation
The CGXStyle class contains all the information necessary for formatting a cell. A style consists of several attributes, such as text color, borders, control type, and font. All of these styles can be modified by the end user via the CGXStyleSheet dialog.
A very important feature of CGXStyle is support for combining style objects. For example, you can copy only those attributes from one style to a second style that are not initialized in the second style. Objective Grid uses this feature to enable a kind of inheritance. By specifying a base style, you can tell Objective Grid that it should inherit attributes from a base style at run time.
Attributes in the CGXStyle class are combined with an include bit. This include bit is TRUE when an attribute is initialized. If it is FALSE, the attribute is not initialized. When drawing the grid, Objective Grid fills up all uninitialized attributes of the cell style object with values inherited from the base styles.
CGXStyle also supports user-defined style attributes. You can also extend the CGXStyle class with additional attributes. The end user can change these attributes through the CGXStyleSheet. Each CGXStyle object maintains a map of user attributes and provides a method to change their values.
The following attributes are provided by the CGXStyle class:
*Value with the cell's text
*Control ID
*Base style
*Text color
*Cell pattern and color using a LOGBRUSH object
*Borders with LOGPEN objects
*Font as a CGXFont object
*Horizontal alignment
*Read-only state
*Enabled/disabled state (disabled cells cannot become the current cell)
*Auto-size feature (this allows a cell to grow automatically when the user enters large text)
*Maximum length of the text
*3D-effect (raised, inset, normal)
*Vertical scrollbar specifies if a multiline edit control should display a vertical scrollbar
*Wrap text (also known as Wordbreak)
*Allow enter specifies if the edit control should insert a new line when the user presses Enter
*Choice list specifying the list of items for a combo-box or list-box, or the text for radio-buttons, push buttons, or checkboxes
*Tri-state property for check boxes
*A user-defined item data pointer, similar to the item data pointer in list boxes.
Style objects are created for those cells that should be drawn and initialized at run time in the CGXGridCore member function ComposeStyleRowCol(). ComposeStyleRowCol() takes a row, a column, and a pointer to a style object as arguments. ComposeStyleRowCol() first calls the GetStyleRowCol() function to get any cell-specific style attributes. ComposeStyleRowCol() adds to the style object any inherited attributes from the row, the column, and the entire grid. Finally, the styles map is checked for any base styles.
The following simplified version of ComposeStyleRowCol() shows how styles are composed.
void CGXGridCore::ComposeStyleRowCol(ROWCOL nRow, ROWCOL nCol,
CGXStyle* pStyle)
//Copy the cell style first
GetStyleRowCol(nRow, nCol, *pStyle, gxCopy);
//Apply the row style next
GetStyleRowCol(nRow, 0, *pStyle, gxApplyNew, -1);
//Apply the column style
GetStyleRowCol(0, nCol, *pStyle, gxApplyNew, -1);
//Apply the table style
GetStyleRowCol(0, 0, *pStyle, gxApplyNew, -1);
//Inherit any base styles
//Finally apply the standard style
pStyle->ChangeStyle(*m_pStyleStandard, gxApplyNew);
You may be wondering why all of the access to styles is controlled by one function. This technique allows the developer to bind or dynamically tie the grid object to data such as a database or a live data feed. All the developer has to do is override the virtual CGXGridCore::GetStyleRowCol() function. By centralizing all style operations in one virtual function, the developer can modify the grid in any way imaginable at run time.
What if the developer wants the user to be able to dynamically modify the data? The grid provides a virtual function CGXGridCore::StoreStyleRowCol() that is called before data is stored. By overriding this function, the developer can intercept the end user's changes.
CGXGridCore - Styles Interface
The following CGXGridCore member functions define the interface for style operations.
Changes a specified base style. All base styles are maintained by the styles-map object.
Changes the column-header-style.
Composes the style for a specific cell by inheriting unspecified attributes from its base styles as explained before.
Determines the base style for a specific column.
Returns the cell value as a string if the cell is text or a number. If the cell is a formula expression, GetExpressionRowCol() will return the expression string.
Determines the base style for a specific row.
Determines the base style for the table.
Determines the value for a cell. If the cell is a formula expression, the result of the evaluated expression will be returned.
// Get the number at cell 1,1
double dValue = atof(GetValueRowCol(1,1));
// Get the string to cell 1,2
CString sValue = GetValueRowCol(1,2);
Changes the row-header-style.
Changes the standard-style settings.
Lets you assign expressions, numbers, or strings to a cell. Objective Grid will interpret the given string and determine if it is a formula expression, date/time string, number, or text.
Applies a given style to the specified range of cells. With SetStyleRange(), you can apply a style to a specific cell, rows, columns, or the entire table.
// Apply style to range of cells
SetStyleRange(CGXRange(1,1,2,2), style);
// Apply style to columns. Cells in the column will be
// filled up with the column’s style.
SetStyleRange(CGXRange().SetCols(1,2), style);
// Apply style to rows. Cells in the row will be
// filled up with the row’s style.
SetStyleRange(CGXRange().SetRows(1), style);
Applies a value to a range of cells.
// Apply a number to cell 1,1
SetValueRange(CGXRange(1,1), 2.22);
// Apply a string to cell 1,2
SetValueRange(CGXRange(1,2), "Hello");
The following are overridable methods:
Called to retrieve the pure style for the specified cell. A pure style does not inherit attributes from its base styles.
Called to store the pure style for the specified cell into the associated data object.
CGXStyle - Class Interface
The CGXStyle class provides accessor methods for all its attributes. The key point is that attributes can be marked as uninitialized. Attributes that are uninitialized will be filled up using base style attributes at run time when drawing the grid.
Each attribute state can be determined or modified with four methods. An example is the text color.
Returns the include bit. This is TRUE if the attribute is initialized and FALSE if it is not.
Changes the include bit.
Returns the text color. The method will assert if the attribute is not marked as initialized.
Changes the text color. This method automatically marks the attribute as initialized.
The various style member functions can be cascaded together to make a very clear and concise block of code. For example, the following code illustrates the formatting of some Objective Grid columns:
SetStyleRange(CGXRange().SetCols(2, 4),
CGXPen().SetStyle(PS_DOTTED) )
The CGXStyle class allows you to operate and combine style objects. The most important member function is ChangeStyle().
Used by Objective Grid to compose style objects.
ChangeStyle() can perform the following operations with style objects:
*gxApplyNew - Apply only new attributes. Only those attributes that are included in the source style and not yet included in the destination style are copied from the source style to the destination style.
*gxOverride - Override included attributes. Those attributes which are included in the source style (whether they are included in the destination style or not) are copied from the source style to the destination style.
*gxCopy - Copy the style. All attributes are copied from the source style to the destination style. Attributes that are not included in the source style will be removed from the destination style object.
*gxExclude - Reset attributes. Attributes that are included in the source style will be reset in the destination style. When the grid draws, the reset attributes will be filled using the base style attribute settings.
SetStyleRange() takes an argument that lets the developer specify the operation to be performed on the style object. This parameter is internally passed to ChangeStyle(). The default argument is gxOverride.
// Next call: only the value will be copied,
// all other attributes will be reset
// Next call: The interior and the font attribute
// will be reset, so that these attributes will be filled
// up with the default background color and font when drawing.
// Next call: The interior and the font attribute
// will be applied to the cell only if they have not
// yet been initialized for the cells: