Click here to Skip to main content
Click here to Skip to main content

Flexible Frame using RTSXMLParser

By , 29 Feb 2004
 

Introduction

My other project is developing flexible windows frame based on flexible menu (see previous article RTSXMLParser here).

I chose to reuse RTSXML Parser.

How to Work

After seeing the pattern of window frame working, I decided to build my frames.xml look like this:

<frames>
 <frame id="10000" name="stdframe" split="0" vk="ctrl+f1">
  <view name="rtsview"></view>
 </frame>
 <frame id="10001" name="stdframe" split="1" vk="ctrl+f2">
  <split id="1" cols="2" rows="1"></split>
  <view name="rtsView " atid="1" atcol="0" atrow="0" size="50"></view>
  <view name="rtsView " atid="1" atcol="1" atrow="0" size="50"></view>
 </frame>
 <frame id="10002" name="stdframe" split="1" vk="Ctrl+f3">
  <split id="2" cols="1" rows="2"></split>
  <split id="3" cols="2" rows="1" atid="2" atrow="0" atcol="0"></split>
  <view name="rtsview " atid="2" atrow="1" atcol="0" size="50"></view>
  <view name="rtsview " atid="3" atrow="0" atcol="0" size="50"></view>
  <view name="rtsview " atid="3" atrow="0" atcol="1" size="50"></view>
 </frame>
</frames>

frame id 10000 represents non-splitter window, 10001 represents single splitter window and last 10002 represents multiple splitter.

Implementation

And the next job becomes easier, I only need to create new class CXMLFrames which is inherited from CXMLWindow and implement Build() function which looks like this:

int CXMLFrames::Build(CRTSXMLNode *pNode)
{
    CString szString;
    CFrameItem *item;

    CRTSXMLNode *child = pNode->GetFirstChild();
    while (child)
    {
        if (child->m_sTitle == "frame")
        {
            item = new CFrameItem;
            child->GetAttr("id", item->m_nMenuId);
            child->GetAttr("name", item->m_szFrame);
            child->GetAttr("split", item->m_nSplitFlag);
            child->GetAttr("vk", item->m_szVirtualKey);
            child->GetAttr("save", item->m_szSave);
            m_pFrameItems.SetAt(item->m_nMenuId, item);
            CRTSXMLNode *grandchild = child->GetFirstChild();
            while (grandchild)
            {
                if (grandchild->m_sTitle == "split")
                { 
                    CSplitterItem *split = item->AddNewSplitter();
                    grandchild->GetAttr("id", split->m_nSplitId);
                    grandchild->GetAttr("cols", split->m_nCols);
                    grandchild->GetAttr("rows", split->m_nRows);
                    grandchild->GetAttr("atid", split->m_nParentId);
                    grandchild->GetAttr("atcol", split->m_nParentCol);
                    grandchild->GetAttr("atrow", split->m_nParentRow);
                }

                if (grandchild->m_sTitle == "view")
                {
                    CViewItem *view = item->AddNewView();
                    grandchild->GetAttr("name", view->m_szName);
                    grandchild->GetAttr("param", view->m_szParam);
                    grandchild->GetAttr("atid", view->m_nSplitId);
                    grandchild->GetAttr("atcol", view->m_nCol);
                    grandchild->GetAttr("atrow", view->m_nRow);
                    grandchild->GetAttr("size", view->m_nSize);
                }
                dchild = child->GetNextChild();
            }
        }
    
        id = pNode->GetNextChild();
    }
    return 1;
}

And develop frame class which looks like this:

BOOL CRTSFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 

{
    CViewItem *pViewItem;
    CSplitterItem *pSplitItem;
    CSplitterWnd *pWndSplitter, *pParentSplitter;
    CRuntimeClass *pClass;
    CString szError;
    m_bActive = false;
    CMainFrame *pParent = (CMainFrame *)m_pApp->m_pMainWnd;
    item = m_pApp->m_pFrameManager.GetFrameItem(pParent->m_nMenuID);
    if (!item)
    {
        szError.Format("Frame Not Available ID='%d'", pParent->m_nMenuID);
        AfxMessageBox(szError, MB_OK|MB_ICONINFORMATION);
        return false;
    }
    // non splitter view
    if (!item->m_nSplitFlag)
    {
        pViewItem = item->GetFirstView();
        pClass = RUNTIME_CLASS(CRTSView);
        pContext->m_pNewViewClass = pClass;
        return CMDIChildWnd::OnCreateClient(lpcs, pContext);
    }
    // create window splitter
    pSplitItem = item->GetFirstSplitter();
    while (pSplitItem)
    {
        pWndSplitter = new CSplitterWnd;
        if (pSplitItem->m_nParentId == -1) // first splitter
            pWndSplitter->CreateStatic(this, 
                 pSplitItem->m_nRows, pSplitItem->m_nCols);
        else
        {
            // next splitter
            if (!m_pSplitters.Lookup(pSplitItem->m_nParentId, 
                                          (void *&)pParentSplitter))
            {
                pSplitItem = item->GetNextSplitter();
                continue;
            }
            pWndSplitter->CreateStatic(pParentSplitter, 
              pSplitItem->m_nRows, pSplitItem->m_nCols, 
              WS_CHILD | WS_VISIBLE | WS_BORDER, 
              pParentSplitter->IdFromRowCol(pSplitItem->m_nParentRow,
              pSplitItem->m_nParentCol));
        }
        // save splitter in list
        m_pSplitters.SetAt(pSplitItem->m_nSplitId, pWndSplitter);_
        // next unprocessing splitter
        pSplitItem = item->GetNextSplitter();
    }

    // create 
    views pViewItem = item->GetFirstView();
    while (pViewItem)
    {
          if (!m_pSplitters.Lookup(pViewItem->m_nSplitId, 
                                        (void *&)pWndSplitter))
          {
               pViewItem = item->GetNextView();
               continue;
          }
          // create view
          pWndSplitter->CreateView(pViewItem->m_nRow, 
              pViewItem->m_nCol, RUNTIME_CLASS(CRTSView), 
              CSize(0, 0), pContext);
          pViewItem = item->GetNextView();
     }
     m_bActive = true;
    return true;
}

