Professional UI Solutions
Site Map   /  Register
 
 
 

Prof-UIS Grid Brief Overview

The documentation on Prof-UIS includes detailed information on the classes of the grid control.

The Prof-UIS grid control is implemented as an instance of the CExtGridWnd class. It manages cell objects, which are instances of the CExtGridCell class (or a class derived from it). The grid control itself does not keep cell objects. It manages them by means of the data provider component, which is an instance of a class derived from CExtGridDataProvider. The CExtGridWnd class just provides a visual interface for cell objects which are accessed through the data provider. The class hierarchy for CExtGridWnd is shown below:

CWnd -> CExtScrollWnd -> CExtScrollItemWnd -> CExtGridBaseWnd -> CExtGridWnd

The following sections are a brief outline of these classes.

CExtScrollWnd

The CExtScrollWnd class implements an abstract window that supports scrolling. Two build-in scroll bars are part of the non-client area of the window. Of course, you can use scroll bar controls instead. CExtScrollWnd is a base class for such Prof-UIS controls as the image editor (CExtImageEditWnd) and color palette (CExtColorPaletteWnd). It defines a set of OnSw...() virtual methods, which may be overridden to implement any kind of scrollable control. Unlike the CScrollView class in MFC, the only scrolling units used in CExtScrollWnd are pixels (the MM_TEXT mapping mode, which GDI uses to convert logical coordinates into the appropriate device coordinates of GDI device context).

Frequently Asked Questions about CExtScrollWnd

How to use scroll bar controls within a CExtScrollWnd-derived class instead of built-in scroll bar areas?

Just create each scroll bar window as a child of the CExtScrollWnd based control and override the CWnd::GetScrollBarCtrl virtual method which should return a pointer to the appropriate scroll bar window. The CExtScrollWnd class supports managing the layout of its child windows. This is based on the MFC's CWnd::RepositionBars method and on handling WM_SIZEPARENT message in the child windows. For example, the CExtScrollBar class handles this message and aligns itself along the specified side of the CExtScrollWnd-based window.

What are the benefits of using scroll bar windows instead of built-in scroll bar areas?

The scroll bar windows may be useful when you need some non-standard layout inside the CExtScrollWnd-based window. For example, Microsoft Word has a few buttons (Normal View, Web Layout View, etc.) next to the left scroll arrow button of the horizontal scroll bar. Scroll bar windows allow you to fully control their positions inside the parent scrollable window.

How does Prof-UIS make the use of scroll bar windows inside CExtScrollWnd-based controls easier?

The CExtScrollWnd class uses an algorithm responsible for recalculating the window's layout, which is based on the OnSwRecalcLayout virtual method. The default implementation of this algorithm uses the MFC's WM_SIZEPARENT internal message and CWnd::RepositionBars method. The CExtScrollBar class is able to reflect WM_SIZEPARENT and reposition itself inside its parent scrollable control window automatically. Being used as the horizontal and vertical scrollbars, two instances of the CExtScrollBar class can set their size and positions dependently on each.

The CExtScrollBar class also supports two properties of the HWND type: the first is assumed to be a window located before the scroll bar (at the top of the vertical scroll bar or at the left of the horizontal one) and the second is a window located after the scroll bar (at the bottom of the vertical scroll bar or at the right of the horizontal one). The CExtScrollBar class automatically repositions these two associated windows and hides them when there is not enough room.

CExtScrollItemWnd

The CExtScrollItemWnd class implements a scrollable window which supports four scrolling strategies in horizontal and vertical directions independently:

  • no scrolling
  • pixel-by-pixel scrolling
  • item-by-item scrolling
  • virtual scrolling

The no scrolling strategy disables scrolling at all. The pixel-by-pixel scrolling, for example, is used in the standard list view control in the report/table mode in the horizontal direction. It is the only strategy supported by the CExtScrollBar class. The item-by-item scrolling is used in the standard list view control in the report/table mode in the vertical direction.

The virtual scrolling strategy is used when two scrolling states should be compared to find out which data columns and/or rows should be hidden or shown in the client area. This feature is used by the grid requires cacheable data for effective operations with any kind of external data sources. The CExtScrollItemCacheInfo class allows you to detect any scroll event that is or is not triggered by resizing the control.

CExtGridBaseWnd

The CExtGridBaseWnd class implements an abstract grid control. It manages the window's client area (except scroll bar areas) to organize the layout of inner (or data) cells and outer (or header) cells. The base grid window also handles mouse and keyboard events and redirects them into the calls of OnGbw...() virtual methods. It supports the handling of focus and selection events, tool tips, and contents pop-up windows.

The selection model is implemented as a set of rectangular areas which constitute the selection region. The base grid window allows the user to select only full rows or columns. It supports the Microsoft Excel-like selection with or without overlapped selection rectangles.

