2012-10-02 2 views
0

MFC를 사용하여 C++에서 레이아웃 관리자를 수행하려고합니다. 이 레이아웃에는 윈도우 매트릭스가 포함됩니다. 레이아웃 초기 폼은 MS Word와 같은 매트릭스 선택기로 정의됩니다. 그런 다음 사용자는 가장자리를 당겨서 각 창의 크기를 조정할 수 있습니다. 2 차원 충돌 탐지 알고리즘을 사용하려고 생각하고 있지만 이것이 실시간 크기 조정 (또는 MFC를 사용하여 수행하는 방법)에서 어떻게 수행되는지는 모르겠다.mfc 자식 창으로 2 차 충돌 탐지

각 요소 및 블록에 최소 크기를 부과하고 싶다. 이 제한을 위반하는 경우 요소 축소 (다른 요소가 확장 될 때) 어떤 sugestion을 기다리는 것

답변

0

나는 C++과 MFC에서 비슷한 레이아웃 매니저를해야했다. 나는 직사각형을 포함하는 N-ary 트리 (CDisplayObject)를 구현했으며 트리의 각 리프는 CFrame을 가질 수 있습니다. 그러한 트리를 구성하기 위해 간단한 텍스트 구문 분석이 수행됩니다. 각 사각형의 크기는 0에서 1 사이이며 크기의 합이 1 인 하위 항목이 있습니다.

크기를 조정하지 않아도 CDisplayObject 크기를 조정하기 때문에 구현이 쉽습니다. 창문.

우리 프로그램에서 MainView 인 "표시"사각형에 따라 자체 크기를 조절하는 display 객체를 처리하는 코드는 다음과 같습니다. "|"

CDisplayObject* tmp; 
    CString szCurrentName = "Big + three" 
tmp = new CDisplayObject(szCurrentName); 
tmp->Add(szCurrentName + "|Column1",0.75); 
tmp->Add(szCurrentName + "|Column2",0.25); 
tmp->Add(szCurrentName + "|Column2-Row1",0.3333333); 
tmp->Add(szCurrentName + "|Column2-Row2",0.3333333); 
tmp->Add(szCurrentName + "|Column2-Row3",0.3333333); 

:

오른쪽에 작은 하나 개의 큰 왼쪽에 사각형 세와 "디스플레이 트리"를 만들려면 신호는 열이고 "-"는 이것이 행이라는 신호입니다.

SwitchFrameWnd를 사용하여 자식 윈도우를 포함하도록 리프를 설정하고 SetPos (CRect)를 사용하여 트리의 모든 표시 객체의 크기를 조정합니다. 트리를 지나가는 행/열/리프의 가중치를 변경하는 함수를 구현하여 윈도우의 크기 조정을 추가 할 수 있습니다. 당신이 코드를 게시 할 수 있다면

#pragma once 

#ifndef __AFXWIN_H__ 
#error include 'stdafx.h' before including this file for PCH 
#endif 

class CDisplayObject : public CObject 
{ 
    friend class CMainView; 
    typedef std::list<CDisplayObject*> Childrens; 
public: 
    typedef std::list<CDisplayObject*> Leafs; 

    typedef enum 
    { 
     LEAF, 
     ROW, 
     COLUMN 
    } ITEM_TYPE; 

    CDisplayObject(LPCTSTR name,CDisplayObject* Parent = NULL, CoordinateType weight = 1.0); 

    virtual    ~CDisplayObject(); 
    bool    HasViewOrFrame(const CWnd* wnd) const;    
    void    TRACE_IT(); 
    void    Draw(CDC* pDC, const CRect& drawRect,BOOL isIconMode); 
    CView*   GetView() const; 
    void    Add(LPCSTR layoutItemDesc, CoordinateType weigth); 
    //returns all the leafs in the tree 
    virtual Leafs  GetLeafs() ; 
    //this removes the framewnd from any other object in same layout-tree 
    //and sets the view in this object 
    virtual BOOL  SwitchFrameWnd(CFrameWnd* view); 
    CFrameWnd*   GetFrameWnd() const     {return m_pFrameWnd;} 
    void    SetPos(const RECT& rect); 
    CString    GetName() const    { return m_Name;} 
    CString    GetUniqueName() const {return m_UUID;} 

