728x90

MainFrame Class, View Class 참조

CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
CCeSerialView* pView = (CCeSerialView*)pFrame->GetActiveView();
위와같이 참조하기 위해선 메인프레임, 도큐먼트, 뷰 헤더파일 인클루드

#include "CeSerial.h"
#include "MainFrm.h"
#include "CeSerialDoc.h"
#include "CeSerialView.h"

App 헤더파일을 인클루드 하지않으면 아래와 같은 에러 발생 

error C2065: 'IDD_CESERIAL_FORM' : undeclared identifier
error C2057: expected constant expression

CTestSendDlg *p_Dlg = (CTestSendDlg*)AfxGetMainWnd(); 임의클래스에서 다이얼로그 참조

------------------------------------------------------------------------------------------------

MFC로 프로그래밍을 하다 보면, 각 클래스에 어떻게 접근해서 포인터를 얻어와야 하는지 매우 어려울 때가 많다... 
특히 초중급자 시절엔 말이다.. 사용한 지 오래 되어도 여전히 헷갈리기는 매 한가지다.자 그럼.. 하나씩.. 이해해 보자.

우선 MFC로 프로그램을 만들면, 다음과 같이 클래스가 생성된다. 프로젝트 명을 Test라고 가정해 보자.

CTestApp - CWinApp 클래스를 상속, 프로그램 초기화 클래스 (InitInstance)

CMainFrame - CFrameWnd 클래스를 상속, 전체 윈도우 관련 클래스(툴바, 메뉴, 상태바 등등)

CTestDoc - CDocument 클래스를 상속, 문서 관련 클래스(Open, Save, Serialize)

CTestView - CView 클래스를 상속, 사용자 화면 클래스(OnPaint, OnDraw)

CAboutDlg - CDialog 클래스를 상속, 도움말 대화 상자 클래스(DoModal)

------------------------------------------------------------------------------------------------


우선 가장 쉬운 것부터 설명하자면, 
어느 곳에서나 CTestApp의 포인터를 얻고자 한다면, 다음과 같이 코딩한다.
AfxGetApp()는 전역 함수이므로 어느 곳에서나 호출할 수 있다.

CTestApp* pApp = AfxGetApp();

하지만 위와 같이 사용하면, 다음과 같은 에러가 발생한다.

error C2440: 'initializing' : cannot convert from 'class CWinApp *' to 'class CTestApp *'

에러를 보면, CWinApp*를 CTestApp*로 변환할 수 없다는 것인데, AfxGetApp()의 함수 원형이

CWinApp* AfxGetApp();

이기 때문이다. 그래서 이 문제를 해결하기 위해서는 아래와 같이 형변환(casting)을 해 주어야 한다.

CTestApp* pApp = (CTestApp*)AfxGetApp();

이제는 컴파일 에러 없이 잘 될 것이다. 그리고 다음과 같은 에러가 발생될 수도 있느데,

error C2065: 'CTestApp' : undeclared identifier

이는 CTestApp 클래스의 선언 부분이 포함(include)되지 않았기 때문이다. 이럴 때는

CTestApp 클래스의 선언을 다음처럼 포함시켜야 한다.

#include "Test.h"

pApp는 이미 생성되어 있는 CTestApp의 객체 포인터이기 때문에,
이젠 pApp 포인터를 통해 CTestApp 객체에 쉽게 접근할 수 있다. 만약에 CTestApp에 

int i;

라는 멤버 변수가 있었다면, 

pApp->i = 5;

와 같이 사용할 수 있다. 또한 멤버 함수 func()가 있다면,

pApp->func();

처럼 접근할 수 있다. 주의해야 할 것은 객체 접근이기 때문에 public 속성의 멤버들만 접근할 수 있고, 
private와 protected는 접근할 수 없음에 유의해야 한다.

------------------------------------------------------------------------------------------------

두 번째는 CMainFrame의 포인터을 얻어 오는 방법이다. 다음과 같이 사용하려 할 때,

CMainFrame* pFrame = AfxGetMainWnd();

두 가지 에러와 만나게 된다.

첫 번째, CMainFrame에 대해서 컴파일러가 모르겠다는 에러이다.

error C2065: 'CMainFrame' : undeclared identifier

이 에러를 수정하기 위해서는 CMainFrame 클래스가 선언되어 있는 헤더 파일을

