Click here to Skip to main content
6,594,432 members and growing! (14,706 online)
Email Password   helpLost your password?
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 dialogs

By Emery Emerald

The demonstration of using of general-purpose MDI interface in MFC table forms.
C++ (VC6), Windows (WinXP, Win2003), Win32, Visual Studio, MFC, Dev
Posted:12 Jul 2009
Views:3,464
Bookmarked:12 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
2 votes for this article.
Popularity: 1.51 Rating: 5.00 out of 5

1

2

3

4
2 votes, 100.0%
5

Introduction

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.

Tables.jpg

Fig. 1. Modified lists on the changed forms with the elements of user interface.

1. Scrollbars

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

2. ON_WM_SIZE message’s handlers for main and child frames

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

3. Tabs on main frame

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.

4. Menu

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.

5. Toolbars (are docked side by side)

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

6. Hotkeys

For the call of our tables the following keys are appointed:

F10 – First table; F11 – Second table; F12 – Third table.

7. Common processing of table forms commands

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Emery Emerald


Member

Occupation: Software Developer
Location: Ukraine Ukraine

Other popular List Controls articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
  (Refresh) 
-- There are no messages in this forum --

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 12 Jul 2009
Editor:
Copyright 2009 by Emery Emerald
Everything else Copyright © CodeProject, 1999-2009
Web17 | Advertise on the Code Project