티스토리 뷰

프로그래밍/MFC

MFC SDI

에어버스 2016. 7. 3. 12:32

MFC SDI (Single Document Interface)

하나의 응용프로그램에서 어느 한 순간에 하나의 문서만을 대상으로 작업할 수 있는 사용자 인터페이스

- 도큐먼트 객체

응용프로그램에 오직 하나만 존재

- 뷰 객체

응용프로그램의 필요에 따라 여러개(화면분할) 생성 가능. (View Splitter)

- 도큐먼트 프레임 윈도우 (Document Frame Window)

SDI 에서는 메인 윈도우
도큐먼트의 내용을 화면에 표시하는 뷰를 자식으로 갖는 윈도우
뷰의 부모윈도우

<객체간 상호 작용>

SDI 프로젝트를 만들면 프로젝트명App, 프로젝트명Doc, 프로젝트명View, CMainFrame(도큐먼트 프레임 윈도우) 클래스들이 자동으로 만들어지고, 위 그림에 나와있는 도큐먼트 템플릿(CSingleDocTempakte)은 아래 코드처럼 프로젝트App::InitInstance() 내에서 객체가 만들어 진다.

1
2
3
4
5
6
7
8
9
10
11
12
BOOL CMFCApplication12App::InitInstance()
{
...
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CMFCApplication12Doc),
        RUNTIME_CLASS(CMainFrame),       // 주 SDI 프레임 창입니다.
        RUNTIME_CLASS(CMFCApplication12View));
    if (!pDocTemplate)
        return FALSE;
}
cs

 

- CWinApp* AfxGetApp()

응용프로그램 객체의 주소를 리턴. 전역함수
CWinApp 클래스의 멤버함수를 호출할때는 그대로 사용하지만 그렇지 않을때는 반드시 형변환을 해야 한다.

1
2
CMyApp* pMyApp = (CMyApp*)AfxGetApp();
pMyApp->Doit();
cs

- CWnd* AfxGetMainWnd()

메인 윈도우 객체의 주소를 리턴, 전역함수
CWnd 클래스의 멤버함수외 함수를 호출하려면 형변환 해야 한다.

1
2
CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();
pMainFrame->DoThat();
cs

- CFrameWnd* CWnd::GetParentFrame()

부모 윈도우 중 CFrameWnd 또는 CFrameWnd 파생 클래스에 속한 해당 윈도우 객체 주소를 리턴
일반적으로 도큐먼트 프레임 윈도우가 된다.

- CView* CFrameWnd::GetActiveView()

사용자가 현재 작업하고 있는 활성 뷰(Active View) 객체의 주소를 리턴

- CDocument* CView::GetDocument()

하나의 뷰 객체는 반드시 하나의 도큐먼트 객체와 연결되어 있다. 뷰 객체와 연결된 도큐먼트 객체의 주소를 리턴, 뷰 객체가 생성될때 멤버변수인 m_pDocument 가 이 도큐먼트 객체의 주소로 초기화 된다.

실제 코드도 m_pDocument 값을 리턴한다.

1
2
3
4
5
CMFCApplication11Doc* CMFCApplication11View::GetDocument() const // 디버그되지 않은 버전은 인라인으로 지정됩니다.
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCApplication11Doc)));
    return (CMFCApplication11Doc*)m_pDocument;
}

cs

 

POSITION CDocument::GetFirstViewPosition()
CView* CDocument::GetNextView(POSITION& rPosition)

도큐먼트 객체는 자신과 연결된 뷰를 연결 리스트로 관리한다.

GetFirstViewPosition()는 연결 리스트의 시작점에 해당하는 POSITION 타입의 값을 리턴
이 값을 이용하여 GetNextView()를 호출할 때마다 뷰 객체의 주소를 순서대로 얻을 수 있다.

1
2
3
4
5
    POSITION pos = GetFirstViewPosition();
    while (pos != NULL) {
        CView* pView = GetNextView(pos);
        ...
    }
cs

POSITION CWinApp::GetFirstDocTemplatePosition();
CDocTemplate* CWinApp::GetNextDocTemplate(POSITION& pos);

응용프로그램 객체는 도큐먼트 템플릿 객체를 연결 리스트로 관리한다.

POSITION CDocTempalte::GetFirstDocPosition();
CDocument* CDocTempalte::GetNextDoc(POSITION& rPos);

도큐먼트 템플릿 객체는 도큐먼트 객체를 연결 리스트로 관리한다.

CDocTemplate* CDocument::GetDocTemplate();

도큐먼트 객체가 도큐먼트 템플릿 객체의 주소를 얻을때 사용한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
BOOL CMFCApplication11App::InitInstance()
{
...
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CMFCApplication11Doc),
        RUNTIME_CLASS(CMainFrame),       // 주 SDI 프레임 창입니다.
        RUNTIME_CLASS(CMFCApplication11View));
    if (!pDocTemplate)
        return FALSE;
    AddDocTemplate(pDocTemplate);
}
cs

6행의 IDR_MAINFRAME 은 리소스의 String Table 에 있으며
프레임 윈도우 제목, 새로 생성되는 문서의 제목, 파일 확장자 등의 정보를 가지고 있다.

<문자열 의미> '\n' 으로 구분