다음처럼 포함시키면 된다. 그리고 포함시키는 위치도 Test.h와 TestDoc.h 사이가 좋다.

그것은 클래스들간에 서로 관계가 있기 때문에 포함 순서는 매우 중요하다.


#include "stdafx.h"
#include "Test.h"


#include "MainFrm.h"


#include "TestDoc.h"
#include "TestView.h"

이 에러를 해결하고 나면, 다음과 같이 CTestApp에서 발생했던 에러가 발생한다.


error C2440: 'initializing' : cannot convert from 'class CWnd *' to 'class CMainFrame *'

에러를 보면, CWnd*를 CMainFrame*로 변환할 수 없다는 것인데, AfxGetMainWnd()의 함수 원형이


CWnd* AfxGetMainWnd();


이기 때문이다. 그래서 이 문제를 해결하기 위해서는 아래와 같이 형변환(casting)을 해 주어야 한다.


CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();


이제는 컴파일 에러 없이 잘 될 것이다. CMainFrame은 CFrameWnd를 상속 받고, CFrameWnd는

CWnd를 상속 받기 때문에, pFrame 포인터를 통해서 CFrameWnd와 CWnd가 갖고 있는 모든 함수를

호출하여 사용할 수 있다. 만약 윈도우의 타이틀에 나오는 제목을 바꾸고 싶다면,


pFrame->SetWindowText( "야.. 바뀌어라" ); 
처럼 사용하면 된다. 

------------------------------------------------------------------------------------------------

CMainFrame*는 또 다른 이유로 자주 사용하게 되는데, 그 이유는 도큐먼트(CTestDoc)와

뷰(CTestView) 클래스에 접근하기 위해서이다. CMainFrame 클래스는 뷰에 접근하는 GetActiveView(); 함수와

문서에 접근하는 GetActiveDocument() 함수를 제공한다.


우리가 어느 특정 클래스를 만들어서 사용하고, 이 클래스가 뷰에 접근해야 한다면 다음과 같은 문장을 사용해야 한다.


CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();

CTestView* pView = (CTestView*)pFrame->GetActiveView();


만약 도큐먼트 클래스에 접근해야 한다면,


CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();

CTestDoc* pDoc = (CTestDoc*)pFrame->GetActiveDocument();


물론 이 때는 각각의 클래스에 대한 헤더를 반드시 포함시켜야 함을 잊지 말아야 된다.

가끔 아래와 같은 순서로 헤더를 포함시키지 않는 경우가 있는데, 반드시 아래와 같이 포함해야 한다.


#include "MainFrm.h"

#include "TestDoc.h"

#include "TestView.h"


만약 대화 상자에서 도큐먼트 클래스에 접근하려면 어떻게 할 것인가? 방법은 위와 동일하다.

------------------------------------------------------------------------------------------------

다음은 뷰에서 도큐먼트에 접근하는 것과 도큐먼트에서 뷰에 접근하는 것에 대해 알아보자.

뷰와 도큐먼트는 서로를 직접 접근할 수 있는 함수가 제공된다. 뷰에서 도큐먼트를 직접 접근하려면, 

CTestDoc* pDocument = (CTestDoc*)GetDocument();

를 호출하면 된다. 물론 View 클래스에는 GetDocument() 함수가 존재해야 한다. 일반적으로 이 함수는

MFC로 프로젝트 생성 시 기본적으로 있다. 하지만 만약 직접 만든 새로운 클래스라면 GetDocument() 함수를

직접 만들어줘야 한다. 직접 만들기가 귀찮다면, 다음과 같이 사용해도 된다.

CTestDoc* pDocument = (CTestDoc*)m_pDocument;

m_pDocument는 CTestView 클래스의 멤버이며, 다음과 같이 선언되어 있다.

CDocument* m_pDocument;


그리고, 도큐먼트에 뷰 클래스를 참조하려면 아래와 같이 해야 한다.


POSITION pos = GetFirstViewPosition();
CTestView* pView = (CTestView*)GetNextView( pos );

도큐먼트는 뷰 클래스를 내부적으로 링크드리스트를 사용해서 관리하고 있다. 그러므로 GetFirstViewPosition()

함수를 통해 POSITION을 얻어 온 다음, GetNextView() 함수를 통해 뷰의 포인터를 얻어오면 된다.

만약 창 분할에 의해 뷰가 여러 개 존재한다면, 다음과 같이 얻어 올 수 있다. 만약 컴파일 에러가 발생하면,