    //returns the complete name for this leaf i.e: main|column-row 
    CString    GetCompleteName() const; 
    CRect    GetDisplayRect() const  { return m_DisplayRect; } 
    CDisplayObject*  GetFirstEmptyLeaf(); 
    CDisplayObject*  GetFirstEmptyLeafAfterLastFrame(); 
    //removes the wnd in the subtree 
    void    RemoveWnd(CFrameWnd* view); 
    //calls updateSlaveWindows for each view 
    void    UpdateSlaveWindows(); 
    //returns the CDisplayObject that has the wnd as framewnd or view 
    //can return null! 
    CDisplayObject*  GetObjectWithWnd(const CWnd* wnd) ; 

    CDisplayObject*  GetLeafViewFromPoint(const CPoint& point); 
protected: 
    CDisplayObject(){}; 

    BOOL    IsLeaf() const   { return m_type == LEAF && m_Childrens.size() == 0;}  
    CRect    CalculateChildrenRect(CDisplayObject* children, const CRect& mainRect,Vector2d &topLeft); 
    void    SetDisplayRect(CRect val) ; 
    CFrameWnd*   GetLastView() const   { return m_pLastView; } 
    void    HideViews(); 
    void    ShowViews(); 
    CDisplayObject::ITEM_TYPE   GetType() const { return m_type; } 
private: 
    static CString  translateString(LPCTSTR str); 
    static CString  GetPrefix(LPCSTR str); 
    static CString  GetSuffix(LPCTSTR str); 
    static ITEM_TYPE GetDividerType(LPCTSTR str); 
    void    RepositionView(); 
    void    SetWeight(CoordinateType weight); 
    CoordinateType  GetWeight() const; 
    CoordinateType  GetChildrenWeight() const; 
    CDisplayObject*  GetRootObject(); 


    CFrameWnd   *m_pFrameWnd; 
    //used for distributing documents correctly (=last place used) when changing layouts 
    CFrameWnd   *m_pLastView; 
    Childrens   m_Childrens; 
    CoordinateType  m_Weight; 
    CString    m_Name; 
    CString    m_UUID; 
    ITEM_TYPE   m_type; 
    //this is the client rect for this window 
    CRect    m_DisplayRect; 
    //the parent for this CDisplayObject. if m_parent == NULL => root-object 
    CDisplayObject*  m_Parent; 
    //used for draw the name of the object 
#ifdef _DEBUG 
    CFont *m_Font; 
#endif // _DEBUG 
    DECLARE_DYNCREATE(CDisplayObject) 
}; 

cpp를 구현

#include "stdafx.h" 
#include "DisplayObject.h" 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 

IMPLEMENT_DYNCREATE(CDisplayObject, CObject) 

////////////////////////////////////////////////////////////////////////// 
///CDisplayObject 
////////////////////////////////////////////////////////////////////////// 
CDisplayObject::CDisplayObject(LPCTSTR name, CDisplayObject* Parent /*= NULL*/, CoordinateType weight /*= 1.0*/) 
:CObject() 
{ 
    m_UUID = CreateUUID(); 
    m_Name = GetPrefix(name); 
    m_type = LEAF; 
    ASSERT(!m_Name.IsEmpty()); 
    if(!GetSuffix(name).IsEmpty()) 
    { 
     this->Add(name, weight); 
    } 
    else 
    { 
     m_Weight = weight; 
    } 
    m_Parent = Parent; 
    m_pFrameWnd = NULL; 
    m_pLastView = NULL; 
    CViewSettings viewSettings; 
    viewSettings = AfxGetProperties()->m_ViewSettings; 
    m_DisplayRect = CRect(0,0,0,0); 
#ifdef _DEBUG 
    m_Font = new CFont;  
    m_Font->CreateFont( 
     12, // nHeight 
     0,      // nWidth 
     0,      // nEscapement 
     0,      // nOrientation 
     FW_NORMAL,    // nWeight, 
     FALSE,     // bItalic 
     FALSE,     // bUnderline 
     FALSE,     // cStrikeOut 
     DEFAULT_CHARSET,  // CharSet 
     OUT_CHARACTER_PRECIS, 
     CLIP_DEFAULT_PRECIS, 
     PROOF_QUALITY, 
     FF_DONTCARE, 
     "Arial"); 
#endif // _DEBUG 
} 


