[How-To] 기존 MFC 프로젝트에 Ribbon UI 적용하기




기존 MFC Scribble Sample에 VS2008 Feature Pack에 포함된 MFC의 Ribbon UI를 적용해 보겠습니다.

Visual C++ 2008 Feature Pack Download
Visual C++ 2008 Feature Pack Documentaion

우선 기존 Scribble Sample을 가져 와서 VS 2008 로 Open 합니다.
\Microsoft Visual Studio 9.0\Samples\1033\AllVCLanguageSamples\C++\MFC\ole 에 위치해 있습니다.

1. afxcontrolbars.h 헤더 추가
우선 리본을 적용하기 위해서 헤더를 포함하여야 합니다. 
stdafx.h 파일을 열어 상단에 afxcontrolbars.h 를 include합니다.

#ifndef WINVER
#define WINVER 0x0600
#endif
#include <afxcontrolbars.h>


2008에서 부터는 WINVER가 Default로 Define되어 있지 않습니다.  따라서 WINVER를 명시적으로 선언하지 않으면 Warning을 표시하고 Default로 0x0600 (Vista)로 선언됩니다. 

class CScribbleApp : public CWinAppEx
{
scribble.cpp 를 열어 다음을 추가 합니다.

LoadStdProfileSettings();  // Load standard INI file options (including MRU)
SetRegistryKey(_T(“MFCNext\\Samples\\Scribble2”));
SetRegistryBase(_T(“Settings”));
기존 Scribble프로젝트 에서는 ini방식을 사용하므로 자동으로 저장되는 프로그램설정을 위해 레지스트리를 사용하도록 변경합니다.

3. MainFrame 클래스 변경
mainfrm.h를 열어 CMDIFrameWnd를 CMDIFrameWndEx로 변경합니다.

class CMainFrame : public CMDIFrameWndEx
{
상속클래스가 변경되었으니 mainfrm.cpp를 열어 모든 CMDIFrameWnd를 CMDIFrameWndEx로 변경하여야 겠지요?  변경합니다.
 
CMDIFrameWnd를 CMDIFrameWndEx로 한번에 Replace하는것이 빠르겠지요..

변경되는 코드 모두 펼치기


[#M_펼쳐두기..|접어두기..|
IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWndEx)

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx)
    //{{AFX_MSG_MAP(CMainFrame)
        // NOTE – the ClassWizard will add and remove mapping macros here.
        //    DO NOT EDIT what you see in these blocks of generated code !
    ON_WM_CREATE()
    //}}AFX_MSG_MAP
    ON_COMMAND(ID_HELP_FINDER, CMDIFrameWndEx::OnHelpFinder)
    ON_COMMAND(ID_HELP, CMDIFrameWndEx::OnHelp)
    ON_COMMAND(ID_CONTEXT_HELP, CMDIFrameWndEx::OnContextHelp)
    ON_COMMAND(ID_DEFAULT_HELP, CMDIFrameWndEx::OnHelpFinder)
END_MESSAGE_MAP()


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1)
        return -1;


BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    return CMDIFrameWndEx::PreCreateWindow(cs);
}


#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
    CMDIFrameWndEx::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
    CMDIFrameWndEx::Dump(dc);
}

#endif //_DEBUG

_M#]
4. ChildWnd 클래스 변경 하기
childfrm.h를 열어 CMDIChildWnd을 CMDIChildWndEx로 변경합니다.
class CChildFrame : public CMDIChildWndEx
{
childfrm.cpp를 열어 모든 CMDIChildWnd를 CMDIChildWndEx로 변경합니다.

변경되는 모든 코드


[#M_펼쳐두기..|접어두기..|
IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWndEx)

BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWndEx)
   //{{AFX_MSG_MAP(CChildFrame)
       // NOTE – the ClassWizard will add and remove mapping macros here.
       //    DO NOT EDIT what you see in these blocks of generated code !
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    return CMDIChildWndEx::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CChildFrame diagnostics

#ifdef _DEBUG
void CChildFrame::AssertValid() const
{
    CMDIChildWndEx::AssertValid();
}