Besides the base grid control defines a set of methods for handling mouse and keyboard events, activating in-place cell editor windows, managing column/row resizing, drag-and-dropping, and sorting.

Absolutely like the CExtScrollItemWnd class, the base grid window "knows" nothing about the contents of its inner (data) cells. It also operates an abstract two-dimensional array of items using the scrolling strategies provided by the CExtScrollItemWnd class. But it extends the functionality of CExtScrollItemWnd by implementing the hit-test algorithm, and painting the default cell background and gridlines.

CExtGridWnd

The CExtGridWnd class implements a grid window that is able to manage data of different types. It extends the CExtGridBaseWnd class by implementing displaying and editing data. The grid control uses the CExtGridDataProvider-derived class as a data provider component to access cell objects. A reference to the data provider object is returned by the OnGridQueryDataProvider method. There are two useful implementations of the data provider component. The first is the CExtGridDataProviderMemory class, which completely manages the two-dimensional array of cell objects and which is used by the grid control by default. The second is the CExtGridDataProviderRecordset abstract class, which is a base class for the cacheable data binding.

Each cell object is an instance of the CExtGridCell class or a class derived from it. The CExtGridCell class only defines a set of virtual methods for implementing cells that have different data types and the editing behavior. There are four useful cell classes: CExtGridCellVariant, CExtGridCellColor, CExtGridCellStringDM, and CExtGridCellHeader.

The CExtGridCellVariant class implements the cell object based on the OLE VARIANT data type. It is not reasonable to use variant cells that contain BSTR values if the grid control contains too much rows and/or columns: use CExtGridCellStringDM instead. The CExtGridCellStringDM class implements the cell object that keeps a text value of any size. The CExtGridCellHeader class is used for outer (header) cells and is based on CExtGridCellStringDM. Unlike the string cell, the header cell stores a few numeric values specifying minimum, maximum, and current column widths and row heights. The CExtGridCellColor class keeps any COLORREF value or an index of one of the Windows system colors.

Frequently Asked Questions about CExtGridWnd

Some grid controls hide horizontal and/or vertical scrollbars when there is enough room for all items in the client area. But some do not hide their scrollbars and leave them visible and disabled. How is it implemented in the Prof-UIS grid control?

This feature is available in any Prof-UIS scrollable control. The CExtScrollWnd class defines the OnSwCanAutoHideScrollBar virtual method, which returns a boolean value specifying whether the scroll bar can be hidden.

Some scrollable controls perform data scrolling immediately after the user starts to drag the scroll box (thumb). But sometimes it's handy to disable such scrolling, especially when the control is based on a slow external data source. Is this feature supported in the Prof-UIS grid control?

This feature is provided by the CExtScrollWnd class. Just override the OnSwQueryThumbTrackEnabled method and return false if you do not want immediate scrolling when the user is dragging the thumb.

What do OnSw...(), OnSiw...(), OnGbw...() and OnGrid...() stand for?

Most Prof-UIS classes contain virtual methods available for overriding. Each virtual method name has a unique prefix. The OnSw...() methods are defined in the CExtScrollWnd class. The OnSiw...() methods are defined by the CExtScrollItemWnd class. The OnGbw...() methods are defined in the CExtGridBaseWnd class. The OnGrid...() methods are defined in the CExtGridWnd class.

How to define a custom cell type?

The cell objects should use CExtGridCell as their base type and be enabled for dynamic creation through the MFC's runtime class information mechanism. You should also add support for clone operations by declaring the IMPLEMENT_ExtGridCell_Clone preprocessor definition. Here is a sample declaration and implementation of such a class:

class CMyCustomCell : public CExtGridCell {
public:
      DECLARE_DYNCREATE( CMyCustomCell );
      IMPLEMENT_ExtGridCell_Clone( CMyCustomCell, CExtGridCell );
      CMyCustomCell(
            CExtGridDataProvider * pDataProvider = NULL
            )
            : CExtGridCell( pDataProvider )
      {
      }
      virtual ~CMyCustomCell()
      {
      }
#ifdef _DEBUG
      virtual void AssertValid() const
      {
            CExtGridCell::AssertValid();
      }
      virtual void Dump( CDumpContext & dc ) const
      {
            CExtGridCell::Dump( dc );
      }
#endif // _DEBUG
      virtual void Serialize( CArchive & ar )
      {
            CExtGridCell::Serialize( ar );
            if( ar.IsStoring() )
            {
  ...
            }
            else
            {
  ...
            }
      }
      virtual bool IsEmpty() const
      {
            return CExtGridCell::IsEmpty();
      }
      virtual void Empty()
      {
            CExtGridCell::Empty();
      }
      virtual void Assign( const CExtGridCell & other )
      {
            CExtGridCell::Assign( other );
      }
}; // class CMyCustomCell
 