CDisplayObject::~CDisplayObject() 
{ 
    // TRACE_LINE; 
    for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     delete *it; 
    m_Childrens.clear(); 
#ifdef _DEBUG 
    if(m_Font) 
    { 
     m_Font->DeleteObject(); 
     SAFE_DELETE(m_Font); 
    } 
#endif // _DEBUG 

} 


void CDisplayObject::Add(LPCSTR layoutItemDesc, CoordinateType weigth) 
{ 
    CString prefix = GetPrefix(layoutItemDesc); 
    CString suffix = GetSuffix(layoutItemDesc); 
    if(prefix == m_Name) 
    { 
     if(!suffix.IsEmpty()) 
     { 
      m_type = (m_type == LEAF) ? GetDividerType(layoutItemDesc) : m_type; 
      CString prefixSuffix = GetPrefix(suffix); 
      CDisplayObject* tmp = NULL; 
      if(!prefixSuffix.IsEmpty()) 
      { 
       for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
       { 
        if((*it)->GetName() == prefixSuffix) 
        { 
         tmp = *it; 
         break; 
        } 
       } 
       if(tmp == NULL) 
       { 
        tmp = new CDisplayObject(prefixSuffix, this); 
        m_Childrens.push_back(tmp); 
       } 
      } 
      tmp->Add(suffix, weigth); 
     } 
     else 
     { 
      SetWeight(weigth); 
     } 
    } 
} 

void CDisplayObject::TRACE_IT() 
{ 
    TRACE(m_Name); 
    TRACE(" %.2f", m_Weight); 
    if(m_Childrens.size() > 0) 
    { 
     TRACE(" ("); 
     CString divider; 
     for(Childrens::const_iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      TRACE(divider); 
      (*it)->TRACE_IT(); 
      divider = (m_type == ROW) ? " - " : " | "; 
     } 
     TRACE(") "); 
    } 
} 


CString CDisplayObject::translateString(LPCTSTR str) 
{ 
    CString retValue = str; 
    retValue.MakeLower(); 
    retValue.Trim(); 
    return str; 
} 

CString CDisplayObject::GetPrefix(LPCSTR str) 
{ 
    CString tmpStr = translateString(str); 
    int index = tmpStr.FindOneOf("|-"); 
    if(index == -1) 
    { 
     return tmpStr; 
    } 
    else 
    { 
     return tmpStr.Left(index); 
    } 
} 

CString CDisplayObject::GetSuffix(LPCTSTR str) 
{ 
    CString tmpStr = translateString(str); 
    int index = tmpStr.FindOneOf("|-"); 
    if(index == -1) 
    { 
     return ""; 
    } 
    else 
    { 
     return tmpStr.Mid(index + 1); 
    } 
} 

CDisplayObject::ITEM_TYPE CDisplayObject::GetDividerType(LPCTSTR str) 
{ 
    CString tmpStr = translateString(str); 
    int index = tmpStr.Find("-"); 
    if(index != -1) //horizontal 
    { 
     return ROW; 
    } 
    index = tmpStr.Find("|"); 
    if(index != -1) //vertical 
    { 
     return COLUMN; 
    } 
    return LEAF; 
} 



CoordinateType CDisplayObject::GetWeight() const 
{ 
    return m_Weight; 
} 

