IT_Programming/MFC · API

여러 파일 한꺼번에 열기 / 각 클래스의 포인터 얻기 / 틀이 없는 윈도우

JJun ™ 2007. 12. 25. 14:05
LONG
 

 

<Dialog Box 생성자를 통해 데이터를 전달하는 방법>

 대화상자는 사용자와 프로그램간의 상호 의사전달을 용이하게 하는 도구이다. 사용자의 명령을 처리하기 위해 적당한 정보를 알려주고 또 필요한 정보를 입력받는다. 이 과정에서 대화상자는 모든 정보를 스스로 생성하여 제시하지는 않는다. 대화상자 자체가 프로그램의 부수적인 기능일 뿐이므로 대부분의 정보는 메인 프로그램이 갖게된다. 따라서 대화상자를 호출하기 전에 대화상자에서 필요한 데이터를 전달해 주어야 한다. (물론 그 데이터가 전역변수라면 상관이 없겠지만...)
여기서 하려는 얘기는 바로 그 전달 방법이다.

 

- 가장 일반적인 방법

참고서적의 가장 흔한 주제가 대화상자이고 거기서 빈번하게 사용하는 방법되는 코드는 다음과 같다.

CMyDlg dlg;

dlg.m_data = myData1;       // dialog box의 멤버변수에 직접 전달하는 경우.
dlg.SetData( myData2 );     // dialog box의 멤버함수를 사용하는 경우.
dlg.DoModal();

 

- 생성자를 통해 전달하는 방법

이렇게 하면 더 간단하지 않을까?

CMyDlg dlg( myData1, myData2 );    // dialog box의 생성자에 데이터 전달.

dlg.DoModal();

그러자면 클래스위저드가 생성해준 대화상자 클래스를 조금 수정해야 한다.
먼저 헤더파일의 클래스 선언중 생성자 원형을 다음과 같이 수정한다. 원래의 생성자는 지워도 되고 그대로 둔 채 새로운 생성자를 추가해도 된다.

class CMyDlg : public CDialog
{
public:
   CMyDlg( CWnd* pParent = NULL );              // 표준 생성자
   CMyDlg( MYDATA1 myData1, MYDATA2 myData2 );  
// 새로운 생성자
   ...
};

다음에 cpp 파일의 정의부분을 수정한다. 마찬가지로 기존의 생성자는 지워도 되고 그대로 둔 채 새로운 생성자함수를 추개해도 된다. 그대로 둘 경우엔 어떤 생성자를 사용해서 대화상자를 호출할 것인가는 프로그래머 맘대로다.

CMyDlg::CMyDlg( CWnd* pParent /*=NULL*/ ) : CDialog( CDbNewDlg::IDD, pParent )
{
   ...      
// 기존의 생성자
}

CMyDlg::CMyDlg( MYDATA1 myData1, MYDATA2 myData2 ) : CDialog(CMyDlg::IDD, NULL)
{
   ...      
// 새로운 생성자
}

위에서 MYDATA1, MYDATA2는 임의의 데이터형이다. 원래의 형태와 수정된 형태를 잘 비교해 보라.
생성자에 전달하는 인자의 데이터형과 갯수는 제한이 없다.
참, 생성자를 통해 전달된 인수는 생성자 함수 내에서만 유효하므로 생성자에서 대화상자의 적당한 멤버변수에 대입하여 저장해두어야 한다.  

 

<콘솔에 문자열 출력하기>

 콘솔에 문자열을 출력하기 위해 다음과 같은 코드를 사용한다.

    void CConsoleTest::OnButton1()
    {
            CString str;
            GetDlgItemText(IDC_EDIT1, str);
            AllocConsole();  
    // 새로운 콘솔 프로세스 할당
            DWORD dwWrite;

            
    // 콘솔 프로세스의 핸들을 얻는다.
            HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
            WriteFile(hOut, str, str.GetLength(), &dwWrite, NULL);  
    // 데이터 출력
            AfxMessageBox("콘솔 화면에 출력하기");  
    // 콘솔을 잠시 유지하기 위해 사용
            FreeConsole();  // 할당된 콘솔 해제
            SetDlgItemText(IDC_EDIT1, "");
    // 에디트 박스 내용 삭제
    }

 여기서는 새로운 다이얼로그를 하나 만들고, 거기에 에디트 박스와 버튼을 하나씩 추가한 후 그 ID를 각각 IDC_EDIT1, IDC_BUTTON1 으로 하고, 뷰에서 마우스 왼쪽 버튼을 더블 클릭하면 그 다이얼로그가 뜨도록 작성해 보았다. 물론 필요한 대로 다르게 작성해도 된다.

 단, 만약 위의 AfxMessageBox() 가 없다면 출력되자마자 콘솔이 사라져 버리므로 FreeConsole()을 적당한 장소에서 사용해야 할 것이다.

 

 

