MFC

[TOC]

MFC 설치

MFC 프로그램의 종류

SDI(Single Document Interface)

MDI(Multi Document Interface)

대화상자 기반

MFC 기본 생성 클래스

App

MainFrame

View

Doc

메시지 맵

MFC 작동 구조

대화상자 기반

디버그 메시지 출력

컨트롤에 이벤트 추가

리소스 편집기에서 탭 순서보기

라디오 컨트롤

리스트 컨트롤

스크롤바

	//스크롤바 최소,최대값 지정
	//hVScrollBar.SetScrollRange(0, 100);
	//스크롤바 정보 한번에 설정
	SCROLLINFO sScrollInfo;
	sScrollInfo.cbSize = sizeof(sScrollInfo);
	sScrollInfo.fMask = SIF_ALL;
	sScrollInfo.nMin = 0;
	sScrollInfo.nMax = 100;
	sScrollInfo.nPage = 10;
	sScrollInfo.nTrackPos = 0;
	sScrollInfo.nPos = 50;
	hVScrollBar.SetScrollInfo(&sScrollInfo);
	
	
	void CWinMFCDialogBasedDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {
	// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
	if (pScrollBar == &hVScrollBar) {
		SCROLLINFO sScrollInfo;
		pScrollBar->GetScrollInfo(&sScrollInfo);
		switch (nSBCode) {
		case SB_PAGEUP:
		{
			sScrollInfo.nPos -= sScrollInfo.nPage;
			break;
		}
		case SB_PAGEDOWN:
		{
			sScrollInfo.nPos += sScrollInfo.nPage;
			break;
		}
		case SB_LINEUP://화살표클릭
		{
			sScrollInfo.nPos -= sScrollInfo.nPage/10;
			break;
		}
		case SB_LINEDOWN://화살표클릭
		{
			sScrollInfo.nPos += sScrollInfo.nPage/10;
			break;
		}
		case SB_THUMBPOSITION://트랙 움직이고 나서
		case SB_THUMBTRACK://트랙 움직이는 동안
		{
			sScrollInfo.nPos = sScrollInfo.nTrackPos;
			break;
		}
		default:
			break;
		}
		hVScrollBar.SetScrollPos(sScrollInfo.nPos);
	}
	CDialogEx::OnVScroll(nSBCode, nPos, pScrollBar);
}

MFC에서 DC 사용

CDC *dc1 = CWnd::GetDC();
CDC *dc2 = this->GetDC();
CDC *dc3 = GetDC();
CClientDC dc(this);
//세 변수 모두 다른 주소값을 갖는다. GetDC요청시 새로 생성하여 넘겨주는 듯.

공용 컨트롤

ListControl

	//스타일설정
	cListCtrl.SetExtendedStyle(
		LVS_EX_FULLROWSELECT // 아이템 전체가 클릭되도록 한다.
		| LVS_EX_GRIDLINES // 서브아이템 사이에 그리드 라인을 넣는다.
	);
	//컬럼삽입
	cListCtrl.InsertColumn(0, "Column1", 0, 200);
	cListCtrl.InsertColumn(1, "Column2", 0, 200);
	
	pcListCtrl.InsertColumn(0, "Column1", 0, 200);
	pcListCtrl.InsertColumn(1, "Column2", 0, 200);
	
	//아이템삽입
	LVITEMA item = {};
	if (cListCtrl.GetItemCount() == 0) {
		item.pszText = "0";
	}
	else {
		item.pszText = "9";
	}
	item.mask = LVIF_TEXT;
	item.iItem = 1;//아이템이 삽입될 위치
	cListCtrl.InsertItem(&item);
	cListCtrl.SetItemText(1, 1, "hi");
	

TreeControl

	//TreeCtrl
	HTREEITEM root = cTreeCtrl.InsertItem("root");
	HTREEITEM sub = cTreeCtrl.InsertItem("sub", root);
	cTreeCtrl.InsertItem("sub2", root);
	cTreeCtrl.InsertItem("subsub", sub);

