![]() |
Desktop Development »
List Controls »
ListView controls
Beginner
License: The Code Project Open License (CPOL)
Menu, tabs, toolbars, scrollbars, hotkeys, frames resizing and the ON_COMMAND_RANGE handler for classes derived from the CListCtrl on the CFormView dialogsBy Emery EmeraldThe demonstration of using of general-purpose MDI interface in MFC table forms. |
C++ (VC6), Windows (WinXP, Win2003), Win32, Visual Studio, MFC, Dev
|
||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
A theme of the general-purpose MFC interface is neither new nor difficult. However, somehow it demands to call to attention itself, at first because without it is impossible to move farther in programming, and secondly, in connection with that for the real application, which we plan to carry out on the base of these examples, some adaptation is however required to our project. Usually demonstrated examples are programmed abstractly and in general, as a rule, they are torn off from workings applications. We will do our demonstrations as «concrete», and inasmuch as it is really necessary in, having an ultimate goal to get practical application.
We continue to develop our previous project. We will add now some standard elements of interface for a management our dialog forms with classes descendant from CListCtrl. Each of these elements does not present the special difficulties, however there are some nuances. As the result we get an example indicated on the fig. 1.
When the forms of lists have a small enough size, the horizontal and vertical scrollbars appear on them. It is the property by default which do not quite need for us and we disconnect them forcedly. For this purpose we use the following code:
/////////////////////////////////////////////////////////////////////////////
// OnInitialUpdate
/////////////////////////////////////////////////////////////////////////////
void CMainView::OnInitialUpdate() {
. . .
//*** Don’t set the Size to {0} else the debug version of the program
// will be wrong!
SIZE Size = {1, 1};
//*** Turns off scroll bars of the form
SetScaleToFitSize(Size);
} // OnInitialUpdate
However for the vertical scrollbar for a list is other problem. It is represented only then when a lot of records suffices in the list. If there are little records and a scrollbar absents, it is a blot on the table, because there is untapped space. The conduct of horizontal scrollbar fully arranges us. Therefore we forcedly will set the vertical scrollbar for a permanent reflection with the code:
/////////////////////////////////////////////////////////////////////////////
// OnCreate
/////////////////////////////////////////////////////////////////////////////
int CMainView::OnCreate(LPCREATESTRUCT pCS){
. . .
//*** Shows the vertical scroll bar always
pTable->ShowScrollBar(SB_VERT);
. . .
} // OnCreate
and analogical code is in the handler:
/////////////////////////////////////////////////////////////////////////////
// OnSize
/////////////////////////////////////////////////////////////////////////////
void CChildFrame::OnSize(UINT nType, int cx, int су){
. . .
//*** Shows the vertical scroll bar always
m_pTable->ShowScrollBar(SB_VERT);
} // OnSize
If we change sizes of child frame, table into him to become inaccessible for the use, because its scrollbars become not visible. Analogical situation, when we change main, parent frame sizes. Child windows in him can also have invisible scrollbars. This situation is observed in the Russian accountant program «1С77». At diminishing of its main window, child windows can become inaccessible for a management by scrollbars. To do away with such situation we process the ON_WM_SIZE messages for parent and child frames.
In child frame have the following code:
/////////////////////////////////////////////////////////////////////////////
// OnSize
/////////////////////////////////////////////////////////////////////////////
void CChildFrame::OnSize(UINT nType, int cx, int cy) {
CMDIChildWnd::OnSize(nType, cx, cy);
//*** Common offset for child frames
int m_nChildFrmOffset = m_pMainApp->m_nChildFrmOffset;
//*** Common width of main frame for border
UINT m_nMainFrmBorders = m_pMainApp->m_nMainFrmBorders;
//*** Current table pointer
m_pTable = m_pMainApp->m_apTable[m_eTable];
if(!m_pTable) {
_M("CChildFrame: Empty a CListCtrlEx object!");
return;
}
//*** Offset & Border size
cx = cx - m_nMainFrmBorders + m_nChildFrmOffset;
cy = cy - m_nMainFrmBorders + m_nChildFrmOffset;
//*** Uses suitable sizes
RECT Rect = {m_nChildFrmOffset, m_nChildFrmOffset, cx, cy};
//*** Changes a window sizes
m_pTable->MoveWindow(&Rect);
//*** Shows the vertical scroll bar always
m_pTable->ShowScrollBar(SB_VERT);
} // OnSize
And in a parent frame we need process not one child window, but all of their great number already. It is arrived at the following code:
/////////////////////////////////////////////////////////////////////////////
// OnSize
/////////////////////////////////////////////////////////////////////////////
void CMainFrame::OnSize(UINT nType, int cx, int cy) {
CMDIFrameWnd::OnSize(nType, cx, cy);
//*** True sizes of the main frame client
int nMainWidth = cx - m_pMainApp->m_nMainFrmBorders;
int nMainHeight = cy - m_pMainApp->m_nClientCtrlsHeight;
//*** Current child frame rectangle
RECT ChildRect = {0}; // For safe change a child rectangle
RECT *pChildRect = NULL;
//*** Table Id
ETABLE eTable = m_pMainApp->m_eTable;
if(!eTable) {
//_M("CMainFrame: No objects is in the application!");
return; // Simply exit
}
//*** Current child frame pointer
CChildFrame **apChildFrame = m_pMainApp->m_apFrame;
CChildFrame *pChildFrame = NULL;
//*** The meta table structure
META_TABLE *aMetaTable = m_pMainApp->m_aMetaTable;
//*** Sizes of child frames
int nChildLeft = 0;
int nChildTop = 0;
int nChildWidth = 0;
int nChildHeight = 0;
//*** Look at the child frame array
for(UINT i = e_NULL; i < e_MAX; i++) {
pChildFrame = apChildFrame[i];
if(!pChildFrame)
continue;
pChildRect = aMetaTable[i].pFrmRect;
if(!pChildRect) {
_M("CChildFrame: Empty a child rectangle!");
return;
}
//*** Sizes of the child frame
nChildLeft = pChildRect->left;
nChildTop = pChildRect->top;
nChildWidth = pChildRect->right - pChildRect->left;
nChildHeight = pChildRect->bottom - pChildRect->top;
//*** Changes sizes and locality of the child frame
if(nChildWidth > nMainWidth) {
ChildRect.left = 0;
ChildRect.right = nMainWidth;
} else if(nChildLeft > nMainWidth - nChildWidth) {
ChildRect.left = nMainWidth - nChildWidth;
ChildRect.right = nMainWidth;
} else {
ChildRect.left = nChildLeft;
ChildRect.right = nChildLeft + nChildWidth;
}
if(nChildHeight > nMainHeight) {
ChildRect.top = 0;
ChildRect.bottom = nMainHeight;
} else if(nChildTop > nMainHeight - nChildHeight) {
ChildRect.top = nMainHeight - nChildHeight;
ChildRect.bottom = nMainHeight;
} else {
ChildRect.top = nChildTop;
ChildRect.bottom = nChildTop + nChildHeight;
}
pChildFrame->MoveWindow(&ChildRect);
}
pChildFrame = m_pMainApp->m_apFrame[eTable];
if(pChildFrame) {
//*** Activates current child frame
pChildFrame->ActivateFrame();
//*** Updates tabs
m_MainTabs.Update();
}
} // OnSize
For organization of tabs on main frame we took advantage of CMDITabs classes from Christian Rodemeyer. It is possible to see their decoration in our program on the fig. 1.
The construction of user submenu presents no problems. Unique nuance, it is automatic creation of elements of Window submenu, which correspond the opened forms of the application. As handlers for these commands of menu we do not write and have not an access to them, at their implementation there are not an update of tabs via the m_MainTabs.Update function. To intercept these system handlers in some wise we plugged the ON_WM_CHILDACTIVATE messages in our map. Here is the handler:
/////////////////////////////////////////////////////////////////////////////
// OnChildActivate
/////////////////////////////////////////////////////////////////////////////
void CChildFrame::OnChildActivate() {
CMDIChildWnd::OnChildActivate();
//*** Saves current table Id in the main application
m_pMainApp->m_eTable = m_eTable;
//*** Updates tabs
m_pMainFrame->m_MainTabs.Update();
}
As a result we get the necessary update of tabs on main frame.
At creation of our toolbar it is disposed by default from a «new line» in relation to created before toolbar. To dock a «new» control to an «old» in one line (side by side) it is possible to take advantage of the third parameter in the function of main frame:
void DockControlBar(CControlBar *pBar, UINT nDockBarID = 0, LPCRECT lpRect = NULL);
However, this method does not work until we will not take advantage of advice of from Kirk Stowell who suggests to cause the RecalcLayout function before the DockControlBar function. We have in the total:
/////////////////////////////////////////////////////////////////////////////
// OnCreate
/////////////////////////////////////////////////////////////////////////////
int CMainFrame::OnCreate(LPCREATESTRUCT pCS){
. . .
//*** To enable dock able control bars in the frame window
EnableDocking(CBRS_ALIGN_ANY);
//*** To enable the control bars to be docked
m_ToolBar.EnableDocking(CBRS_ALIGN_ANY);
m_ToolBar2.EnableDocking(CBRS_ALIGN_ANY);
//*** Causes the control bar to be docked to the frame window
DockControlBar(&m_ToolBar);
//*** Called when the control bars are toggled on or off or when the frame
// window is resized
RecalcLayout();
RECT Rect = {0};
//*** Copies the dimensions of the bounding rectangle of the toolbar to
// the structure pointed to by &Rect
m_ToolBar.GetWindowRect(&Rect);
//*** Docking the toolbars side by side
Rect.left++;
DockControlBar(&m_ToolBar2, AFX_IDW_DOCKBAR_TOP, &Rect);
. . .
} // OnCreate
For the call of our tables the following keys are appointed:
F10 – First table; F11 – Second table; F12 – Third table.
To process our tables by one handler we will add the following macro in the message map:
ON_COMMAND_RANGE(ID_TABLE_NULL, ID_TABLE_MAX, OnTable)
where the OnTable function is determined as:
/////////////////////////////////////////////////////////////////////////////
// OnTable
/////////////////////////////////////////////////////////////////////////////
void CMainApp::OnTable(UINT nTable) {
//*** Calculates m_eTable
m_eTable = (ETABLE) (nTable - ID_TABLE_NULL);
if(m_eTable <= e_NULL || m_eTable >= e_MAX) {
_M("No data is for this table!");
return;
}
//*** Current child frame pointer
CChildFrame *pChildFrame = m_apFrame[m_eTable];
if(pChildFrame) {
//*** Activates current child frame
pChildFrame->ActivateFrame();
//*** Checks the pointer before to call m_MainTabs.Update()
if(!m_pMainFrame) {
_M("CMainApp: Empty a CMainFrame object!");
return;
}
//*** Updates tabs
m_pMainFrame->m_MainTabs.Update();
return;
}
//*** Creates a new child frame with a document
//*
CWinApp::OnFileNew();
//*
//*** Creates a new child frame with a document
//*** Creates a new child frame without a document
//*** Doesn't call CMainView::OnInitialUpdate() and ignores a call of
//* CMainView::SetScaleToFitSize function
//*
/*if(!m_pDocTemplate) {
_M("CMainApp: Empty a CMultiDocTemplate object!");
return;
}
pChildFrame = reinterpret_cast<CChildFrame *>(
m_pDocTemplate->CreateNewFrame(NULL, NULL)
);
//*** Current meta table static structure
META_TABLE MetaTable = m_aMetaTable[m_eTable];
//*** Sets a title of child frame
pChildFrame->SetTitle(MetaTable.szTblName);
//*** Activates current child frame
pChildFrame->ActivateFrame();*/
//*
//*** Creates a new child frame without a document
//*** Checks the pointer before to call m_MainTabs.Update()
if(!m_pMainFrame) {
_M("CMainApp: Empty a CMainFrame object!");
return;
}
//*** Updates tabs
m_pMainFrame->m_MainTabs.Update();
} // OnTable
We will notice that if to eliminate the CWinApp::OnFileNew function, then it is necessary to clean a comment in the code which creates new child frame without a concomitant document. Thus the AddDocTemplate function is possible also to eliminate in the CMainApp::InitInstance function. The commented code is leaved for those programmers who do not wish to work with the classes of documents without an absolute necessity. Unique nuances the noticed here consist of that then is not caused the CMainView::OnInitialUpdate function and the call of the CMainView::SetScaleToFitSize function is ignored.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 12 Jul 2009 Editor: |
Copyright 2009 by Emery Emerald Everything else Copyright © CodeProject, 1999-2009 Web10 | Advertise on the Code Project |