<분할 윈도우에서 뷰 바꾸기>

분할 윈도우에서 한쪽 창의 버튼을 눌렀을 때 다른 창의 뷰가 새로운 뷰로 전환되도록 하려고 하는데 잘 안되네요. 방법을 일러주세요.

CSplitterWnd에서 상속받은 다른 클래스를 하나 생성하고, 다음과 같은 함수를 하나 만듭니다.

BOOL CSplitter::ReplaceView(int row, int col,
     CRuntimeClass *pViewClass, Size size)
{
     CCreateContext context;
     BOOL bSetActive;

     if((GetPane(row, col)->IsKindOf(pViewClass)) == TRUE)
          return FALSE;

     // CDocument *pDoc = GetParentFrame()->GetActiveDocument();

     // Get pointer to CDocument object so that it can be used
     // in the creation process of the new view

     CDocument *pDoc = ((CView *)GetPane(row, col))->GetDocument();
     CView *pActiveView = GetParentFrame()->GetActiveView();
     if(pActiveView == NULL || pActiveView == GetPane(row, col))
          bSetActive = TRUE;
     else
          bSetActive = FALSE;

     // set flag so that document will not be deleted when view is
     // destroyed
     pDoc->m_bAutoDelete = FALSE;

     // Delete existing view
     ((CView *)GetPane(row, col))->DestroyWindow();

     // set flag back to default
     pDoc->m_bAutoDelete = TRUE;

     // Create new view
     context.m_pNewViewClass = pViewClass;
     context.m_pCurrentDoc = pDoc;
     context.m_pNewDocTemplate = NULL;
     context.m_pLastView = NULL;
     context.m_pCurrentFrame = NULL;

     CreateView(row, col, pViewClass, size, &context);

     CView *pNewView = (CView *)GetPane(row, col);

     if(bSetActive == TRUE)
          GetParentFrame()->SetActiveView(pNewView);

     RecalcLayout();
     GetPane(row, col)->SendMessage(WM_PAINT);

     return TRUE;
}

 

<MDI에서 Child LIST를 얻는 방법>

MDI 애플리케이션을 제작하고 있습니다. 그런데 프로그램 실행 중 임의의 시간에 모든 열려진 MDI의 CHILD 내용을 주기적으로 저장하고 싶습니다. 그래서 제 생각에 모든 CHILD에 'Save Message' 또는 함수를 콜하고자 합니다. 꼭 모든 CHILD 가 아닌 경우도 있는데 특정 CHILD를 찾아서 작업을 할 때도 있습니다. 이 때 어떻게 원하는 CHILD를 찾을 수 있는지요?

 질문에서 현재 MDI를 단일 템플릿(Single Template)으로 구성한 건지, 멀티 템플릿(Multi Template)으로 구성한 건지 설명돼 있지 않아서 일단 멀티 템플릿인 경우를 기준으로 설명하겠습니다. 단일 템플릿인 경우는 앞의 템플릿을 찾는 부분 이하만 보면 됩니다. 일단 여러 템플릿이 등록돼 있는 경우 각 템플릿은 고유의 이름을 갖습니다. 따라서 각 템플릿의 포인터를 루프(Loop)에서 모두 이름으로 검색해 찾습니다. 코드는 다음과 같은 형태가 되겠습니다.

POSITION curTemplatePos = GetFirstDocTemplatePosition();
while(curTemplatePos != NULL) {
     CDocTemplate* curTemplate = GetNextDocTemplate(curTemplatePos);
     CString str;
     curTemplate->GetDocString(str, CDocTemplate::docName);
     if(str == sDocName)
        다음 처리.....
}

 그 다음 하나의 템플릿이 결정되면 해당 템플릿 아래의 각 도큐먼트를 비슷한 방법으로 찾아냅니다. 그 함수는 GetFirstDocPosition() 과 GetNextDoc 인데 위의 템플릿을 찾을 때와 같은 방법으로 루프에서 찾으면 됩니다. 이 때 찾는 기준은 직접 만들어야 합니다(변수를 사용하거나 윈도우 타이틀로 하든지 하면 됩니다). 그 다음 만약 해당 도큐먼트의 뷰(View)에 접근하고자 할 때는 도큐먼트당 하나 이상의 뷰가 있을 수 있으므로 또다시 같은 로직으로 다음의 함수들을 사용해 뷰 포인터(View Pointer)를 얻으면 됩니다.

GetFirstViewPosition(), GetNextView

 물론 루프에서 하나씩 검색해야 합니다. 보통의 경우 하나의 도큐먼트에 하나의 뷰이니까 첫째 뷰 포인터를 그냥 사용하면 됩니다.

 

<CEdit에서 엔터키 감지하기>

에디트 컨트롤에서 엔터키를 감지하는 방법을 알고 싶습니다.

기존 컨트롤에 질문한 것과 같이 어떤 다른 기능을 넣고자 할 경우는 일반적인 방법으로는 되지 않습니다. 가장 쉽게 할 수 있는 방법으로는 SubClassing 기법을 사용하면 됩니다. 서브클래스란 어떤 객체(Object)에서 발생하는 모든 메시지를 어떤 다른 클래스의 객체로 보낼 수 있도록 하는 것인데(정확한 의미는 아니지만), CWnd::SubClassDlgItem 함수를 사용해 서브클래싱하면 됩니다.

 방법은 CEdit 클래스에서 상속받은 새로운 클래스를 만들고 해당 클래스에서 키입력처리 Member 함수를 오버라이드해 엔터키 처리를 해 줍니다. 그 다음 새로 만든 클래스의 객체로 원하는 에디트 컨트롤을 서브클래스해 주기 바랍니다. 이렇게 하면 엔터키 뿐만 아니라 원래 컨트롤이 가지는 디폴트 기능을 원하는대로 바꿀 수 있게 됩니다.

- the end of this article -