MFC에서는 클래스들 간 서로를 참조하는 기능들이 마련되어 있습니다.
상호 참조를 위한 함수들은 다음과 같습니다.
이제부터는 프로젝트명을 Example이라 가정 후 설명하겠습니다.
CExampleApp |
CWinApp 클래스 상속, 프로그램 초기화 클래스 |
CMainFrame |
CFrameWnd 클래스 상속, 전체 윈도우 관련 클래스 |
CExampleDoc |
CDocument 클래스 상속, 문서 관련 클래스 |
CExampleView |
CView 클래스 상속, 사용자 화면 클래스 |
CAboutDlg |
CDialog 클래스 상속, 도움말 대화 상자 클래스 |
1. 메인 프레임 윈도우( CExampleAPP ) 참조
CWinApp* AfxGetApp();
- CWinApp 파생클래스의 인스턴스 포인터를 반환해 줍니다.
ex)
#include Example.h
CExampleApp* pApp = (CExampleApp*)AfxGetApp();
2. 메인 프레임 윈도우( CMainFrame ) 참조
CWnd* AfxGetMainWnd();
- 메인 프레임 클래스의 인스턴스 포인터를 반환해 줍니다.
ex)
#include "MainFrm.h"
CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
① 프레임 윈도우에서 뷰( CExampleView ) 참조
CView* CFrameWnd::GetActiveView();
- 프레임 윈도우에서 뷰를 참조합니다.
현재 프레임 윈도우와 연결된 뷰 중 활성화 된 것의 포인터를 반환합니다.
ex)
CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
CExampleView* pView = (CExampleView*)pFrame->GetActiveView();
② 프레임 윈도우에서 도큐먼트 ( CExampleDoc ) 참조
virtual CDocument* CFrameWnd::GetActiveDocument();
- 프레임 윈도우 클래스에서 도큐먼트 클래스를 참조합니다.
현재 프레임 윈도우와 연결된 도큐먼트 중 활성화 된 것의 포인터를 반환합니다.
ex)
CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
CExampleDoc* pDoc = (CExampleDoc*)pFrame->GetActiveDocument();
대화 상자에서도 동일합니다.
3. 뷰에서 프레임 윈도우/도큐먼트( CExampleDoc ) 참조
① 도큐먼트 참조
CDocument* CView::GetDocument();
- 뷰 클래스와 연결된 도큐먼트 클래스를 참조합니다.
CView클래스의 멤버 함수로써 CView클래스에서만 사용할 수 있습니다.
어떤 뷰와 연결된 도큐먼트는 오직 하나만 존재하기 때문입니다.
ex)
CExampleDoc* pDocument = (CExampleDoc*)GetDocument();
☞ MFC로 프로젝트 생성 시 기본적으로 생성되는 함수이지만,
만약 직접 만든 클래스라면 GetDocument()함수를 직접 만들어 주거나
CExampleView 클래스의 멤버인 m_pDocument 를 사용해도 됩니다.
① 자식 프레임 윈도우 참조
CFrameWnd* CWnd::GetParentFrame();
- 뷰를 둘러싸고 있는 프레임을 참조합니다.
프레임 윈도우는 뷰 뿐 아니라, 일반적인 윈도우를 둘러싸는 틀로써 사용될 수 있기 때문에,
CWnd 클래스의 멤버 함수로 되어 있습니다.
물론 CView에서도 사용할 수 있습니다.
단일 도큐먼트 프로그램에선 AfxGetMainWnd함수와 GetParentFrame 함수의 반환 값이 같습니다.
하지만 다중 도큐먼트 프로그램에선 함수가 서로 구별됩니다.
ex)
CMainFrame* pFrame = (CMainFrame*)GetParentFrame();
4. 도큐먼트에서 뷰/프레임 윈도우 참조
① 뷰 참조
하나의 도큐먼트에 여러 개의 뷰가 결합되어 리스트로 관리되고 있습니다.
GetFirstViewPosition 함수와 GetNextView 함수를 조합하여 사용합니다.
ex)
POSITION pos = GetFirstViewPosition(); // 첫번째 뷰가 매달려 있는 포인터
while ( pos != NULL )
{
CView * pView = GetNextView( pos ); // 다음 뷰들의 포인터
// to do
}
- 뷰가 하나인 경우
m_viewList: CDocument 클래스의 멤버 변수로 뷰를 관리하는 연결 리스트.
ex)
CView* pView = m_viewList.GetHead();
5. 도큐먼트 템플릿에서 도큐먼트/뷰/자식 프레임 윈도우 참조
다중 도큐먼트 프로그램에는 여러 개의 도큐먼트/뷰/자식 프레임이 있을 수 있습니다.
같은 타입의 클래스의 인스턴스가 두 개 이상 존재하는 것들은 연결리스트로 이루어져 있습니다.
노드를 참조하는 함수는 모두 다음과 같은 형식입니다.
POSITION pos = GetFirstXXXPosition();
while( !pos != NULL )
{
XXX xx = ( XXX* )GetNextXXX(pos);
// to do
}
ex)
CWinApp *App = AfxGetApp();
POSITION posTemplate = pApp-> GetFirstDocTemplatePosition();
// POSITION CWinApp::GetFirstDocTemplatePosition();
while( posTemplate )
{
CDocTemplate * pTemplate = pApp-> GetNextDocTemplatePosition( posTemplate );
// CDocTemplate* CWinApp::GetNextDocTemplatePosition( POSITION& pos );
POSITION posDoc = pTemplate-> GetFirstDocPosition();
// virtual POSITION CDocTemplate::GetFirstDocPosition();
while( posDoc )
{
CDocument *pDoc = pTemplate->GetNextDoc( posDoc );
// virtual CDocument* CDocTemplate::GetNextDoc( POSITION& rPos );
POSITION posView = pDoc-> GetFirstViewPosition();
// virtual POSITION CDoccument::GetFirstViewPosition();
while( posView )
{
CView *pView = pDoc->GetNextView( posView );
// virtual CView* CDocument::GetNextView( POSITION& rPosition );
// to do
}
}
}
6. 분할 뷰에서의 참조
위의 방법과 같이 포인터를 얻어 올 수 있거나 다음과 같은 방법으로 얻어 올 수 있습니다.
CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
CExampleView* pView1 = (CExampleView*)pFrame->m_wndSplitter.GetPane(0,0);
CXXXView* pView2 = (CXXXView*)pFrame->m_wndSplitter.GetPane(0,1);
뷰 포인터의 좌표는 다음과 같습니다.
GetPane( 0, 0 ) |
GetPane( 0, 1 ) |
GetPane( 1, 0 ) |
GetPane( 1, 1 ) |
GetPane( 2, 0 ) |
GetPane( 2, 1) |
[ 메시지를 이용한 통신 ]
- 포인터를 얻어 직접 서로의 함수를 호출할 수도 있지만 메시지를 보내어 간접적으로 함수가 호출되도록 할 수도 있습니다.
방법은 다음의 두 가지 방법이 있습니다.
① SendMessage 함수
LRESULT SendMessage( UINT message, WPARAM wParam=0, LPARAM lParam=0 );
- 윈도우에 메시지를 보내는 함수 입니다.
wParam, lParam은 추가적인 정보를 담기 위한 인자입니다.
CWnd 클래스의 멤버 함수 입니다.
CWnd 클래스에서 상속받지 않은 클래스는 호출할 수 없습니다.
메인 프레임 클래스 밖에서 메인 프레임 윈도우로 메시지를 보낼시 다음과 같이 하면 됩니다.
AfxGetMainWnd()-> SendMessage( ..., ..., ...);
ex)
AfxGetMainWnd()-> SendMessage( WM_COMMAND, ID_FILE_OPEN );
① PostMessage 함수
BOOL PostMessage( UINT message, WPARAM wParam=0, LPARAM lParam=0 );
- SendMessage 함수와 비슷하게 메시지를 보냅니다.
차이점은 메시지 큐를 거치느냐 아니냐 하는 것입니다.
SendMessage 함수는 메시지를 보내면 메시지 큐를 거치지 않고 직접 메시지 처리기를 호출합니다.
따라서, 호출과 동시에 해당하는 메시지 처리기가 호출됩니다.
반면, PostMessage 함수는 메시지를 메시지 큐에 넣어 주는 일만 합니다.
따라서, 메시지를 보내주면 현재 수행되고 있는 함수가 완전히 끝나고, 메시지 큐에 쌓여 있던 메시지들의 처리기가
다 수행되고 난후에야 PostMessage함수로 보낸 메시지의 처리기가 호출됩니다.
☞ 헤더파일 포함 순서.
#include "stdafx.h"
#include "Example.h"
#include "MainFrm.h"
#include "ExampleDoc.h"
#include "ExampleView.h"