MDI 와 SDI의 차이를 설명하고
자주 사용하게 되는 Frame형태 또는 Architecture를 미리 만들어 놓는 과정을 설명 하였습니다.
이제 제가 사용하는 Frame의 최종 형태가 완성이 되었습니다.
이렇게 기본적인 형태를 준비 해놓고 프로젝트를 수행할 때 필요한 부분만 수정하여 사용할 목적으로 기본형태를 만들었습니다.
개발 방법이 궁금하시면 이전 단계 MDI(Multi Document Interface)로 개발하기1~5 까지를 참조 하시기 바랍니다.
이번에 다루는 주제는 사이즈 변경 가능한 유연한 도킹컨트롤 바 입니다.
Resizable Docking Window 또는 SizingControlBar 정도로 이름을 붙이면 될 것 같습니다.
첨부된 소스의 “CDynamicCtrlBar”클래스 입니다.
MFC로 작업하다 보면 CDialogBar를 사용하다 보면 상당히 불편한 부분이 많습니다.
CDynamicCtrlBar는 CDialog를 직접 도킹 시킬 수 있게 만들어 져 있습니다.
기능과 사용법을 살펴 보겠습니다.
MainFrame.h에 #include "DynaCtrlBar.h"를 선언합니다.그리고 도킹된 윈도우를 관리하는 클래스를 변수로 잡습니다 CSCBArray m_dynar; #include "DynaCtrlBar.h"
class CMainFrame : public baseFRAME
{
DECLARE_DYNCREATE(CMainFrame)
public:
CMainFrame();
CSCBArray m_dynar;//동적바를 쉽게 추가 하고 제어하기 위해 Array로 만듦
윈도우 도킹
Window를 직접 도킹시키기 위해서 m_dynar에 CDynamicWNDBarCF를 할당합니다.
아래 소스는 CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 에 코딩된 내용 입니다.
///////////////////////////////////////////////////
/// 동적 컨트롤바 생성 Default
//동적 BAR를 만들어 Frame에 붙인다
int pos=0;
pos=m_dynar.GetSize();
m_dynar.Add(new CDynamicWNDBarCF());//생성자에서 바로 추가
if (!m_dynar[0]->Create(_T("Window Add"), this,CSize(460,100),FALSE, ID_VIEW_CTRLBAR+pos /* control*= Id*/))
{
TRACE0("Failed to create instant bar\n");
return -1; // fail to create
}
m_dynar[pos]->SetBarStyle(m_dynar[pos]->GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC|SCBS_SIZECHILD);
m_dynar[pos]->EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(m_dynar[pos], AFX_IDW_DOCKBAR_TOP);//default로 최상단에 고정CDlgSetItem* p_dlg=new CDlgSetItem();
p_dlg->Create(IDD_DIALOG_SET,m_dynar[pos]);
((CDynamicWNDBarCF*)m_dynar[pos])->AddWnd(p_dlg,"Test1");
CDialog클래스인 CDlgSetItem를 Modaless로 생성하여 도킹 시킨 것 입니다.
CDialog 도킹
CDialog클래스는
((CDynamicWNDBarCF*)m_dynar[pos])->AddDialog(new CDlgSetItem(),IDD_DIALOG_SET,"Test1");
와 같이 사용하여 직접 도킹이 가능합니다.
CRichEditCtrl 도킹
StatusControl 클래스는 CDynamicCtrlBarCF를 상속받아서 도킹 시킨 것입니다.
유산한 방법으로 상속 받아서 도킹 시켜도 됩니다.//동적 BAR를 만들어 Frame에 붙인다 좌측에 자동 고정
pos=m_dynar.GetSize();
m_dynar.Add(p_App->p_statuslog);
if (!m_dynar[pos]->Create(_T("Status"), this,CSize(160,100),FALSE, ID_VIEW_CTRLBAR+pos /* control*= Id*/))
{
TRACE0("Failed to create instant bar\n");
return -1; // fail to create
}
m_dynar[pos]->SetBarStyle(m_dynar[pos]->GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC|SCBS_SIZECHILD);
m_dynar[pos]->EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(m_dynar[pos], AFX_IDW_DOCKBAR_LEFT);//default로 좌측 고정
도킹 컨트롤 메뉴 제어하기(동적 메뉴 만들기)
도킹된 메뉴를 숨겼을 때 이를 다시 보여주기 위한 메뉴를 자동적으로 만듧니다.
CMainFrame::OnInitMenu(CMenu* pMenu) 에서 메뉴가 만들어 질 때 메뉴를 추가 합니다.
void CMainFrame::OnInitMenu(CMenu* pMenu)
{
baseFRAME::OnInitMenu(pMenu);
CreateBarShowMenu();//MAin Frame이 활성화 될때 마다 동적 Bar View 메뉴 최적하 하도록
}///////////////////////////////////////////////////////////////////////////////////////
void CMainFrame::CreateBarShowMenu()
{
CMenu* p_menu=AfxGetMainWnd()->GetMenu();
UINT sz=p_menu->GetMenuItemCount();
if(sz<0) return;
if(m_dynar.GetSize()<=0)return;//컨트롤 할 것이 없으면 return
BOOL b_Find=FALSE;
CString m_text,m_comp;
UINT i=0,j=0,sz_fnc=0,mID=0;
MENUITEMINFO m_menuinf;
CMenu* menu =NULL;
CMenu* p_smenu=NULL;
CMenu* p_third=NULL;
memset(&m_menuinf,0,sizeof(MENUITEMINFO));
m_menuinf.cbSize=sizeof(MENUITEMINFO);
m_menuinf.fMask=MIIM_TYPE|MIIM_SUBMENU|MIIM_ID|MIIM_DATA;
m_menuinf.fType=MFT_STRING;
for(i=0; (p_third==NULL) && (i<sz) ;i++)//메뉴에서 찾고자 하는 항목을 찾아서 ...
{
p_smenu=p_menu->GetSubMenu(i); //Sub Menu를 불러 와럿
sz_fnc=p_smenu->GetMenuItemCount();//Sub Menu의 갯수를 확인
for(j=0;j<sz_fnc;j++)
{
mID=p_smenu->GetMenuItemID(j);
if(mID==ID_VIEW_STATUS_BAR)
{
p_third=p_smenu;//상태바가 있는 위치 일 경우
break;
}
}
}
if(p_third==NULL)//View Menu가 없으므로 메뉴 추가
{
p_menu->AppendMenu(MF_STRING,MF_STRING,"View");
}
//찾은 메뉴의 하단에 메뉴를 추가, 동적 메뉴 추가
if(p_third)
{
m_dynar[0]->GetWindowText(m_comp);//찾을 메뉴의 이름 가져 오기 즉 첫번째 메뉴
sz=p_third->GetMenuItemCount();
for(j=0;j<sz;j++)//추가 할 메뉴가 있는지 확인
{
p_third->GetMenuString(j,m_text,MF_BYPOSITION);
if(m_text==m_comp)b_Find=TRUE;
}
if(!b_Find) //등록해야할 메뉴를 잧지 못한 경우
{
p_smenu->InsertMenu (sz,MF_BYPOSITION,MF_SEPARATOR); //메뉴 구분선 추가 하기
sz_fnc=m_dynar.GetSize();
for(i=0;i<sz_fnc;i++)//메뉴에 자동 추가
{
m_dynar[i]->GetWindowText(m_text);
p_smenu->InsertMenu (sz+i+1,MF_BYPOSITION,ID_VIEW_CTRLBAR+i,m_text);
//p_menu->ModifyMenu(m_menuinf.wID, MF_BYCOMMAND, m_menuinf.wID,m_text);
}
}
}
sz_mnu=sz_mnu+m_dynar.GetSize();//Show 메뉴으 Click Command를 수행할 갯수 설정
}
도킹 컨트롤의 최종상태 가져오기
도킹컨트롤의 사이즈 변경 또는 숨기기 도킹위치 변경 정보를 레지스트리에서 불러와 마지마 상태와 똑같이 복원합니다.
#ifdef _SCB_REPLACE_MINIFRAME
m_pFloatingFrameClass = RUNTIME_CLASS(CSCBMiniDockFrameWnd);
#endif //_SCB_REPLACE_MINIFAME
CRuntimeClass* prt = GetRuntimeClass();
CString sProfile = _T(prt->m_lpszClassName);
TRY
{
if (VerifyBarState(sProfile))
{
CDynamicCtrlBar::GlobalLoadState(this, sProfile);
LoadBarState(sProfile);
}
}
CATCH(CException, e)
{
puts("in except");
}
END_CATCH
도킹 컨트롤의 최종상태 저장하기
도킹컨트롤의 사이즈 변경 또는 숨기기 도킹위치 변경 정보를 레지스트리에 저장합니다.
void CMainFrame::OnDestroy()
{
//Save Bar Status before MainFrame Closed
CRuntimeClass* prt = GetRuntimeClass();
CString sProfile = _T(prt->m_lpszClassName);
CDynamicCtrlBar::GlobalSaveState(this, sProfile);
SaveBarState(sProfile);baseFRAME::OnDestroy();
// TODO: Add your message handler code here
}
CRichEditCtrl을 파일로 저장하기
CRichEditCtrl요 있는 내용을 파일로 저장합니다.
void StatusControl::SaveRtf()
{
CString m_FullFile;
CString s_file=AfxGetApp()->m_pszHelpFilePath ;
int p=s_file.ReverseFind('\\');
s_file=s_file.Left(p);
m_FullFile.Format("%s\\%s.rtf",s_file,CTime::GetCurrentTime().Format("%Y%m%d%H"));
CFile cFile(m_FullFile, CFile::modeCreate|CFile::modeWrite);
EDITSTREAM es;
es.dwCookie = (DWORD) &cFile;
es.pfnCallback = MyStreamOutCallback;
m_RichEdit.StreamOut(SF_RTF, es);
}
위의 과정까지 모두 구현 하고 나서 파일을 보관 하고 나면
다음에 작업할 땐 휠씬 쉽게 작업이 가능 할 것입니다.
'개발언어 > c++' 카테고리의 다른 글
[MFC]NI CWGraph 사용예제 (0) | 2016.08.02 |
---|---|
[MFC] NI CWGraph 사용 잘 하는 법 (0) | 2016.08.02 |
MDI(Multi Document Interface)로 개발하기5 (0) | 2016.07.25 |
MDI(Multi Document Interface)로 개발하기4 (0) | 2016.07.25 |
MDI(Multi Document Interface)로 개발하기 3 (0) | 2016.07.19 |