MFCApplication11\n\nMFCApplication1\nMFCApplication11 Files (*.sdi)\n.sdi\nMFCApplication11.Document\nMFCApplication11.Document

 

순서

 의미

 MFCApplication11

 프레임 윈도우의 타이틀 바에 표시되는 제목

 

 새 문서의 제목, 생략하면 기본값은 '제목없음' 이다

 MFCApplication1

 MDI에서만 사용, 새 문서를 생성할때 도큐먼트 타입을 묻는 대화상자에 표시될 문자열

 MFCApplication11 Files (*.sdi)

 열기 또는 저장하기 대화상자에 표시  

 .sdi

 파일의 기본 확장자 

 MFCApplication11.Document

 레지스트리에 등록되는 도큐먼트 타입 ID, 공백 문자는 안된다. 

 MFCApplication11.Document

 레지스트리에 등록되는 도큐먼트 타입 문자열, 공백문자 안된다.

void CDocument::SetModifiedFlag(BOOL bModified = TRUE);

도큐먼트 객체가 유지하는 데이터를 수정하는 경우 이 함수를 호출해서 도큐먼트 객체에게 알려준다.
수정된 내용을 디스크에 저장하지 않은 상태로 종료하거나 새 문서를 작성하려고 하면 변경한 내용을 저장할 건지 묻는 대화상자가 뜨게 된다.

void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL);

도큐먼트 객체가 유지하는 데이터가 수정될 경우 모든 뷰 객체에게 이 사실을 알려줄 필요가 생긴다. 그래야만 뷰 객체가 자신의 화면을 갱신할 수 있기 때문이다. 내부 코드는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL)
{
...
    POSITION pos = GetFirstViewPosition();
    while (pos != NULL)
    {
        CView* pView = GetNextView(pos);
        if (pView != pSender)
            pView->OnUpdate(pSender, lHint, pHint);
    }
}
cs

CDocument::UpdateAllViews() 는
CView::OnUpdate() - CWnd::Invalidate() - CWnd::OnPaint() - CView::OnDraw() 를 순서대로 호출하게된다.

UpdateAllViews(NULL) - 모든 뷰를 갱신
UpdateAllViews(this) - 특정 객체(this)를 제외한 모든 뷰를 갱신

virtual BOOL CDocument::OnNewDocument();

새 문서를 생성할 때 (파일-새파일 메뉴) 자동으로 호출되는 함수
MDI는 새 문서가 생설될때 마다 새 도큐먼트 객체를 생성하지만 SDI는 하나의 도큐먼트 객체를 초기화해서 재사용 하므로 도큐먼트 클래스의 생성자 보다 OnNewDocument() 에서 초기화 코드를 추가해야만 한다.

virtual BOOL CDocument::onOpenDocument(LPCTSTR lpszPathName);

파일- 열기 메뉴를 선택할때 자동으로 호출되는 함수
새 파일을 열때마다 필요한 작업은 여기에 추가한다.

virtual void CDocument::DeleteContents();

OnNewDocument(), OnOpenDocument() 함수 이전에 자동으로 호출하는 가상함수
SDI에서 도큐먼트 객체를 재사용하기 위해서 새 문서를 생성하거나 열때마다 기존의 데이터를 삭제할 필요가 있다. 이 함수는 도큐먼트 객체 데이터를 삭제하는 등의 초기화 코드를 추가에 좋은 위치다.

virtual void CDocument::Serialize(CArchive& ar);

파일을 열거나 저장할때 자동으로 호출되는 함수

파일-새파일 일때 호출 순서> DeleteContents() - OnNewDocument()
파일-열기 일때 호출 순서> DeleteContents() - Serialize() - onOpenDocument()
파일-저장 혹은 파일-다른이름으로 저장 일때 호출 순서> Serialize()

virtual void CView:;OnDraw(DCD* pDC);

CView 클래스에서 순수 가상함수로 선언되어 있으므로 반드시 재정의해야 한다.
화면 출력, 인쇄, 인쇄 미리보기를 할때 자동 호출된다.

virtual void CView::OnInitialUpdate();

뷰 객체가 도큐먼트 객체와 연결된 후 화면에 보이기 전에 자동으로 호출되는 함수
CView:;OnUpdate()를 호출하여 뷰의 화면을 무효화 시킨다.

virtual void CView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);

CDocument::UpdateAllViews()와 CView::OnInitialUpdate() 에서 호출하는 가상함수
기본 구현에 해당하는 CView::OnUpdate()는 CWnd::Invalidate()를 이용하여 뷰의 화면 전체를 무효화 시킨다. 좀 다 효과적인 화면 갱신이 필요한 경우 이 함수를 재정의하고 두번째 인자를 참조하여 뷰의 화면 일부만 무효화 시킬 수 있다.

<효과적인 화면 갱신>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
UpdateAllView(NULL1, (CObject*)pRect);
 
void CMFCApplication11View::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
    if (lHint == 1)
    {
        CRect* pRect = (CRect*)pHint;
        InvalidateRect(pRect);
        return;
    }
    CView::OnUpdate(pSender, lHint, pHint);
}
 
void CCMFCApplication11View::OnDraw(CDC* pDC)
{
...
    CRect rect;
    pDC->GetClipBox(&rect);
    // 사각형을 다시 그린다.
}
cs
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31