MFC(Microsoft Foundation Classes)는 마이크로소프트에서 제공하는 C++ 라이브러리입니다. 윈도우 응용 프로그램을 개발할 때 사용되며, GUI(Graphic User Interface) 프로그래밍을 쉽게 할 수 있게 해줍니다.
주요 특징
윈도우 메시징과 이벤트 처리를 간단히 할 수 있습니다.
다양한 UI 컨트롤(버튼, 메뉴, 툴바 등)을 쉽게 추가할 수 있습니다.
문서/뷰 아키텍처를 통해 데이터와 UI를 분리하여 개발할 수 있습니다.
OLE, 데이터베이스 프로그래밍 등 다양한 기능을 지원합니다.
Visual C++ 통합 개발 환경을 지원하여 GUI 기반 개발이 가능합니다.
MFC 표기법
헝가리안 표기법
변수나 함수 이름에 데이터 형식이나 유형에 대한 정보를 접두사로 붙이는 방식
iCount - 정수형 변수 Count
클래스는 모두 C로 시작한다.
여러 단어가 하나의 클래스 이름일 경우 각 단어별로 첫 글자를 대문자로 표기한다.
맴버 변수는 m_으로 시작하고, 맴버 변수는 대문자로 시작한다.
전역 함수는 Afx라는 접두어가 붙는다.
최근에는 .NET이나 더 가벼운 라이브러리를 사용하는 추세라고 합니다.
💡
이번 미니 프로젝트 Version 2에서는 MFC를 사용하여 UI를 구현하였습니다.
2. MFC 시작하기
먼저 Visual Studio을 실행한 후, 새 프로젝트를 생성해 줍니다. Visual Studio를 설치 시 MFC를 선택해야만 아래와 같이 ‘MFC 앱’이 활성화됩니다.
프로젝트 이름을 입력한 후, 애플리케이션 종류와 프로젝트, 비주얼 스타일을 선택합니다.
문서 템플릿 속성에서, 파일 확장명을 입력합니다. 저는 Gray scale의 경우 .raw로, Color scale의 경우 .jpg로 설정했습니다.
프로젝트가 생성되면 먼저 이미지 처리에 필요한 유틸리티 함수들이 필요합니다. MFC에서는 함수의 재정의를 통해 문서 처리 및 그래픽 렌더링 기능을 사용자가 정의할 수 있습니다.
표시된 버튼을 클릭한 뒤, 원하는 기능의 함수를 선택해 Add 하고 기능을 구현합니다.
이러한 방식으로 Doc 클래스의 OnOpenDocument()와 OnSaveDocument(), View 클래스의 OnDraw() 함수를 재정의하여 사용했습니다.
프로젝트가 생성되면, 각 기능에 해당하는 함수와 변수를 추가해주면 됩니다.
참고로 변수나 함수의 이름, 매개변수 등 잘못 설정할 경우 다시 선언하거나 사용 하지 않는 방법을 사용해야 합니다.
보이지 않는 기능은 Doc.cpp에, 보이는 기능은 View.cpp에 구현합니다.
이제 Doc 클래스에 영상 처리 알고리즘을 수행하는 함수를 추가해야 합니다.
함수 이름과 반환 형식, 매개 변수 등을 입력한 뒤 영상처리 기능을 구현해 줍니다.
영상 처리 알고리즘을 구현해 기능들을 만들었다면, 그러한 기능들과 여러 옵션을 선택하는 화면이 필요하겠죠?
리소스 파일의 Menu에서 Main Menu를 찾아 선택하고, 기능을 선택할 수 있는 화면을 구성해줍니다.
각 기능 메뉴의 속성에서 ID를 설정한 후, 이벤트 처리기를 View 클래스에 추가합니다.
그러면 View.cpp에 함수가 추가되는데, 아래의 코드를 통해 기능을 수행합니다.
// 영상을 반전시키는 함수
void CColorImageProcessingView::OnReverseImage()
{
// 문서 클래스로부터 문서 포인터를 가져옵니다.
CColorImageProcessingDoc* pDoc = GetDocument();
// 문서 포인터가 유효한지 확인합니다.
ASSERT_VALID(pDoc);
// 문서의 OnReverseImage() 함수를 호출하여 실제 영상 반전 작업을 수행합니다.
pDoc->OnReverseImage();
// 뷰 영역을 무효화하여 반전된 영상을 다시 그립니다.
Invalidate(TRUE);
}
이러한 방식으로 View에서 Doc을 호출해 수행하는 방식은 MFC의 문서/뷰 아키텍처에 따라 객체 지향 원칙을 지키기 위한 것입니다.
입력 대화 상자
MFC에서는 입력 대화 상자를 통해 영상처리 기능들을 수행할 때, 사용자에게 입력을 받아 처리할 수 있습니다.
void CConstantConv ::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
// 라디오 버튼의 선택 상태를 m_radio_index 멤버 변수와 연결합니다.
DDX_Radio(pDX, 첫번째라디오버튼ID, (int&)m_radio_index); // 이 부분 추가
}
이제 Doc.cpp에 해당 Dialog 클래스를 include 해서 경우에 따라 처리할 수 있습니다.
CConstantConv btn;
if (btn.DoModal() != IDOK)
return;
if (btn.m_radio_index == 0) // 첫 번째 라디오 버튼을 선택했을 경우
size = 3;
else if (btn.m_radio_index == 1) // 두 번째 라디오 버튼을 선택했을 경우
size = 5;
else if (btn.m_radio_index == 2) // 세 번째 라디오 버튼을 선택했을 경우
size = 7;
else if (btn.m_radio_index == 3) // 네 번째 라디오 버튼을 선택했을 경우
size = 9;
3. 소스 코드 및 미니 프로젝트 Version 1(spin-off), Version 2 발표 자료