본문 바로가기

Programming/Win32&MFC&COM

MFC에서 엔터(Enter), ESC 입력시 종료되는 문제 해결 방법

반응형

MFC에서 프로그램을 개발할 때 엔터나 ESC를 누를 경우 프로그램이 종료되는 문제가 존재합니다.

개발을 MFC로 진행하면 누구나 한 번쯤은 경험하게 됩니다.

이 문제를 해결하기 위해 다음과 같은 방법으로 처리하면 됩니다.

1. PreTranslateMessage() 메소드 재정의(Override)

다이얼로그 베이스의 프로젝트를 생성하면 해당 프로젝트명Dlg.cpp와 .h파일이 생성됩니다.

해당 클래스의 PreTranslateMessage() 메소드를 오버라이딩하는 방법입니다.

이 메소드는 메시지가 처리되기 전에 호출이 되는 함수입니다.

여기서 키보드의 엔터와 ESC 메시지를 거르게 하면 됩니다.

먼저 Class Wizard를 실행(Ctrl + Shift + X)합니다.

Class name에는 Dlg가 뒤에 붙은 클래스를 선택하고 Virtual Functions 탭으로 이동합니다.

아래에 보면 PreTranslateMessage가 보이는데 선택하고 Add Function을 누르면 오른쪽에 추가됩니다.

그리고 OK를 눌러서 창을 닫으면 됩니다.

이제 다음과 같이 헤더에 선언 부분이 추가됩니다.

virtual BOOL PreTranslateMessage(MSG* pMsg);

소스 코드도 추가가 되는데 다음과 같이 작성하면 됩니다.

BOOL CMFCCloseDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class

	if (WM_KEYDOWN == pMsg->message)
	{
		if (VK_RETURN == pMsg->wParam || VK_ESCAPE == pMsg->wParam)
		{
			return TRUE;
		}
	}

	return CDialogEx::PreTranslateMessage(pMsg);
}

2. OnOK()와 OnCancel() 메소드 재정의(Override)

다이얼로그 베이스에서 최종적으로 엔터는 OnOK()를, ESC는 OnCancel()을 호출하게 되어 있습니다.

이 두 함수는 IDOK와 IDCANCEL 리소스 ID를 가진 버튼이 눌렸을 때 발생합니다.

이 ID들이 바로 다이얼로그 베이스로 처음 생성하면 생기는 OK와 Cancel 버튼입니다.

이 함수들은 기본적으로 호출되면 프로그램이 종료하도록 되어 있습니다.

함수를 재정의해서 상위 클래스의 구현을 호출하지 않도록 수정합니다.

먼저 Class Wizard(Ctrl +Shift + X)를 실행합니다.

위와 동일한 방법으로 OnOK()와 OnCancel()을 재정의해서 추가합니다.

간단하게 Virtual Functions 탭으로 이동해서 OnOK와 OnCancel을 찾아서 더블 클릭하면 추가됩니다.

다음과 같이 소스 코드에서 상위의 기능을 호출하는 부분을 주석으로 변경합니다.

void CMFCCloseDlg::OnOK()
{
	// TODO: Add your specialized code here and/or call the base class

	// CDialogEx::OnOK();
}

void CMFCCloseDlg::OnCancel()
{
	// TODO: Add your specialized code here and/or call the base class

	// CDialogEx::OnCancel();
}

이렇게 수정하면 우측 상단의 x 버튼을 눌러도 종료가 안되는 문제가 있습니다.

그래서 종료 버튼을 눌렀을 경우에는 정상적으로 종료가 되도록 수정해야 합니다.

Class Wizard를 실행해서 Messages 탭의 WM_SYSCOMMAND 메시지에 대한 핸들러를 추가합니다.

이미 기본적으로 구현이 포함되어 있으면 바로 사용하면 됩니다.

다음과 같이 SC_CLOSE를 확인해서 프로그램을 종료시키는 코드를 추가합니다.

void CMFCCloseDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else if ((nID & 0xFFF0) == SC_CLOSE)
	{
		EndDialog(IDCANCEL);
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

이렇게 하면 x버튼이나 Alt + F4, 종료 메뉴 등을 통한 종료는 정상적으로 종료됩니다.

그 외에도 다양한 방법이 가능하지만 주로 위의 두 방법으로 문제를 해결합니다.

반응형