나는 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;
}
그것은 나를위한 좋은 출발점이 될 것입니다. 또한 CRectTracker (지금까지 경험이 없음)를 사용하여 중복을 감지 할 생각 이었지만 효율적인 솔루션이 아닐 것이라고 말합니다. 어쨌든 당신의 대답에 감사드립니다. 나는 그 암호를 기다리고있을 것이다. 문안 인사! – SabinManiac
코드를 참조하십시오 – Lucian
코드에 대한 루시 너를 감사하지만 다른 접근 방식을 따르기로했습니다. – SabinManiac