포인터 얻기

개발/연구 / / 2006. 5. 23. 17:17
임의의 클래스의 포인터 얻기

Visual C++로 프로그램을 작성하고자 할 때, 가장 먼저 막히는 부분 중의 하나가 어떤 클래스 인스턴스의 포인
터를 얻는 것이죠. 일반적으로 뷰 클래스를 가장 많이 다루게 되고, 그 다음이 도큐먼트 클래스, 그 다음이 메인
프레임 클래스 순일 것입니다. 그리고 거의 변경할 필요가 없는 애플리케이션 클래스도 있구요.
물론 사용자가 만든 클래스나 버튼 같은 컨트롤에 관련된 클래스에 접근해야 할 경우도 있는데, 그럴 때 초보자
는 막막해 질 수밖에 없습니다. 경험담이기도 하죠.
여기서는 그러한 경우의 각 클래스의 포인터를 얻는 경우에 관해 알아봅니다.여기서는 프로젝트 이름이 Test라
고 가정하죠. 사용자에 따라 프로젝트의 이름이 다르겠죠?
그리고 중간에 참조되는 모든 클래스의 헤더파일이 인클루드 되어야 하구요. 뷰의 헤더가 인클루드 된다면 반드
시 그 앞에 도큐먼트의 헤더가 인클루드 되어야 합니다.


일반적인 SDI 프로그램에서.


1.애플리케이션 클래스의 포인터를 얻을 때
CWinApp* AfxGetApp()
함수를 사용합니다.


2.메인 프레임 클래스의 포인터를 얻을 때
CWnd* AfxGetMainWnd()
함수를 사용합니다.

이들 두 함수는 MFC의 전역함수로써 프로그램을 작성하는 도중 어디에서나 사용할 수 있습니다. MFC에서는 Afx~
로 시작하는 함수들은 모두 전역함수를 의미합니다.
물론 타입 캐스팅을 해야 하구요. 사용법은 다음과 같습니다.

CTestApp *pApp = (CTestApp *)AfxGetApp();
CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();

이렇게 써준 다음에는 pApp와 pFr은 각각 애플리케이션 클래스와 메인 프레임 클래스의 인스턴스 포인터를 가리키
게 됩니다.

이 외에 뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조할 때는

CFrameWnd* GetParentFrame() const

함수를 사용할 수 있습니다. 물론 뷰 클래스뿐만이 아니라 일반적인 윈도우를 둘러싸는 틀로써 프레임 윈도우가
사용될 수 있기 때문에 GetParentFrame() 함수는 CWnd() 클래스의 멤버함수로 되어있습니다.

이 함수와 AfxGetMainWnd() 함수는 SDI에서는 같은 기능을 하지만, MDI에서는 메인 프레임 윈도우와 뷰를 둘러
싸고 있는 프레임 윈도우가 다르기 때문에 그 각각을 구하는 역할을 합니다.


3.도큐먼트 클래스의 포인터를 얻을 때는 몇 가지 경우가 있습니다.

(a) 뷰 클래스에서 도큐먼트 클래스에 접근할 때.

이때는 말할 필요도 없이 GetDocument() 함수를 쓰면 됩니다. 뷰에 이미 정의되어 있는 함수죠. 하지만 사용자
가 임의로 뷰를 추가한 경우에는 이 GetDocument() 함수가 포함되어 있지 않습니다. 이럴 경우 기존에 있는 뷰에
서 GetDocument() 함수 부분을 복사해다가 넣으면 됩니다. 이 부분은 Debug 모드와 Release 모드 두 가지의 함
수가 있으므로 모두 복사해 넣아야 합니다.

(b) 임의의 클래스에서 도큐먼트 클래스에 접근할 때.

CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();
CTestDoc *pDoc = (CTestDoc *)pFr->GetActiveDocument();

위와 같이 두 줄에 걸쳐 써도 되고 다음처럼 한 줄로 줄여써도 됩니다.

CTestDoc *pDoc = (CTestDoc *) ((CMainFrame *)AfxGetMainWnd())->GetActiveDocument();


4. 뷰 클래스의 포인터를 얻을 경우.

(a) 임의의 클래스에서 뷰 클래스에 접근할 때

뷰 클래스의 포인터를 얻어야 하는 경우는 대부분 다이얼로그에서 뷰에 접근하거나, 스플릿을 사용한 경우 다른
뷰 클래스에서 접근하는 경우가 대부분일 겁니다. 뭐 어떻든 상관없이 다음과 같이 하면 어디서든 뷰에 접근할
수 있습니다.

CTestView *pView = (CTestView *) ((CMainWnd *)AfxGetMainWnd())->GetActiveView();
물론 위의 3번의 경우처럼 두 줄로 나누어 써도 상관이 없습니다.

(b) 도큐먼트 클래스에서 뷰 클래스에 접근을 할 때

도큐먼트 클래스에서 뷰 클래스의 인스턴스 포인터를 얻으려면 GetFirstViewPosition() 함수와 GetNextView()
함수를 조합하여 사용해야 합니다. 이렇게 복잡해지는 이유는 도큐먼트 하나에 여러개의 뷰가 연결될 수 있기 때
문입니다.

도큐먼트에는 이에 연결된 뷰가 연결 리스트 형태로 관리되고 있기 때문에 몇 번째 뷰를 얻을 것인지 선택하고 나
서 위의 함수를 조합하여 사용하면 됩니다.

다음은 도큐먼트와 연결된 모든 뷰 클래스를 차례로 얻어 뷰 클래스의 멤버함수인 UpdateWindow() 함수를 호출하
는 예제입니다.

POSITION pos = GetFirstViewPosition();