void CChildFrame::Dump(CDumpContext& dc) const
{
    CMDIChildWndEx::Dump(dc);
}

#endif //_DEBUG

_M#]
5. CToolBar, CStatusBar, CMenuBar
mainfrm.h을 열어 CToolBar는 CMFCToolBar로 CStatusBar는 CMFCStatusBar로 변경하고 CMenuBar는 삭제하도록 합니다.  리본을 적용하면 CMenuBar는 사용하지 않습니다.
protected:  // control bar embedded members
    CMFCStatusBar  m_wndStatusBar;
    CMFCToolBar    m_wndToolBar;
    HICON m_hIcon;
mainfrm.cpp를 열어 변경된 클래스의 함수를 적용하여 줍니다.  SetBarStyle -> SetPaneStyle로 GetBarStyle -> GetPaneStyle로 적용합니다. 
    // TODO: Remove this if you don’t want tool tips
    m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() |
        CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
또한 DockControlBar를 DockPane으로 변경합니다.
DockPane(&m_wndToolBar);

컴파일이 될것입니다.  실행하면 기존과 동일하게 동작합니다.

6. Ribbon Bar 추가
mainfrm.h에 RibbonBar를 추가 합니다.

    CMFCRibbonBar                     m_wndRibbonBar;  // Ribbon bar for the application
    CMFCRibbonApplicationButton m_MainButton;       // The application button for the ribbon
    CMFCToolBarImages              m_PanelImages;     // Ribbon Panel Icons

7. 리본에서 사용할 아이콘 Import하기
리본을 테스트 하기 위해서 우선은 3가지 Bitmap이 필요로 합니다.
사용자 삽입 이미지

<- Main Application 버튼에 넣을 이미지  ( IDB_RIBBON_MAIN )
사용자 삽입 이미지

<- Large Panel Icon ( IDB_RIBBONLARGE )

사용자 삽입 이미지
<- Small Panel Icon ( IDB_RIBBONSMALL )

위와 같은 이미지를 리소스에 Import하여 주세요..

8. Ribbon Create하고 Main Application을 추가
이제 드디어 Ribbon을 추가 합니다. OnCreate 함수 상단에 다음의 코드를 추가 합니다.

    if (CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1)
        return -1;

    // Create the ribbon bar
    if (!m_wndRibbonBar.Create(this))
    {
        return -1;   //Failed to create ribbon bar
    }

Ribbon Bar가 생성되었습니다.  이제 Main Button을 등록합니다.
    // application button
    m_MainButton.SetImage(IDB_RIBBON_MAIN);
    m_MainButton.SetToolTipText(_T(“File”));
    m_MainButton.SetText(_T(“\nf”));

    // Attach it to ribbon
    m_wndRibbonBar.SetApplicationButton(&m_MainButton, CSize(45,45));

RibbonBar에 MainButton을 설정하였습니다.  컴파일을 하여 실행하면 아래와 같이 실행됩니다.

사용자 삽입 이미지

리본바가 나타납니다.  그런데 어딘가 이상하죠?  코드를 수정해 나가면서 점점 모습을 갖추어 갈것입니다. 

9. 메인 Category 추가 하기
메인버튼을 클릭하면 나오는 Main Category을 등록합니다.  AddMainCategory인데 MainPanel을 리턴하는군요 ^__^;… 그다음 버튼들을 추가 합니다.  리본 메인 Panel안에 위치할 버튼들입니다.  보통 File 관련 메뉴들이 위치하게 되겠지요.. 여기서 Command ID들은 기존 메뉴 또는 ToolBar에서 사용하는것을 그대로 사용하면 됩니다.  메인 Panel에 넣은 두개의 Bitmap으로 각 버튼의 큰아이콘과 작은 아이콘을 결정할수 있습니다.

    // Main Category
    CMFCRibbonMainPanel* pMainPanel = m_wndRibbonBar.AddMainCategory(_T(“File”),                  IDB_RIBBONSMALL, IDB_RIBBONLARGE);
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_NEW, _T(“&New”), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_OPEN, _T(“&Open”), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_CLOSE, _T(“&Close”), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE, _T(“&Save”), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE_AS, _T(“Save &As…”), 0, 0 ));
자, 컴파일 하고 실행해 볼까요?
사용자 삽입 이미지
메인 버튼을 클릭하면 메뉴가 나타납니다.  메인 Panel이 생겨났네요..

