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.
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:
- 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),
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::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.
- 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:
enum ETABLE {
e_NULL = 0,
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:
void CMainApp::OnFileNew() {
m_eTable = (ETABLE) ((UINT) m_eTable + 1);
if(m_eTable >= e_MAX){
_M("No data for new table!");
return;
}
CWinApp::OnFileNew();
}
To get access to this variable presents no complications. For example, in the class CMainView
:
CMainView::CMainView() : CFormView(CMainView::IDD){
CMainApp *pMainApp = reinterpret_cast<CMainApp *>(AfxGetApp());
if(!pMainApp){
_M("CMainView: Empty object of the CMainApp class!");
return;
}
m_eTable = pMainApp->m_eTable;
m_MetaTable = pMainApp->m_aMetaTable[m_eTable];
}
Here parameters ETABLE m_eTable
and META_TABLE m_MetaTable
are defined in MainView.h. The structure META_TABLE
is defined in StdAfx.h:
typedef struct {
TCHAR *szTblName;
DWORD dwStyle;
DWORD dwExStyle;
RECT *pFrmRect;
RECT *pViewRect;
CFont *pHdrFont;
CFont *pListFont;
UINT nHdrHeight;
UINT nListHeight;
UINT nColCount;
UINT nRowCount;
TCHAR **apRowText;
META_HEADER *apMetaHeader;
} META_TABLE;
The structure META_HEADER
is defined there too:
typedef struct {
TCHAR *szHdrName;
DWORD nAdjust;
UINT nWidth;
} META_HEADER;
The example of the use of these parameters is shown in the following code:
int CMainView::OnCreate(LPCREATESTRUCT pCS){
if(CFormView::OnCreate(pCS) == -1)
return -1;
CListCtrlEx *pTable = new CListCtrlEx;
if(!pTable){
_M("Empty and CListCtrlEx object!");
return -1;
}
if(!pTable->Create(m_MetaTable.dwStyle, *m_MetaTable.pViewRect, this, m_eTable)){
_M("Failed to create and CListCtrlEx object!");
return - 1;
}
pTable->SetExtendedStyle(m_MetaTable.dwExStyle);
CHeaderCtrlEx *pHeader = new CHeaderCtrlEx;
if(!pHeader){
_M("Empty CHeaderCtrlEx object!");
return -1;
}
HWND hHeader = pHeader->m_hWnd;
CHeaderCtrl *pOldHeader = pTable->GetHeaderCtrl();
if(!pOldHeader){
_M("Empty CHeaderCtrl object!");
return -1;
}
HWND hOldHeader = pOldHeader->m_hWnd;
if(!pHeader->SubclassWindow(hOldHeader)){
_M("Failed to Subclass and table header!");
return -1;
}
HDITEM HDItem = {0};
HDItem.mask |= HDI_FORMAT;
HDItem.mask |= HDI_TEXT;
HDItem.mask |= HDI_WIDTH;
HDItem.cchTextMax = MAXITEMTEXT;
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;
HDItem.fmt |= HDF_OWNERDRAW;
pTable->InsertColumn(
i,
HDItem.pszText,
HDItem.fmt,
HDItem.cxy
);
if(i == 0)
pHeader->SetItem(i, &HDItem);
}
pTable->SetItemCount(2*m_MetaTable.nRowCount);
return 0;
}
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