IMPLEMENT_DYNCREATE( CMyCustomCell, CExtGridCell );

How to initialize a cell object of required type inside the grid control?

The grid control works with a two-dimensional array of cell objects through the data provider component. Each position in this array may be either NULL or contain an instance of the CExtGridCell class or a class derived from it. You can insert cell objects into the grid control with any of the CExtGridWnd::GridCellSet overloaded methods. These methods use a pointer to the existing cell object for creating cloned copies at specified locations. You may use any of the CExtGridWnd::GridCellGet overloaded methods to initialize an instance of the cell object by specifying any required runtime class.

How to disable cell editing and how to disable cell editing in a custom CExtGridCell-derived class?

The most convenient way is to override the OnGbwBeginEdit overridable and return false. You can also disable cell editing in any CExtGridCell-derived class by overriding the OnInplaceControlCreate method - just return NULL in it.

How to verify text input in the in-place editor on-the-fly?

By default, cell objects use the standard single-line edit control as an in-place cell editor window. The CExtGridCell::OnInplaceControlTextInputVerify virtual method is called when the user is editing the text in this control. The bEndEdit parameter of this method specifies whether the text verification is last (after the user has pressed the VK_RETURN key). This mechanism allows you to verify editing on-the-fly or when VK_RETURN has been pressed.

How effective the dynamic memory management implemented by the memory data provider?

The memory data provider is implemented in the CExtGridDataProviderMemory class and used by the grid control by default. This component uses several instances of the standard COM IMalloc interface for allocating the memory. The cell object allocations, dimension allocations, and string allocations are managed separately by different allocators. You may also use an instance of the memory allocator returned by the CoGetMalloc function of COM API. But the memory data provider uses the internal Prof-UIS implementation of the IMalloc interface in the CExtAlloc class, which supports the blocked allocations. This makes memory allocation and deallocation much faster and efficient. The CExtGridCell class contains the new and delete operators based on a pointer to the IMalloc interface. This makes any cell object enabled for the allocation in the block-based memory or in the linked-list-based memory managed by the CExtAlloc class.

How to make a cell read only?

The CExtGridCell class contains a set of cell styles which are accessible with the GetStyle and ModifyStyle methods. Just add the __EGCS_READ_ONLY style to the cell object. This will make its in-place editor window read only. Another way is to override the OnInplaceControlCreate method in the custom cell class and return a HWND handle of the in-place editor window which "knows" that the cell is read only.

How to monitor the column/row sorting events and optionally prevent sorting?

The data sorting is performed by the CExtGridWnd::GridSortOrderSetup virtual method, which either sets new sorting rules or modifies the current rules. You can customize the sorting behavior by overriding this method. Another way to control data sorting is to use custom cell types in the outer (header) areas and override the CExtGridCell::OnClick virtual method, which invokes the wndGrid.OnGridTrackCellMousePressing method for further performing sorting or drag-and-dropping.

How to catch the cell change event?

To catch the cell change event, you need to use your own class(es) derived from CExtGridCell. The CExtGridCell::TextSet virtual method is called when the in-place editing is complete. Besides there are two other methods that may fire the cell change event: CExtGridCell::Assign and CExtGridCell::Serialize.

How to compare two cells of different types?

The CExtGridCell::Compare virtual method performs comparison of one cell with another. The default implementation in the CExtGridCell class converts both cells to OLE VARIANT values and then compares them.

How to implement the cell that stores only numeric values?

The CExtGridCellVariant class implements the cell which keeps the OLE VARIANT value. To store numeric values, use a VARIANT of VT_I4 type.

How to specify the cell location in the methods like OnGbwBeginEdit?

The grid control uses four numeric parameters to identify the location of any cell object. The column and row types are used to specify which area the given cell belongs to: inner or outer. The type can be a negative, positive, or zero value. The zero value specifies the inner area. A negative value specifies the left or top outer area. A positive value specifies the right or bottom outer area. The column and row indices are used to locate the cell inside the inner or outer area. If both column and row type values are set to zero, the column and row indices are specifying the cell inside the inner area of the grid control. For example,

//the inner cell
CExtGridCell * pCell = m_wndGrid.GridCellGet( 
                        5,  // Column index 
                        10, // Row index
                        0,  // Column type
                        0,  // Row type
                        RUNTIME_CLASS( CExtGridCellStringDM ) 
                        );
//the outer cell at left (in left header column 0)
CExtGridCell * pCell = m_wndGrid.GridCellGet( 
                        0,  // Column index 
                        10, // Row index
                        -1,  // Column type
                        0,  // Row type
                        RUNTIME_CLASS( CExtGridCellStringDM ) 
                        );
Back To Top Other Articles...