#include "TestView.h" 처럼 해서 헤더 파일을 포함하는 것도 잊지 말자.


POSITION pos = GetFirstViewPosition();
CTestView1* pView1 = (CTestView1*)GetNextView( pos );

CTestView2* pView2 = (CTestView2*)GetNextView( pos );
CTestView3* pView3 = (CTestView3*)GetNextView( pos );
CTestView4* pView4 = (CTestView4*)GetNextView( pos );
...

------------------------------------------------------------------------------------------------

그렇다면,,, CTestApp 클래스에서 뷰(CTestView) 클래스는 어떻게 얻어 올 수 있을까? 쉽게 응용할 수 있지만

머리가 꽉 막힐 수도 있다. 이 곳에서도 혹시 에러가 나면 헤더 파일을 자~알 추가해야 할 것이다.


CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
CTestView* pView = (CTestView*)pFrame->GetActiveView();

------------------------------------------------------------------------------------------------

마지막으로, 뷰(CTestView) 클래스에서 CMainFrame에 접근할 수 있는데 AfxGetMainWnd() 함수외에도

CMainFrame* pFrame = (CMainFrame*)GetParentFrame();

------------------------------------------------------------------------------------------------

MDI 환경에서 포인터를 가져와 보자.

CTestApp* pApp = (CTestApp*)AfxGetApp();

POSITION pos = pApp->GetFirstDocTemplatePosition();
    
CDocTemplate* pDocTemplate;
pDocTemplate = pApp->GetNextDocTemplate( pos );
  
// 첫 번째 등록한 템플릿
pDocTemplate->OpenDocumentFile( NULL );               // 첫 번째 문서 생성


POSITION posDoc = pDocTemplate->GetFirstDocPosition();
CTestDoc* pDoc = (CTestDoc*)pDocTemplate->GetNextDoc( posDoc );
  // 첫 번째 문서 포인터
ASSERT( pDoc->IsKindof( RUNTIME_CLASS(CMongDoc) ) );                   // 포인터 유효성 검사
//CXXXDoc* pDoc2 = (CXXXDoc*)pDocTemplate->GetNextDoc( posDoc );             // 두 번째 문서 포인터

POSITION posView = pDoc->GetFirstViewPosition();
CTestView* pView = (CTestView*)pDoc->GetNextView( posView );
       // 첫 번째 뷰 포인터
ASSERT( pView->IsKindof( RUNTIME_CLASS(CTestView) ) );                // 포인터 유효성 검사

//CXXXView* pView2 = (CXXXView*)pDoc->GetNextView( posView );                 // 두 번째 뷰 포인터
//ASSERT( pView2->IsKindof( RUNTIME_CLASS(CXXXView) ) );                         // 포인터 유효성 검사

// 다음 템플릿이 존재할 경우만 가능합니다.

pDocTemplate = pApp->GetNextDocTemplate( pos );  // 두 번째 등록한 템플릿
if( pDocTemplate )                                                         
// 두 번째 템플릿이 존재하는지 검사

{

    pDocTemplate->OpenDocumentFile( NULL );          // 두 번째 문서 생성

}

------------------------------------------------------------------------------------------------

분할 뷰에서는 위의 방법과 같이 포인터를 얻어 올 수 있다. 또는 다음과 같은 방법으로 얻어 올 수 있다.

만약 창이 두 개로 분할되어 있다면,


CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();

CTestView* pView1 = (CTestView*)pFrame->m_wndSplitter.GetPane(0,0);   // 첫 번째 뷰 포인터 얻기

CXXXView* pView2 = (CTestView*)pFrame->m_wndSplitter.GetPane(0,1);   // 두 번째 뷰 포인터 얻기


뷰 포인터는 다음과 같이 좌표를 사용하여 구할 수 있다.


------------------------------------------------------------------
|                                |                               |
|         GetPane( 0, 0 )        |     GetPane( 0, 1 )           |
|                                |                               |
------------------------------------------------------------------
|                                |                               |
|         GetPane( 1, 0 )        |     GetPane( 1, 1 )           |
|                                |                               |
---------------------------------------------------------------------------------------------
|                                |                               |                          |
|         GetPane( 2, 0 )        |     GetPane( 2, 1 )           |     GetPane( 2, 2 )      |
|                                |                               |                          |
---------------------------------------------------------------------------------------------

728x90

+ Recent posts