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:
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.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.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.
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.
| You must Sign In to use this message board. | |||||
|
|||||