공용 대화상자

색상 대화상자

	CColorDialog cColorDialog;
	if (cColorDialog.DoModal() == IDOK) {
		COLORREF color = cColorDialog.GetColor();
		CString str;
		str.Format("%u", color);
		AfxMessageBox(str);
	}

파일 대화상자와 MFC의 File

	CFileDialog cFileDialog(true/*true:open, false:save*/, nullptr,  nullptr, OFN_HIDEREADONLY, "filetype1|*.*|filetype2|*.exe|");
	if (cFileDialog.DoModal() == IDOK) {
		CString str;
		str.Format("%s, %s, %s, %s\n", cFileDialog.GetFileName(), cFileDialog.GetFileTitle(), cFileDialog.GetFileExt(), cFileDialog.GetFolderPath());
		TRACE(str);

		CStdioFile cStdioFile;
		if (cStdioFile.Open(cFileDialog.GetPathName(), CFile::modeRead | CFile::typeText)) {
			cStdioFile.ReadString(str);
			TRACE("%s\n", str);
			cStdioFile.Close();
		}
	}

폰트 대화상자

	CFontDialog cFontDialog;
	if (cFontDialog.DoModal() == IDOK) {
		CDC *dc1 = CWnd::GetDC();
		CDC *dc2 = this->GetDC();
		CDC *dc3 = GetDC();

		CClientDC dc(this);

		CFont cFont, *pcOldFont;

		//Logical Font
		//cFont.CreateFontIndirectA에 전달하면 이 값과 가장 비슷한 Physicial Font를 
		//Font Mapper이 찾아서 dc에 등록해준다.
		LOGFONT sLOGFONT;

		//방법1. LOGFONT 구조체를 사용, 좀 더 간단
		cFontDialog.GetCurrentFont(&sLOGFONT);
		cFont.CreateFontIndirectA(&sLOGFONT);

		////방법2. 인자로 전달, 복잡하다
		cFont.CreateFont(
			12,                       // nHeight
			0,                        // nWidth
			0,                        // nEscapement
			0,                        // nOrientation
			FW_NORMAL,                // nWeight
			FALSE,                    // bItalic
			FALSE,                    // bUnderline
			0,                        // cStrikeOut
			ANSI_CHARSET,             // nCharSet
			OUT_DEFAULT_PRECIS,       // nOutPrecision
			CLIP_DEFAULT_PRECIS,      // nClipPrecision
			DEFAULT_QUALITY,          // nQuality
			DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
			cFontDialog.GetFaceName());            // lpszFacename

		//방법3. 간단한 설정
		cFont.CreatePointFont(120, "");

		//폰트 적용
		pcOldFont = dc.SelectObject(&cFont);
		dc.TextOutA(0, 0, "hihi");

		//이전 폰트로 돌림
		dc.SelectObject(pcOldFont);
		cFont.DeleteObject();

		//이전 설정으로 그려진다.
		dc.TextOutA(200, 0, "hoho");
	}

MFC에 Direct3D 적용하기

MFC 프로젝트의 윈도우 기본 구조

MFC 프로젝트 생성

MFC 프로젝트 분할 창 설정

FormView 생성

//.h
#pragma once
#include <afxext.h>
class CMenuFormView :
	public CFormView {
public:
	CMenuFormView();
	DECLARE_DYNCREATE(CMenuFormView)
	~CMenuFormView();
};

//.cpp
#include "stdafx.h"
#include "CMenuFormView.h"
#include "resource.h"

IMPLEMENT_DYNCREATE(CMenuFormView, CFormView)
CMenuFormView::CMenuFormView():CFormView(IDD_FORMVIEW){
}
CMenuFormView::~CMenuFormView() {
}

CSplitterWnd 설정

메인프레임 클래스의 OnCreateClient() 함수에서 CSplitterWnd 및 View를 생성해준다.

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
	CCreateContext* pContext) {
	//CSplitterWnd 생성
	if (!m_wndSplitter.CreateStatic(
		this,//메인프레임
		1,//행
		2//열
	)) {
		return false;
	}
	//분할창 크기 설정
	CRect cRect;
	GetClientRect(&cRect);
	int iClientWidth = cRect.right - cRect.left;
	int iMenuFormViewWidth = iClientWidth / 6;
	//분할창 생성 1
	if (!m_wndSplitter.CreateView(0, 0,
		RUNTIME_CLASS(CMy10D3DMFCView),
		CSize(iClientWidth - iMenuFormViewWidth, 0), pContext
	)) {
		return false;
	};
	//분할창 생성 2
	if (!m_wndSplitter.CreateView(0, 1,
		RUNTIME_CLASS(CMenuFormView),
		CSize(iMenuFormViewWidth, 0), pContext
	)) {
		return false;
	};
}

분할 경계 프레임 고정하기

//.h
class CSpiltterWndStatic : public CSplitterWnd {
public:
	CSpiltterWndStatic();
	~CSpiltterWndStatic();

protected:
	afx_msg LRESULT OnNcHitTest(CPoint point);
	DECLARE_MESSAGE_MAP();
};

//.cpp
BEGIN_MESSAGE_MAP(CSpiltterWndStatic, CSplitterWnd)
	ON_WM_NCHITTEST()
END_MESSAGE_MAP()

CSpiltterWndStatic::CSpiltterWndStatic() {}
CSpiltterWndStatic::~CSpiltterWndStatic() {}
LRESULT CSpiltterWndStatic::OnNcHitTest(CPoint point) {
	return HTNOWHERE;
}

MFC에서 무한 루프

//App 클래스 파일에 전역 변수로 선언
CMy10D3DMFCView *g_pView;

//메인프레임(사용하는 곳)에서 extern 키워드로 g_pView를 지정
extern CMy10D3DMFCView *g_pView;

//OnCreateClient에서 생성된 View의 포인터를 저장
g_pView = (CMy10D3DMFCView *)m_wndSplitter.GetPane(0, 0);

MFC에 Direct3D 적용

Direct3D 라이브러리 등록

View 클래스에 Direct3D 관련 클래스 변수 선언

//..View.h
CD3DFramework m_pD3dFramework;
CAppMesh m_cApp;

View 클래스에서 한번만 호출되는 곳에서 Direct3D 초기화 실행

OnInitialUpdate() 함수 추가 방법
//초기화
void CMy10D3DMFCView::OnInitialUpdate() {
	CView::OnInitialUpdate();

	// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
	m_pD3dFramework.Init(m_hWnd/*View의 Wnd핸들*/, &m_cApp, 1000 / 60);
}

//소멸
CMy10D3DMFCView::~CMy10D3DMFCView()
{
	m_pD3dFramework.Release();
}

View에서 배경을 지우지 않게 설정

BOOL CMenuFormView::OnEraseBkgnd(CDC* pDC) {
	return false;
	//return CFormView::OnEraseBkgnd(pDC);
}

App::OnIdle() 재정의로 무한루프 설정

App::OnIdle() 재정의하기
BOOL CMy10D3DMFCApp::OnIdle(LONG lCount) {
	// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.

	return CWinApp::OnIdle(lCount);
}

MFC 파일별 역할

Direct3D 플리핑 시점 변경하여 FPS 높이기

D3DPRESENT_PARAMETERS sD3DParam;//Direct3D 디바이스 생성에 필요한 파라미터
sD3DParam.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//즉시 플리핑

윈도우 타이틀 바꾸기

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) {
	if (!CFrameWnd::PreCreateWindow(cs))
		return FALSE;

	cs.style &= ~FWS_ADDTOTITLE;
	SetTitle(TEXT("MFC Multi View"));

	return TRUE;
}

참고