이제 Print 관련 버튼을 설정합니다.  Print관련 버튼은 새로운 Sub메뉴가 생겨나는 버튼이기 때문에 서브버튼을 넣습니다.

    // Add Print Button
    CMFCRibbonButton* pBtnPrint = new CMFCRibbonButton( ID_FILE_PRINT, _T(“&Print”), 4, 4 );
    pBtnPrint->AddSubItem( new CMFCRibbonLabel(_T(“Preview and print the document”) ) );
    pBtnPrint->AddSubItem( new CMFCRibbonButton( ID_FILE_PRINT, _T(“&Print”), 4, 4, TRUE ) );
    pBtnPrint->AddSubItem( new CMFCRibbonButton( ID_FILE_PRINT_PREVIEW, _T(“Print Pre&view”), 6, 6, TRUE ) );
    pBtnPrint->SetKeys( _T(“p”), _T(“w”) );
   
    // Add Print Button To Main Panel
    pMainPanel->Add( pBtnPrint );
    pMainPanel->AddSeparator();
    pMainPanel->Add( new CMFCRibbonButton(ID_FILE_CLOSE, _T(“&Close”), 5, 5));
컴파일 해서 실행하면 아래와 같이 나타납니다.
사용자 삽입 이미지
Print 버튼이 들어갔습니다.  Label과 버튼 두개가 보이시죠?

이제 Recent File List컨트롤을 넣겠습니다. 

    // Add Recent File List & Exit Button
    pMainPanel->AddRecentFilesList( _T(“Recent Documents”) );
    pMainPanel->AddToBottom( new CMFCRibbonButton( ID_APP_EXIT, _T(“E&xit”), 8));

사용자 삽입 이미지
Recent Document 영역이 생겼습니다.  추가 Exit 버튼도 넣었습니다.

9. Category 넣기
Ribbon 영역에 Category를 넣겠습니다.  Category에 Panel을 생성하고 Element들을 넣을수 있게됩니다.

    // Load Images for ribbon panels
    m_PanelImages.SetImageSize(CSize(16,16));
    m_PanelImages.Load(IDB_RIBBONSMALL);

    // Add a “Home” category to the ribbonbar
    CMFCRibbonCategory* pCategory = m_wndRibbonBar.AddCategory( _T(“Home”), IDB_RIBBONSMALL, IDB_RIBBONLARGE );

    CMFCRibbonPanel* pPanelClipboard = pCategory->AddPanel( _T(“Clipboard”), m_PanelImages.ExtractIcon(0) ) ;
    pPanelClipboard->Add( new CMFCRibbonButton(ID_EDIT_PASTE, _T(“Paste”), 1, 1 ) );
    pPanelClipboard->Add( new CMFCRibbonButton(ID_EDIT_CUT, _T(“Cut”), 2, 2 ) );
    pPanelClipboard->Add( new CMFCRibbonButton(ID_EDIT_CLEAR, _T(“Clear”), 3, 3 ) );

m_PanelImages는 Panel에서 사용하게될 CMFCToolBarImages입니다.  Category를 넣고 거기에 Panel을 Add하고 Element들을 Add 하면 됩니다. 
사용자 삽입 이미지
어느 정도 모양이 갖추어 졌네요..  여기서 Visual Manager를 적용하면 Modern한 UI로 됩니다.

    // Set the default manager to Office 2007
    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
    CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);

이제 Application Look이 적용되었습니다.
사용자 삽입 이미지
그리 어렵지 않게 기존 Scribble 프로젝트에 Ribbon UI 를 적용하였습니다.
툴바가 같이 나오네요..  툴바를 Create하는 구문을 Comment Out 하시면 나오지 않게 되겠죠?  이제 다음 포스트에서 리본에 여러가지 기능을 적용해 보겠습니다.


답글 남기기

이메일 주소는 공개되지 않습니다.