CoordinateType CDisplayObject::GetChildrenWeight() const 
{ 
    CoordinateType sum = 0; 
    for(Childrens::const_iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
    { 
     sum += (*it)->GetWeight(); 
    } 
    return sum; 
} 

static bool IsRectEqual(const CRect &obj1, const CRect &obj2) 
{ 
    return obj1.left == obj2.left && obj1.right == obj2.right && obj1.top == obj2.top && obj1.bottom == obj2.bottom; 
} 

void CDisplayObject::SetWeight(CoordinateType weight) 
{ 
    m_Weight = weight; 
} 

void CDisplayObject::SetPos(const RECT& rect) 
{ 
    SetDisplayRect(rect); 
    if(IsLeaf()) 
    { 
     SetDisplayRect(rect); 
    } 
    else 
    { 
     Vector2d topLeft; 
     for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      CRect newDrawRect = CalculateChildrenRect(*it,rect,topLeft); 
      (*it)->SetPos(newDrawRect); 
     } 
    } 
} 


CRect CDisplayObject::CalculateChildrenRect(CDisplayObject* children, const CRect& mainRect, Vector2d& topLeft) 
{ 
    ASSERT(m_Childrens.size() > 0); 
    ASSERT(m_type == COLUMN || m_type == ROW); 
    CRect drawRectangle; 
    if(m_type == COLUMN) 
    { 
     CoordinateType weight = children->GetWeight(); 
     Vector2d BottomRight(topLeft.X() + weight, 1.0); 
     CLayoutRectangle childrenRectangle(topLeft, BottomRight); 
     drawRectangle = childrenRectangle.ToCRect(mainRect); 
     topLeft = childrenRectangle.TopRight(); 
    } 
    else if(m_type == ROW) 
    { 
     CoordinateType weight = children->GetWeight(); 
     Vector2d BottomRight(1.0,topLeft.Y() + weight); 
     CLayoutRectangle childrenRectangle(topLeft, BottomRight); 
     drawRectangle = childrenRectangle.ToCRect(mainRect); 
     topLeft = childrenRectangle.BottomLeft(); 
    } 
    return drawRectangle; 
} 

void CDisplayObject::Draw(CDC* pDC, const CRect& drawRect,BOOL isIconMode) 
{ 
    if(IsLeaf()) 
    { 
     if(!isIconMode) 
     { 
      SetDisplayRect(drawRect); 
     } 
     pDC->FillRect(drawRect,&CBrush(m_ViewSettings.m_BackgroundColor)); 

/* 
#ifdef _DEBUG 
     if(!isIconMode) 
     { 
      pDC->SetTextAlign(TA_CENTER); 
      CFont* pOldFont = pDC->SelectObject(m_Font); 
      pDC->SetBkMode(TRANSPARENT); 
      pDC->SetTextColor(RGB(255, 255, 255)); 
      pDC->TextOut(drawRect.left + drawRect.Width()/2, 
       drawRect.top + drawRect.Height()/2, 
       GetCompleteName()); 
      pDC->SelectObject(pOldFont); 
     } 
#endif // _DEBUG 
*/ 

     CPen FramePen(PS_SOLID, m_ViewSettings.m_FrameWidth, m_ViewSettings.m_FrameColor); 
     CPen* oldPen; 
     oldPen = pDC->SelectObject(&FramePen); 
     CLayoutRectangle(drawRect).DoPaint(pDC); 
     pDC->SelectObject(oldPen); 
    } 
    else 
    { 
     Vector2d topLeft; 
     for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      CRect newDrawRect = CalculateChildrenRect(*it,drawRect,topLeft); 
      (*it)->Draw(pDC,newDrawRect,isIconMode); 
     } 
    } 
} 


CDisplayObject* CDisplayObject::GetFirstEmptyLeaf() 
{ 
    if(IsLeaf() && m_pFrameWnd == NULL) 
    { 
     return this; 
    } 
    else 
    { 
     for(Childrens::const_iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      CDisplayObject* tmpDisplayObject = (*it)->GetFirstEmptyLeaf(); 
      if(tmpDisplayObject != NULL) 
      { 
       return tmpDisplayObject; 
      } 
     } 
    } 

    return NULL; 
} 



