앞에서 SDI로 프로젝트를 개발하고 MDI로 변환 하는 방법을 알아 보았습니다.
이장에서는 MDI 에서 CDialogBar를 사용하는 방법을 알아 보겠습니다.
CMainFrame과 CChildFrame의 차이와 CDialogBar에 개념이해 정도를 살펴 볼 것 입니다.
먼저 CDialogBar는 CDialog를 Frame에 ToolBar처럼 Docking되는 컨트롤이라고 보시면 됩니다.
실제로 CDialogBar는 CControlBar를 상속 받았으며 내부 코드로 구현 할 거의 없습니다.
이런 이유 때문에 코드가 Frame과 섞이게 되는 개인적으로는 만족스럽지 못하다고 느낍니다.
구현된 그림을 보면
CDialog를 ToolBar 처럼 프레임에 도킹시켜서, UI를 좀더 보기 좋게 만들 수 있습니다.
툴바를 대신할 수 있는 기능이라고 이해 하시면 됩니다.
콤보박스는 물론 리치에디터도 올릴 수가 있습니다.
자 그럼 구현 방법을 살펴 보겠습니다.
먼저 CDialog Class를 하나 생성하고 리소스에서 폼 속성 Style을 Child
Border속성을 None으로 바꾸어 줍니다.
생성된 CDialog클래스 에서 부모 클래스를 CDialogBar 로 바꾸어 줍니다.
저는 CDlgCtrl이라고 Dialog클래스를 만들었으므로 “class CDlgCtrl : public CDialogBar”와 같이 바꾸었으며
생성자를 변경했습니다.
“DlgCtrl.h”
class CDlgCtrl : public CDialogBar
{
// Construction
public:
CDlgCtrl(CWnd* parent=NULL);
“DlgCtrl.cpp”
CDlgCtrl::CDlgCtrl(CWnd* pParent /*=NULL*/)//CDialog(CDlgCtrl::IDD, pParent)
{
//{{AFX_DATA_INIT(CDlgCtrl)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CDialogBar의 부모클래스가 CDialog가 아니고 CControlBar이므로 생성자의 모양이 다릅니다.
CDialog상속에서 CDialogBar으로 바뀌었으니 부모클래스를 호출하는 부분도 모두 바꾸어 주어야 합니다.
void CDlgCtrl::OnSize(UINT nType, int cx, int cy)
{
CDialogBar::OnSize(nType, cx, cy);
Child Frame에서 CDlgCtrl을 사용하기 위해 헤더에 CDlgCtrl를 하나 선언합니다.
#include "DlgCtrl.h"
class CChildFrame : public CMDIChildWnd
{
DECLARE_DYNCREATE(CChildFrame)
public:
CChildFrame();
CDlgCtrl m_DlgCtrl;
그리고 “ChildFrame.cpp”에 도킹을 구현 합니다.
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
EnableDocking(CBRS_ALIGN_ANY); //프레임에 도킹허용
{
if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
if (!m_DlgCtrl.Create(this, IDD_DIALOG_CTRL,
CBRS_FLOAT_MULTI|CBRS_ALIGN_LEFT|CBRS_TOOLTIPS|CBRS_TOP|CBRS_BOTTOM|WS_CHILD|WS_VISIBLE|CBRS_SIZE_DYNAMIC,AFX_IDW_DIALOGBAR))
{
TRACE0("Failed to create dialogbar\n");
return -1; // fail to create
}
m_DlgCtrl.EnableDocking(CBRS_ALIGN_LEFT|CBRS_ALIGN_TOP|CBRS_ALIGN_BOTTOM); //Dialog bar가 도킹 될 수 있는 위치 설정
DockControlBar(&m_DlgCtrl,AFX_IDW_DOCKBAR_LEFT); //프레임 좌측에 Dialgbar 도킹
RecalcLayout(); //Layout 재 계산
return 0;
}
도킹된 컨트롤러 사이즈 변경
ChildFrame이 Layout을 변경할 때 도킹된 Dialogbar도 프레임 사이즈에 맞게 변경되도록 합니다.
void CChildFrame::RecalcLayout(BOOL bNotify)
{
// TODO: Add your specialized code here and/or call the base class
if(m_DlgCtrl.GetSafeHwnd())
{
CRect rect;
CMDIChildWnd::GetWindowRect(&rect) ;
m_DlgCtrl.MoveWindow(&rect);
}
CMDIChildWnd::RecalcLayout(bNotify);
}
도킹컨트롤 숨기기, 보이기 메뉴 구현
도킹된 DialgBar를 메뉴에서 보이거나 숨기기 위해 Child 프레임에서 메뉴이벤트를 받아서
도킹컨트롤을 보여주거나 숨기도록 합니다.
void CChildFrame::OnViewDlgbar()
{
BOOL b_show=!m_DlgCtrl.IsWindowVisible();
ShowControlBar(&m_DlgCtrl,b_show,TRUE);
}
메뉴에 체크 버튼 넣기
도킹 컨트롤바의 상태를 알아내어 상태를 보여줍니다.
ON_UPDATE_COMMAND_UI에서 컨트롤바의 상태에 따라 메뉴를 Check 상태로 만들어 줍니다.
도킹컨트롤의 도킹상태 알아내기void CChildFrame::OnUpdateViewDlgbar(CCmdUI* pCmdUI)
{
if(m_DlgCtrl.IsWindowVisible()) pCmdUI->SetCheck(1);
else pCmdUI->SetCheck(0);
}
CDailoBar는 컨트롤바 이므로 컨트롤바의 도킹 상태를 알아 낼 수 있습니다.
이렇게 도킹상태를 파악하여 부착위치가 Top,left 등이 상태 인지에 따라서 버튼의 크기를 조절 할 수 있습니다.
BOOL CDlgCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
DWORD bs= GetBarStyle();
if(bs & (CBRS_ALIGN_TOP|CBRS_ALIGN_BOTTOM) )
i_align=1;
else i_align=0;
switch(message)
{
case 310:
Resize();
break;
}
TRACE("%d\r\n",message);
return CDialogBar::OnChildNotify(message, wParam, lParam, pLResult);
}
void CDlgCtrl::Resize()
{
CFrameWnd* p_Frame= GetDockingFrame();
CRect m_Rect,mrec;
if(!m_Btn1.GetSafeHwnd() && (this!=NULL))
{
m_Btn1.SubclassDlgItem(ID_CHILD_BTN,this);
}
if(!m_Btn1.GetSafeHwnd()) return;
p_Frame->GetWindowRect(&mrec);
CDialogBar::MoveWindow(0,0,mrec.right,mrec.Height());
if(i_align==0) m_Rect.SetRect(4,4,110,40);
else//Herizen
m_Rect.SetRect(4,4,mrec.Width()-18,30);m_Btn1.MoveWindow(m_Rect);
}
윈도우배경 색상 및 컨트롤의 색상 바꾸기
OnCtlColor에서 Dialog또는 버튼의 색상을 바 꿀 수 있습니다.
HBRUSH CDlgCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogBar::OnCtlColor(pDC, pWnd, nCtlColor);
hbr=hbrush;
CString m_txt;
COLORREF RefBg=RGB(25,200,240);
COLORREF cReffnt=RGB(25,200,24);
CObject* pobj=pWnd;
if(pobj->IsKindOf(RUNTIME_CLASS(CComboBox)))//콤보박스 인 경우의 색상
{
pDC->SetTextColor(RGB(0xFF,0xDC,0x07));
pDC->SetBkColor( RefBg );
}
switch (pWnd->GetDlgCtrlID())
{
case ID_CHILD_BTN:
pDC->SetTextColor(RGB(230,230,250) );
pDC->SetBkColor(RGB(130,130,150) );
break;
case IDC_CHECK1:
pDC->SetTextColor(RGB(130,130,150));
pDC->SetBkColor(RefBg );
break;
default:
break;}
return hbr;
}
여태 까지 구현된 결과화면은 바로 아래의 그림과 같은 모양이 됩니다.
왼쪽은 ChildFrame에 DialogBar를 도킹한 것이고 오른쪽은 아무런 코딩을 하지 않은
또 하나의 ChildFrame이 활성화 된 상태입니다.
물론 두개의 다른 Document Type이 하나의 MDI Project에 올려진 상태입니다.
MDI에서 MainFrame과 ChildFrame의 역할을 좀더 이해하기가 용이 할 것입니다.
세세하게 더 많은 것을 설명하려고 했는데 막상 그렇지 못해서 아쉽습니다.
하나하나 풀어서 설명하려니 한도 끝도 없는 것 같아
MDI(Multi Document Interface)로 개발하기는 여기까지 설명하고 마칩니다.
기본적인 개념 이해화 향후 재사용 가능한 뼈대는 만들어 진 상태 입니다.
현재까지 코딩한 내용 소스첨부 하여
올려 놓았으니 참조 하시고 이해 하는데 도움이 되었으면 합니다.
지금 까지 의 내용은 Multi Document Interface 와 Single Document Interface를 이해하기 위한
코드를 소개 했습니다.
다음에는 컨트롤 바를 동적으로 사이즈 조절이 가능하게 하고
Log기능을 강화 해서 최종 아키텍쳐를 완성할 예정입니다.
'개발언어 > c++' 카테고리의 다른 글
[MFC] NI CWGraph 사용 잘 하는 법 (0) | 2016.08.02 |
---|---|
MDI(Multi Document Interface)로 개발하기(완료) (0) | 2016.07.26 |
MDI(Multi Document Interface)로 개발하기4 (0) | 2016.07.25 |
MDI(Multi Document Interface)로 개발하기 3 (0) | 2016.07.19 |
MDI(Multi Document Interface)로 개발하기2 (0) | 2016.07.19 |