while(pos != NULL) {
CView *pView = GetNextView(pos);
pView->UpdateWindow();
}

물론 이와 같은 효과를 내기 위해서 도큐먼트 클래스의 멤버함수인 UpdateAllViews(NULL) 함수를 호출해도 됩니
다. 여기서 쓰이는 인자인 NULL 은 모든 뷰를 업데이트하는 것이고, NULL 대신, 신호를 보내는 뷰의 포인터를 넣
어주면 신호를 보내는 뷰는 빼고 나머지 뷰만 업데이트를 합니다.

도큐먼트에 뷰가 오직 하나만 연결되어 있는 경우에는 다음과 같이 간단하게 뷰 클래스의 인슽턴스 포인터를 얻
어낼 수도 있습니다. m_viewList 는 CDocument 클래스의 멤버변수로서, 뷰를 관리하는 연결 리스트입니다. 이것
을 이용하여 GetHead() 함수를 호출하면 리스트에 들어있는 첫 번째 뷰가 얻어집니다.

void CTestDoc::OnRepaintViews()
{
CView *pView = m_viewList.GetHead();
pView->UpdateWindows();
}

(c) 스플리트 윈도우에서의 각 뷰 클래스에 접근할 때

동적 스플리트 윈도우라면 모든 페인에서 같은 뷰를 사용하므로 별 문제가 되지 않는데, 정적 스플리트 윈도우라
면 각 페인마다 다른 뷰를 사용할 수 있으므로 각 페인별로 뷰의 인스턴스 포인터를 얻는 것이 문제가 되는 경우
가 생길 수 있습니다.

이렇때는 메인 프레임 클래스에서 정의한 CSplitterWnd 클래스의 변수인 m_wndSplitter 의 멤버함수 GetPane()
을 사용하면 각 페인의 뷰에 접근할 수 있습니다.

우선 메인 프레임에서 정의된 m_wndSplitter 변수를 public: 속성으로 바꾸고(외부에서 접근해야 하므로) 메인
클래스의 인스턴스 포인터를 얻은 다음, 다시 여기서 m_wndSplitter 변수에 접근하여 이 멤버변수의 멤버함수
GetPane()을 이용하면 됩니다. 다음은 GetPane()의 함수 원형입니다. 리턴값은 대부분의 경우 CView에서 파생
된 클래스의 인스턴스 포인터가 됩니다.

CWnd* GetPane( int row, int col );

임의의 클래스에서 다음과 같이 사용하면 페인에 연결된 뷰의 포인터를 얻을 수 있습니다.

CTestView *pView = (CTestView *)((CMainFrame *)AfxGetMainWnd())->m_wndSplitter.GetPane(0,1);




임의의 클래스의 포인터 얻기


앞에서 SDI에서 각 클래스의 포인터를 얻는 것은 해 보았습니다. 이번엔 MDI에서 이런 작업을 해 보도록 하죠.

먼저 SDI에서의 작업을 참조하시기 바랍니다. SDI와 MDI는 관련되는 부분이 많으니까요.


일반적인 MDI 프로그램에서.


1.애플리케이션 클래스의 포인터를 얻을 때

CWinApp* AfxGetApp()

함수를 사용합니다. 이것은 SDI에서와 동일합니다. App 클래스는 MDI든 SDI든 프로그램 내에서는 하나뿐이니까
요. 다음처럼 사용하면 pApp는 애플리케이션 클래스의 인스턴스 포인터를 가리키게 됩니다.

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


2. CMDIFrameWnd의 파생클래스인 메인 프레임 클래스의 포인터를 얻을 때

CWnd* AfxGetMainWnd()

함수를 사용합니다. 사용법은 SDI에서와 동일합니다.

CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();

이렇게 써준 다음에는 pFr은 메인 프레임 클래스의 인스턴스 포인터를 가리키게 됩니다.


3. CMDIChildWnd의 파생클래스인 자식 프레임 윈도우의 포인터를 얻을 때

(a) 활성화된 자식 프레임 윈도우의 포인터를 얻을 때

virtual CFrameWnd* GetActiveFrame( );

함수를 사용합니다. MSDN에 실려있는 이 함수의 리턴값에 대한 설명을 보면, 애플리케이션이 SDI이거나 MDI 프레
임 윈도우에 활성화된 도큐먼트가 없을 때, 리턴값은 묵시적인 this 포인터가 된다고 하네요.

사용법은 다음과 같습니다.

CMDIChildWnd* pChild = (CMDIChildWnd *)AfxGetMainWnd()->GetActiveFrame();


4. 뷰 / 도큐먼트 클래스의 포인터를 얻을 때

SDI에서 구한 것과 마찬가지 방법을 사용한다. SDI에서는 메인 프레임의 포인터를 얻어 GetActiveView() 또는
GetActiveDocument() 함수를 사용했지만, MDI에서는 차일드 프레임의 포인터를 얻어 거기서 GetActiveView
() / GetActiveDocument() 함수를 사용하면 된다. 사용법은 거의 동일하다.

MDI에서도 SDI와 마찬가지로 도큐먼트나 뷰가 여러 개가 연결될 수 있으므로 그점만 주의해 주면 된다.

사용법은 다음과 같다.

CMDIChildWnd* pChild = (CMDIChildWnd *)AfxGetMainWnd()->GetActiveFrame();

// 뷰 클래스의 포인터 얻기
CTestView *pView = (CTestView *)pChild->GetActiveView();

// 도큐먼트 클래스의 포인터 얻기
CTestDoc *pDoc = (CTestDoc *)pChild->GetActiveDocument();


복사해서 편집하기두 힘들군여
에구 힘들다... ^^;

좋은 주말 되세요
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기