CDisplayObject* CDisplayObject::GetFirstEmptyLeafAfterLastFrame() 
{ 
    Leafs leafs = GetLeafs(); 
    Leafs::reverse_iterator it = leafs.rbegin(); 
    while(1) 
    { 
     Leafs::reverse_iterator tmpIt = it; 
     if((*tmpIt)->GetFrameWnd() != NULL) 
     { 
      return NULL; 
     } 
     it++; 
     if(it != leafs.rend()) 
     { 
      if((*it)->GetFrameWnd() != NULL) 
       return *tmpIt; 
     } 
     else 
     { 
      //no frameWnd present 
      return (*leafs.begin()); 
     } 
    } 
    return NULL; 
} 


CDisplayObject* CDisplayObject::GetLeafViewFromPoint(const CPoint& point) 
{ 
    if(IsLeaf() && m_DisplayRect.PtInRect(point)) 
    { 
     return this; 
    } 
    else 
    { 
     for(Childrens::const_iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      CDisplayObject* tmpDisplayObject = (*it)->GetLeafViewFromPoint(point); 
      if(tmpDisplayObject != NULL) 
      { 
       return tmpDisplayObject; 
      } 
     } 
    } 
    return NULL; 
} 

BOOL CDisplayObject::SwitchFrameWnd(CFrameWnd* View) 
{ 
    //walk through whole tree and remove the view 
    GetRootObject()->RemoveWnd(View); 
    if(!IsLeaf()) 
     return FALSE; 
    if(m_pFrameWnd && ::IsWindow(m_pFrameWnd->GetSafeHwnd())) 
     RemoveWindow(m_pFrameWnd); //hide the window 
    m_pLastView = m_pFrameWnd; 
    m_pFrameWnd = View; 
    if(m_pFrameWnd) 
    { 
     RepositionView(); 
     if(m_pFrameWnd && ::IsWindow(m_pFrameWnd->GetSafeHwnd())) 
      AddWindow(m_pFrameWnd); 

     if(m_pFrameWnd && ::IsWindow(m_pFrameWnd->GetSafeHwnd())) 
     { 
      if(m_pFrameWnd->GetActiveView()) 
      { 
       CImageView* pImageView = (CImageView*)m_pFrameWnd->GetActiveView(); 
       pImageView->ResetOrigoPanPos(); 
       pImageView->ResetPanPos(FALSE); 
       pImageView->UpdateShownImage(); 
      } 
      m_pFrameWnd->Invalidate(); 
      m_pFrameWnd->RedrawWindow(); 
     } 
    } 
    return TRUE; 
} 


CDisplayObject::Leafs CDisplayObject::GetLeafs() 
{ 
    Leafs retValue; 
    if(IsLeaf()) 
    { 
     retValue.push_back(this); 
    } 
    else 
    { 
     for(Childrens::const_iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      Leafs tmpLeafs = (*it)->GetLeafs(); 
      retValue.merge(tmpLeafs); 
     } 
    } 
    return retValue; 
} 

void CDisplayObject::SetDisplayRect(CRect val) 
{ 
    if(IsRectEqual(val , m_DisplayRect)) 
     return; 
    //TRACE_LINE; 
    int frameWidth = m_ViewSettings.m_FrameWidth; 
    m_DisplayRect = val; 
    //deflate the rect for accomodate the own frame. 
    if(IsLeaf()) 
     m_DisplayRect.DeflateRect(frameWidth,frameWidth,frameWidth,frameWidth); 
    //m_DisplayRect.OffsetRect(CPoint(0,-100)); 
    RepositionView(); 
} 

void CDisplayObject::RepositionView() 
{ 
    if(m_pFrameWnd && ::IsWindow(m_pFrameWnd->GetSafeHwnd())) 
    { 
     m_pFrameWnd->SetWindowPos(NULL,m_DisplayRect.left,m_DisplayRect.top,m_DisplayRect.Width(),m_DisplayRect.Height(),SWP_NOZORDER); 
    } 
} 