Problem

Problem arises while I am developing WM_SIZE to resize all splitters and views; I can’t touch a part of splitter window which is used by another splitter. I am doing little tricks here:

void CRTSFrame::OnSize(UINT nType, int cx, int cy) 
{
    CSplitterWnd *pWndSplitter;
    CViewItem *pViewItem;
    CSplitterItem *pSplitItem;
    int nHeight, nWidth; 
    CMDIChildWnd::OnSize(nType, cx, cy);
    if (!m_bActive)
        return; 
    if (!item)
        return; 
    CRect pRect;
    GetClientRect(pRect); 
    int nRectWidth = pRect.Width();
    int nRectHeight = pRect.Height(); 
    if (!nRectWidth || !nRectHeight)
        return; 
    // we need resize views in splitter's pane
    pViewItem = item->GetFirstView();
    while (pViewItem)
    {  
        if (!m_pSplitters.Lookup(pViewItem->m_nSplitId, (void *&)pWndSplitter))
        {
            pViewItem = item->GetNextView();
            continue;
        } 
        if (pViewItem->m_nSize == -1)
        {
            pViewItem = item->GetNextView();
            continue;
        } 
        if (pWndSplitter->GetRowCount() > 1)
        {
            nHeight = (int)((nRectHeight - 
              ::GetSystemMetrics(SM_CYBORDER) * 2 - 8) * pViewItem->m_nSize/100);
            pWndSplitter->SetRowInfo(pViewItem->m_nRow, nHeight, 1);
        } 
        if (pWndSplitter->GetColumnCount() > 1)
        {
            nWidth = (int)((nRectWidth - 
              ::GetSystemMetrics(SM_CXBORDER) * 2 - 8) * ewItem->m_nSize/100);
            pWndSplitter->SetColumnInfo(pViewItem->m_nCol, nWidth, 1);
        } 
        pViewItem = item->GetNextView(); 
    }  

    // we need to resize splitter's pane which doesn't have view
    // (splitter which have subsplitter)
    // little tricky here
    int nSize;
    pSplitItem = item->GetFirstSplitter();
    while (pSplitItem)
    {
        // if we have parentid then parent doesn't have view
        if (pSplitItem->m_nParentId != -1) 
        {

            // we need to calculate size of non-view splitter's pane
            nSize = 100;
            pViewItem = item->GetFirstView();
            while (pViewItem)
            { 
                nSize -= pViewItem->m_nSize;
                pViewItem = item->GetNextView();
            }

            // find a splitter window
            if (!m_pSplitters.Lookup(pSplitItem->m_nParentId, 
                                          (void *&)pWndSplitter))
            {
                pSplitItem = item->GetNextSplitter();
                continue;
            } 

            // if splitter vertically then it has rowcount more than one
            if (pWndSplitter->GetRowCount() > 1)
            {
                nHeight = (int)((nRectHeight - 
                   ::GetSystemMetrics(SM_CYBORDER) * 2 - 8) * abs(nSize)/100);
                pWndSplitter->SetRowInfo(pSplitItem->m_nParentRow, nHeight, 1);
            } 
            // if splitter horisontally then it has columncount more than one
            if (pWndSplitter->GetColumnCount() > 1)
            {
                nWidth = (int)((nRectWidth - 
                  ::GetSystemMetrics(SM_CXBORDER) * 2 - 8) * abs(nSize)/100);
                dSplitter->SetColumnInfo(pSplitItem->m_nParentCol, nWidth, 1);
            }
            // processing: next splitter
            pSplitItem = item->GetNextSplitter();
        } 
        // window splitter recalclayour
        POSITION pos = m_pSplitters.GetStartPosition();
        WORD nKey; 
        while (pos)
        {
           m_pSplitters.GetNextAssoc(pos, nKey, (void *&)pWndSplitter);
           pWndSplitter->RecalcLayout();
        }
    } 
}

In the first while block, I try to reach all created views and set size based on input.

In the next while block, I try to reach splitter panes which doesn’t have view. I am iterating all splitter windows which have a parent (so the parent must have no view in one of their panes).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Hendranto Nugroho
Web Developer
Indonesia Indonesia
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalto fix the size of the viewmemberBrunda G16 Nov '06 - 0:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 1 Mar 2004
Article Copyright 2004 by Hendranto Nugroho
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid