Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Parametrization of CListCtrl’s Descendant Class in MDI Templates of CMultiDocTemplate Function

0.00/5 (No votes)
2 Jul 2009 1  
The demonstration of the possibility of parametrization of the non parametrized constructors of the MFC application's document templates.

Introduction

In the previous article, we showed the modified CListCtrl classes, displayed on the insets of CFormView’s descendants. However on different insets, the controls were displayed identically. Therefore it would be desirable to have different variants of descendants of CListCtrl on the forms of dialogs. For example, as shown in Fig. 1.

Tables.jpg - Click to enlarge image

Fig. 1. Different variants of descendants of CListCtrl class on the forms of dialogs.

To attain this, it is possible to offer a few variants of decision. For example:

  1. To write the own variant of CMultiDocTemplate, using of parametrized constructors of necessary classes. But this way does not seem to be such a necessity, it can be reserved for emergencies.
  2. To create a few descendants of classes in-use in CMultiDocTemplate, differing only on internal parameterization. This method is simpler, but more bulky. If we will wish to use hundreds of tables in the program, as it is done, for example, in the Russian accountant program «1C», version 7.7, written on MFC, this method already will not show oneself well.
  3. To pass with MFC on Qt, as some programmers advise sometimes. But, personally it does not suit me.
  4. To make an attempt to pass a parameter to the non parametrized constructor unobviously. We will say so. We will assume, in the code of class CMainApp, we have:
    CMultiDocTemplate *pDocTemplate;
    
    pDocTemplate = new CMultiDocTemplate(
        IDR_MAINTYPE,
        RUNTIME_CLASS(CMainDoc),
        RUNTIME_CLASS(CTableFrame),   // Custom MDI child frame
        RUNTIME_CLASS(CMainView)
        );
    
    AddDocTemplate(pDocTemplate);

    And we want to pass the parameter UINT nTable (number of table) in a class CTableFrame. Doing obvious appearance of it is impossible, because the function CMultiDocTemplate calls the not parametrized constructor CTableFrame::CTableFrame() even if there is a parametrized constructor. But if you look closely at the macro RUNTIME_CLASS, you will see that:

    #define RUNTIME_CLASS(class_name) 
    	((CRuntimeClass*)(&class_name::class##class_name))

    In the structure CTableFrame::classCTableFrame for our purpose it is possible to avail of the variable – member classCTableFrame.m_pNextClass, on the condition that we will not use the list of the templates by means of function AddDocTemplate(pDocTemplate), and instead we will simply define the array of the templates. So, we can pass the necessary parameter nTable:

    CTableFrame::classCTableFrame.m_pNextClass = 
    		reinterpret_cast<CRuntimeClass *>(nTable);

    This line of code must be located before the line:

    CMultiDocTemplate *pDocTemplate;

    To smuggle out of this variable in the class CTableFrame will do the reverse operation:

    /////////////////////////////////////////////////////////////////////////////
    // CTableFrame construction
    /////////////////////////////////////////////////////////////////////////////
    CTableFrame::CTableFrame() {
      m_nTable = (UINT) reinterpret_cast<DWORD>(classCTableFrame.m_pNextClass);
    }

    Through this, we got the quasi parametrized constructor CTableFrame::CTableFrame(). The analogical procedure can be done for other classes of the function CMultiDocTemplate.

    This method is fully capable of working and it would be used, if it were not for another method of non-parametrized constructor, which is evident and simple enough, but for some reason not occurring at once.

  5. Passing of parameters in templates of classes by global variables of application. Only instead of variable UINT nTable we will take advantage of enumeration, defined in the Main.h for comfort of manipulation of plenty of tables:
  6. /////////////////////////////////////////////////////////////////////////////
    // ETABLE
    /////////////////////////////////////////////////////////////////////////////
    enum ETABLE {
        e_NULL = 0,  // Empty Form Index
        e_First,
        e_Second,
        e_Third,
        e_MAX
    };

    etc. This is enough for our demonstration purposes. Later we define a global variable ETABLE m_eTable in Main.h, which by default is equal to e_NULL. For an example, we will take advantage of the functional handler:

    /////////////////////////////////////////////////////////////////////////////
    // OnFileNew
    /////////////////////////////////////////////////////////////////////////////
    void CMainApp::OnFileNew() {
      m_eTable = (ETABLE) ((UINT) m_eTable + 1);
    
      if(m_eTable >= e_MAX){
        _M("No data for new table!");
        return;
      }
    
      CWinApp::OnFileNew();
    }  // OnFileNew

    To get access to this variable presents no complications. For example, in the class CMainView:

    /////////////////////////////////////////////////////////////////////////////
    // CMainView construction
    /////////////////////////////////////////////////////////////////////////////
    CMainView::CMainView() : CFormView(CMainView::IDD){
      //*** Main Application Pointer
      CMainApp *pMainApp = reinterpret_cast<CMainApp *>(AfxGetApp());
    
      if(!pMainApp){
        _M("CMainView: Empty object of the CMainApp class!");
        return;
      }
    
      //*** Table Id
      m_eTable = pMainApp->m_eTable;
    
      //*** The Meta Table Structure
      m_MetaTable = pMainApp->m_aMetaTable[m_eTable];
    }  // CMainView

    Here parameters ETABLE m_eTable and META_TABLE m_MetaTable are defined in MainView.h. The structure META_TABLE is defined in StdAfx.h:

    //*** The Meta Table Structure
    typedef struct {
        TCHAR *szTblName;  	// Table name
        DWORD dwStyle;  	// Table style
        DWORD dwExStyle;  	// Extended table style
        RECT *pFrmRect;  	// Frame rectangle pointer
        RECT *pViewRect;  	// View rectangle pointer
        CFont *pHdrFont;  	// Table header font pointer
        CFont *pListFont;  	// Table list font pointer
        UINT nHdrHeight;  	// Table header height
        UINT nListHeight;  	// Table list height
        UINT nColCount;  	// Table header columns count
        UINT nRowCount;  	// Table list row count
        TCHAR **apRowText;  	// Table rows text array
        META_HEADER *apMetaHeader;  // Meta table header pointer
    } META_TABLE;

    The structure META_HEADER is defined there too:

    //*** The Meta Table Header Structure
    typedef struct {
        TCHAR *szHdrName;  	// Column name
        // TCHAR *szFormat;  	// Table list data format
        DWORD nAdjust;  	// Text formatting
        UINT nWidth;  		// Column width
    } META_HEADER;

    The example of the use of these parameters is shown in the following code:

    /////////////////////////////////////////////////////////////////////////////
    // OnCreate
    /////////////////////////////////////////////////////////////////////////////
    int CMainView::OnCreate(LPCREATESTRUCT pCS){
      if(CFormView::OnCreate(pCS) == -1)
          return -1;
    
      //*** Create table
      CListCtrlEx *pTable = new CListCtrlEx;
        
      if(!pTable){
        _M("Empty and CListCtrlEx object!");
        return -1;
      }
    
      //*** CListCtrlEx initialization
      if(!pTable->Create(m_MetaTable.dwStyle, *m_MetaTable.pViewRect, this, m_eTable)){
        _M("Failed to create and CListCtrlEx object!");
        return - 1;
      }
    
      //*** Sets extended table style
      pTable->SetExtendedStyle(m_MetaTable.dwExStyle);
    
      //*** Creates and table header
      CHeaderCtrlEx *pHeader = new CHeaderCtrlEx;
        
      if(!pHeader){
        _M("Empty CHeaderCtrlEx object!");
        return -1;
      }
        
      //*** The CHeaderCtrlEx handle
      HWND hHeader = pHeader->m_hWnd;
      //HWND hHeader = pHeader->GetSafeHwnd();
    
      CHeaderCtrl *pOldHeader = pTable->GetHeaderCtrl();
    
      if(!pOldHeader){
        _M("Empty CHeaderCtrl object!");
        return -1;
      }
        
      //*** The CHeaderCtrl handle
      HWND hOldHeader = pOldHeader->m_hWnd; 
      //HWND hOldHeader = pOldHeader->GetSafeHwnd();
    
      //*** The table header subclassing
      if(!pHeader->SubclassWindow(hOldHeader)){
        _M("Failed to Subclass and table header!");
        return -1;
      }
    
      //*** The structure of and table header cell
      HDITEM HDItem = {0};
    
      HDItem.mask |= HDI_FORMAT;  	// The fmt member is valid
      HDItem.mask |= HDI_TEXT;  	// The pszText and cchTextMax members are valid
      HDItem.mask |= HDI_WIDTH;  	// The cxy member is valid and specifies 
    				// the item's width
    
      HDItem.cchTextMax = MAXITEMTEXT;
    
      //*** Creates table columns
      for(UINT i = 0; i < m_MetaTable.nColCount; i++){
        META_HEADER *apMetaHeader = m_MetaTable.apMetaHeader;
    
        HDItem.pszText = (LPTSTR) apMetaHeader[i].szHdrName;
        HDItem.fmt = apMetaHeader[i].nAdjust;
        HDItem.cxy = apMetaHeader[i].nWidth;
            
        //*** Calls CHeaderCtrlEx::DrawItem
        HDItem.fmt |= HDF_OWNERDRAW;
    
        //*** Sends too message HDM_LAYOUT
        pTable->InsertColumn(
            i, 
            HDItem.pszText,    
            HDItem.fmt, 
            HDItem.cxy
        );
        
        //*** Reset the first column
        if(i == 0)
            pHeader->SetItem(i, &HDItem);
      }
    
      //*** Sets the table rows count in the virtual mode (LVS_OWNERDATA)
      //*** Send messages LVN_GETDISPINFOW & HDM_LAYOUT
      //*** Cals the CListCtrlEx::DrawItem
      pTable->SetItemCount(2*m_MetaTable.nRowCount);  	// REALLY MUST BE 
    						// m_MetaTable.nRowCount
    
      return 0;
    }  // OnCreate

The program shows three list controls designed in various ways by one class. All of them are caused on CTRL-N. Information for these demo lists is presented as static variables in the class CMainApp. In a real application, information will be accepted from some database.

History

  • 2nd July, 2009: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here