void CDisplayObject::HideViews() 
{ 
    if(GetFrameWnd() && ::IsWindow(GetFrameWnd()->GetSafeHwnd())) 
     RemoveWindow(GetFrameWnd()); 
    if(!IsLeaf()) 
    { 
     for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      (*it)->HideViews(); 
     } 
    } 
} 

void CDisplayObject::ShowViews() 
{ 
    if(GetFrameWnd() && ::IsWindow(GetFrameWnd()->GetSafeHwnd())) 
     AddWindow(GetFrameWnd()); 
    if(!IsLeaf()) 
    { 
     for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      (*it)->ShowViews(); 
     } 
    } 
} 

void CDisplayObject::RemoveWnd(CFrameWnd* view) 
{ 
    if(m_pFrameWnd == view) 
    { 
     m_pFrameWnd = NULL; 
    } 
    if(!IsLeaf()) 
    { 
     for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      (*it)->RemoveWnd(view); 
     } 
    } 

} 


CDisplayObject* CDisplayObject::GetRootObject() 
{ 
    //get the root display object 
    CDisplayObject* rootParent = m_Parent; 
    CDisplayObject* currentObject = this; 
    while(rootParent) 
    { 
     CDisplayObject* tmp = rootParent; 
     currentObject = rootParent; 
     rootParent = tmp->m_Parent; 
    } 
    ASSERT(currentObject); 
    return currentObject; 
} 

    CView* CDisplayObject::GetView() const 
{ 
    if(m_pFrameWnd && m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CImageFrameWnd))) 
    { 
     CView* view = m_pFrameWnd->GetActiveView(); 
     if(view && view->IsKindOf(RUNTIME_CLASS(CImageView))) 
     { 
      return (CImageView*)view; 
     } 
    } 

    return NULL; 
} 


bool CDisplayObject::HasViewOrFrame(const CWnd* wnd) const 
{ 
    if(this->m_pFrameWnd == wnd) 
     return true; 
    if(this->GetFrameWnd() && this->GetView() == wnd) 
    { 
     return true; 
    } 
    return false; 
} 

CDisplayObject* CDisplayObject::GetObjectWithWnd(const CWnd* wnd) 
{ 
    if(this->HasViewOrFrame(wnd)) 
    { 
     return this; 
    } 
    if(!IsLeaf()) 
    { 
     for(Childrens::iterator it = m_Childrens.begin(); it != m_Childrens.end(); ++it) 
     { 
      CDisplayObject* retValue; 
      if((retValue = (*it)->GetObjectWithWnd(wnd)) != NULL) 
      { 
       return retValue; 
      } 
     } 
    } 
    return NULL; 
} 

CString CDisplayObject::GetCompleteName() const 
{ 
    CString name = GetName(); 
    const CDisplayObject* rootParent = m_Parent; 
    const CDisplayObject* currentObject = this; 
    while(rootParent) 
    { 
     if(rootParent->GetType() == COLUMN) 
     { 
      name = rootParent->GetName() + CString("|") + name; 
     } 
     else if(rootParent->GetType() == ROW) 
     { 
      name = rootParent->GetName() + CString("-") + name; 
     } 
     else 
     { 
      name = rootParent->GetName() + CString(" ERROR! ") + name; 
     } 
     const CDisplayObject* tmp = rootParent; 
     currentObject = rootParent; 
     rootParent = tmp->m_Parent; 
    } 
    return name; 
} 
+0

그것은 나를위한 좋은 출발점이 될 것입니다. 또한 CRectTracker (지금까지 경험이 없음)를 사용하여 중복을 감지 할 생각 이었지만 효율적인 솔루션이 아닐 것이라고 말합니다. 어쨌든 당신의 대답에 감사드립니다. 나는 그 암호를 기다리고있을 것이다. 문안 인사! – SabinManiac

+0

코드를 참조하십시오 – Lucian

+0

코드에 대한 루시 너를 감사하지만 다른 접근 방식을 따르기로했습니다. – SabinManiac