ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [MFC] 임의의 클래스 포인터 얻기(SDI)
    프로그래밍/MFC 2005. 6. 24. 05:40

    * 프로젝트 이름은Test라고 가정. 

    * 중간에 참조되는 모든 클래스의 헤더파일이 인클루드 되어야 함.

    * 뷰의 헤더가 인클루드 된다면 반드시 그 앞에 도큐먼트의 헤더가 인클루드 되어야 함.

     

     

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

      CWinApp* AfxGetApp()

     

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

      CWnd* AfxGetMainWnd()

              이들 두 함수는 MFC의 전역함수로써 프로그램을 작성하는 도중 어디에서나  사용할수

              있다. MFC에서는 Afx~로 시작하는 함수들은 모두 전역함수를 의미한다.

              물론 타입 캐스팅을 해야하며, 사용법은 다음과 같다.

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

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

      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 *) ((CMainFrame *)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(introw,intcol);

       

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

            CTestView *pView = (CTestView *)((CMainFrame *)AfxGetMainWnd())->

                                                                         m_wndSplitter.GetPane(0,1);

    댓글