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






4.33/5 (3 votes)
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.
To attain this, it is possible to offer a few variants of decision. For example:
- 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. - 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. - To pass with MFC on Qt, as some programmers advise sometimes. But, personally it does not suit me.
- 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 classCTableFrame
. Doing obvious appearance of it is impossible, because the functionCMultiDocTemplate
calls the not parametrized constructorCTableFrame::CTableFrame()
even if there is a parametrized constructor. But if you look closely at the macroRUNTIME_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 – memberclassCTableFrame.m_pNextClass
, on the condition that we will not use the list of the templates by means of functionAddDocTemplate(pDocTemplate)
, and instead we will simply define the array of the templates. So, we can pass the necessary parameternTable
: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 functionCMultiDocTemplate
.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.
- 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:
/////////////////////////////////////////////////////////////////////////////
// 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