- the end of this article -

ARTICLE

<여러개의 파일 한꺼번에 열기>

 보통 MDI에서 파일을 열 때, 하나씩밖에 선택이 되지 않는데, 다음과 같이 onFileOpen() 함수를 오버라이드 하면 여러개의 파일을 선택할 수 있습니다. SDI에서 이거 쓸 필요 없겠죠??

 void CMultiSelApp::OnFileOpen()
{
       
 // TODO: Add your command handler code here
        static char BASED_CODE szFilter[] = "Image Files (*.bmp,*.dib)|*.bmp;*.dib||";
        PSZ pszFile=new char[32767];
        CFileDialog cfd(TRUE,".bmp",NULL,
                OFN_HIDEREADONLY|      
            OFN_OVERWRITEPROMPT|                
            OFN_FILEMUSTEXIST |                    
            OFN_EXPLORER|
            OFN_ALLOWMULTISELECT|
            OFN_LONGNAMES,
            szFilter);

        ZeroMemory(pszFile,32767);  
        cfd.m_ofn.lpstrFile=pszFile;
        cfd.m_ofn.nMaxFile=32767;
        cfd.m_ofn.nFileOffset=0;

        if(cfd.DoModal()==IDOK) {
                POSITION pos=cfd.GetStartPosition();
                while(pos!=NULL) {
                        CString csFile=cfd.GetNextPathName(pos);
                        OpenDocumentFile(csFile);
                }
        }
}

 

 

 <각 클래스의 포인터 얻기>

- SDI

CWinApp : AfxGetApp()
CMainFrame : AfxGetMainWnd()
CView 계열 : AfxGetMainWnd()->GetActiveView()
CDocument : AfxGetMainWnd()->GetActiveDocument()  

 

- MDI

CWinApp : AfxGetApp()
CMDIFrameWnd : AfxGetMainWnd()
CMDIChildWnd : AfxGetMainWnd()->GetActiveFrame()
CView 계열 : AfxGetMainWnd()->GetActiveFrame()->GetActiveView()
CDocument : AfxGetMainWnd()->GetActiveFrame()->GetActiveDocument()

 

 

<틀이 없는 윈도우>

 프로그램을 작성하다 보면 CD-ROM 타이틀처럼 메뉴도 없고, 툴바도 없고, 상태바도 없고, 캡션바도 없는 말 그대로 틀이 전혀 없는 그런 윈도우가 필요할 때가 있다. SDK에선 간단하지만 MFC에선 좀 까다로운 문제가 될 수 있다.

 MFC에서는 기본적으로 메뉴가 내장되기 때문에 이 메뉴를 해제하지 않고 크기와 스타일을 바꾸면 실행에러가 발생한다. 이 메뉴를 없애기 위해 새로운 메뉴를 만들고 이 메뉴를 메인프레임에 설정된 메뉴와 연결한다. 이때 Attach 함수를 이용한다. 이렇게 연결된 후 pMenu를 삭제하면 메인프레임의 메뉴 또한 삭제된다. 이렇게 한 후 메인프레임의 메뉴를 NULL로 설정하고, pMenu를 메모리에서 해제한다.

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
        if( !CFrameWnd::PreCreateWindow(cs) )
                return FALSE;
        
// TODO: Modify the Window class or styles here by modifying
        //  the CREATESTRUCT cs

        cs.style = WS_VISIBLE|WS_POPUP|WS_BORDER;
        int cx = GetSystemMetrics(SM_CXFULLSCREEN);
        int cy = GetSystemMetrics(SM_CYFULLSCREEN);
        cs.cx = 640;            
// 윈도우의 가로크기

        cs.cy = 480;            
// 윈도우의 세로크기
        cs.x = (cx-640)/2;   
// 윈도우의 좌상단 x 좌표 
        cs.y = (cy-480)/2;  
 // 윈도우의 좌상단 y 좌표
        CMenu *pMenu = new CMenu;      
// 새로운 메뉴를 만든다.
        pMenu->Attach(cs.hMenu);         
// 메인프레임에 설정된 메뉴와 연결
        pMenu->DestroyMenu();             
// 메뉴삭제
        cs.hMenu = NULL;
        delete pMenu;                           
 // 메모리에서 해제  

        return CFrameWnd::PreCreateWindow(cs);
        //return TRUE;
}

 이러한 윈도우를 종료하기 위해서 View에 약간 처리를 해주었다.

void CNoFrameView::OnRButtonDown(UINT nFlags, CPoint point)
{
        
// TODO: Add your message handler code here and/or call default
        ((CMainFrame *)AfxGetMainWnd())->SendMessage(WM_CLOSE, 0, 0);

        //CView::OnRButtonDown(nFlags, point);
}

 

 

[↓Click! Dialog Box 생성자를 통해 데이터를 전달하는 방법 / 콘솔에 문자열 출력하기 ]