728x90
300x250

[MFC] 윈도우 프로그래밍 기초 - 대화 상자 실습

 

이번 글에서는 이전에 소개한 대화 상자 글을 바탕으로 실제 대화 상자를 구현하는 방법에 대해 소개하겠습니다.

 


1. 실습 주제) MFCModal 창 만들어 보기

 

 

 

  동작 전 결과

 

 동작 후 결과

 

 


1-1. BITMAP 리소스 추가

 

 

리소스 추가(A) 클릭

 

 

새로 만들기(N) 클릭 

->참고로 "가져오기" 하셔도 됩니다.

 

 

전 이렇게 그렸습니다.

 

 

이번에 그린 그림의 이름(ID)은 IDB_EARTH로 하겠습니다.

 

 


1-2. 컨트롤 박스 배치하기

 

 

 

 

 컨트롤 꾸며보기 - 이 부분은 여러분이 도구상자 탭을 이용하여 직접 하셔야 합니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

컨트롤 

 ID

 Caption

 Image

Type

Dialog

IDD_MFCMODAL_DIALOG

 

 

 

Edit Box

IDC_INPUT_NAME

 

 

 

Edit Box 

IDC_INPUT_SCHOOL

 

 

 

Edit Box

IDC_INPUT_DEPT

 

 

 

Edit Box

IDC_INPUT_GRAD

 

 

 

Static

IDC_STATIC

이름

 

 

Static

IDC_STATIC 

학교

 

 

Static

IDC_STATIC

학과

 

 

Static

IDC_STATIC

학년

 

 

Picture Control

IDC_INPUT_IMAGE

 

 IDC_EARTH

 Bitmap

Edit Box

IDC_OUTPUT_NAME

 

 

 

Edit Box

IDC_OUTPUT_SCHOOL

 

 

 

Edit Box

IDC_OUTPUT_DEPT

 

 

 

Edit Box

IDC_OUTPUT_GRAD 

 

 

 

Picture Control

IDC_OUTPUT_IMAGE

 

 

 Bitmap

Static

IDC_STATIC

이름

 

 

Static 

IDC_STATIC 

학교

 

 

Static

IDC_STATIC

학과 

 

 

Static 

IDC_STATIC

학년

 

 

Group Box

IDC_STATIC

최종입력결과

 

 

Button

IDB_BTN_COMPLETE 

입력완료 

 

 

 

리소스를 이처럼 편집해주시기 바랍니다.

 


1-3 변수 추가

 

하나를 대상으로 변수 추가 방법을 소개해드리겠습니다.

나머지는 여러분들이 아래의 테이블을 참고하여 만들어주시기 바랍니다.

 

 

 

변수 추가(B) 클릭

 

 

 

 범주(T)를 Value로 변경

 

 

변수 형식 : CString,

변수 이름 : m_staticName

최대 문자수 : 20

 

마침을 클릭합니다.

 

변수 추가 후에 코드가 변동됩니다.

변동되는 코드는

MFCModalDlg.h와 MFCModalDlg.cpp입니다.

 

 

 

 MFCModalDlg.h

 

 

 MFCModalDlg.cpp의 DoDataExchange()

-> 여기에서 사용하는 역할을 간접적으로 학습하셨으면 합니다.

 

참고로 DDX와 DDV는

앞서 살펴보셨겠지만, 대화상자에서의 최대 문자 수와 같은 제약조건을 다루는 함수입니다.

 

 

이 예제에서 만들어야 할 멤버 변수 설정 값 테이블입니다.

첫 번째 예제를 통해 변수 하나는 만들었으므로 나머지에 대한 테이블을 소개하겠습니다.

 

 컨트롤 ID

변수 형식

범주

최대 문자 수

 IDC_INPUT_SCHOOL

CString m_staticSchool

Value

50

 IDC_INPUT_DEPT

CString m_staticDept

Value

20

 IDC_INPUT_GRAD

CString m_staticGrad

Value

5

 IDC_OUTPUT_NAME

CString m_strName

Value

20

 IDC_OUTPUT_SCHOOL

CString m_strSchool

Value

50

 IDC_OUTPUT_DEPT

CString m_strDept

Value

20

 IDC_OUTPUT_GRAD

CString m_strGrad

Value

5

 IDC_OUTPUT_IMAGE

CString m_strImage

Control

 

 


1-4. 이벤트 처리기 추가

 

입력완료 버튼에서 오른쪽 버튼을 클릭한 후 이벤트 처리기 추가(A)를 클릭합니다. 

 

 

 

기본값으로 두가 추가 및 편집을 클릭합니다.

 

 

OnBnClickedBtnComplete( )라는 함수가 생성됩니다.

 

MFCModalDlg.h와 MFCModalDlg.cpp의 파일이 영향을 받게 됩니다.

어떻게 코드가 생성되었는지 확인해보겠습니다. 

 

 

 

결과)

 afx_msg void OnBnClickedBtnComplete( )라는 함수가 추가되었습니다. 

 

 

 결과)

  MFCModalDlg.cpp의 void CMFCModalDlg::OnBnClickedBtnComplete( )라는 함수 구현부가 완성되었습니다.

 


1-5 기능 구현

 


{
         CBitmap MyImageView;

       

         UpdateData(TRUE);  // UpdateData(TRUE)함수를 통해 데이터가 전송됩니다.

         m_strName = m_staticName;
         m_strSchool = m_staticSchool;
         m_strDept = m_staticDept;
         m_strGrad = m_staticGrad;

 

         MyImageView.LoadBitmap(IDB_EARTH);

         m_staticImage.SetBitmap(MyImageView);

 

         UpdateData(FALSE);

 
}
 

 OnBnClickedBtnComplete( ) 구현

 


1-6. 동작해보기

 

반응형
728x90
300x250

[MFC] 윈도우 프로그래밍 기초 - 대화 상자 만들기

 

이번에는 윈도우 프로그래밍 기초로 "대화 상자 만들기"에 대해서 소개하고자 합니다.

 


1. 프로젝트 만들기

 

 

 

 새 프로젝트 -> 이름 : MFCModal, 확인 클릭

 

 

 대화 상자 기반에 체크한 후 마침을 누릅니다.

 

 

 Welcome to 대화상자 월드

 


2. 소스 코드 살펴보기

 

 

 


2-1. 응용 프로그램 클래스

 

앞전에 http://yyman.tistory.com/494 ([MFC] 윈도우 프로그래밍 기초 - 팝업메뉴 만들기(리소스의 이해))의 글에서는
SDI 기반으로 응용 프로그램을 작성했습니다.

 

SDI는 Single Document Interface의 약자로서 단일 Document를 의미합니다.

하지만, 이번에 살펴볼 대화상자는 SDI기반과는 다른 구조로 되어있음을 소개하고자 합니다.

 

SDI 기반에서는

 

CDocument, CView 

 

로 구성되어 있었습니다.

 

하지만, 대화상자에서는

CDialogi 클래스 대체되고, 공통 클래스는 CWinApp

 

로 구성됩니다.

 

MFCModal.cpp를 열어보면,

// MFCModal.cpp : 응용 프로그램에 대한 클래스 동작을 정의합니다.
//

#include "stdafx.h"
#include "MFCModal.h"
#include "MFCModalDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMFCModalApp

BEGIN_MESSAGE_MAP(CMFCModalApp, CWinApp)
     ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CMFCModalApp 생성

CMFCModalApp::CMFCModalApp()
{
          // 다시 시작 관리자 지원
         m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

         // TODO: 여기에 생성 코드를 추가합니다.
         // InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}


// 유일한 CMFCModalApp 개체입니다.

CMFCModalApp theApp;


// CMFCModalApp 초기화

BOOL CMFCModalApp::InitInstance()
{
          // 응용 프로그램 매니페스트가 ComCtl32.dll 버전 6 이상을 사용하여 비주얼 스타일을
          // 사용하도록 지정하는 경우, Windows XP 상에서 반드시 InitCommonControlsEx()가 필요합니다.
          // InitCommonControlsEx()를 사용하지 않으면 창을 만들 수 없습니다.
          INITCOMMONCONTROLSEX InitCtrls;
          InitCtrls.dwSize = sizeof(InitCtrls);
          // 응용 프로그램에서 사용할 모든 공용 컨트롤 클래스를 포함하도록
          // 이 항목을 설정하십시오.
          InitCtrls.dwICC = ICC_WIN95_CLASSES;
          InitCommonControlsEx(&InitCtrls);

          CWinApp::InitInstance();


          AfxEnableControlContainer();

          // 대화 상자에 셸 트리 뷰 또는
          // 셸 목록 뷰 컨트롤이 포함되어 있는 경우 셸 관리자를 만듭니다.
          CShellManager *pShellManager = new CShellManager;

          // MFC 컨트롤의 테마를 사용하기 위해 "Windows 원형" 비주얼 관리자 활성화
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

 

          SetRegistryKey(_T("로컬 응용 프로그램 마법사에서 생성된 응용 프로그램"));

          CMFCModalDlg dlg;
          m_pMainWnd = &dlg;
          INT_PTR nResponse = dlg.DoModal();
      

          if (nResponse == IDOK)
          {
             // TODO: 여기에 [확인]을 클릭하여 대화 상자가 없어질 때 처리할
            //  코드를 배치합니다.
          }
          else if (nResponse == IDCANCEL)
          {
                 // TODO: 여기에 [취소]를 클릭하여 대화 상자가 없어질 때 처리할
                 //  코드를 배치합니다.
          }
          else if (nResponse == -1)
         {
               TRACE(traceAppMsg, 0, "경고: 대화 상자를 만들지 못했으므로 응용 프로그램이 예기치 않게 종료됩니다.\n");
               TRACE(traceAppMsg, 0, "경고: 대화 상자에서 MFC 컨트롤을 사용하는 경우 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS를 수행할 수 없습니다.\n");
         }

           // 위에서 만든 셸 관리자를 삭제합니다.
          if (pShellManager != NULL)
         {
             delete pShellManager;
         }

         // 대화 상자가 닫혔으므로 응용 프로그램의 메시지 펌프를 시작하지 않고  응용 프로그램을 끝낼 수 있도록 FALSE를
         // 반환합니다.
        return FALSE;
}

 

이처럼 코드가 구성되어 있습니다.

 


2-2) 대화 상자 클래스

 

MFCModelDlg.cpp 소개

 


// MFCModalDlg.cpp : 구현 파일
//

#include "stdafx.h"
#include "MFCModal.h"
#include "MFCModalDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.

class CAboutDlg : public CDialogEx
{
         public:
                  CAboutDlg();

                 // 대화 상자 데이터입니다.
                 enum { IDD = IDD_ABOUTBOX };

         protected:
                 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 지원입니다.

// 구현입니다.
         protected:
                 DECLARE_MESSAGE_MAP()
};

 

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{

 

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
          CDialogEx::DoDataExchange(pDX);
}

 

 

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCModalDlg 대화 상자

 

CMFCModalDlg::CMFCModalDlg(CWnd* pParent /*=NULL*/)
 : CDialogEx(CMFCModalDlg::IDD, pParent)
{
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

 

void CMFCModalDlg::DoDataExchange(CDataExchange* pDX)
{
           CDialogEx::DoDataExchange(pDX);
}

 

BEGIN_MESSAGE_MAP(CMFCModalDlg, CDialogEx)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
END_MESSAGE_MAP()


// CMFCModalDlg 메시지 처리기

BOOL CMFCModalDlg::OnInitDialog()
{
            CDialogEx::OnInitDialog();

            // 시스템 메뉴에 "정보..." 메뉴 항목을 추가합니다.

            // IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
            ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
            ASSERT(IDM_ABOUTBOX < 0xF000);

 

            CMenu* pSysMenu = GetSystemMenu(FALSE);

 

            if (pSysMenu != NULL)
            {
                     BOOL bNameValid;
                     CString strAboutMenu;
                     bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
                     ASSERT(bNameValid);
         

                     if (!strAboutMenu.IsEmpty())
                     {
                                 pSysMenu->AppendMenu(MF_SEPARATOR);
                                 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
                     }
            }

 

            // 이 대화 상자의 아이콘을 설정합니다.  응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
            //  프레임워크가 이 작업을 자동으로 수행합니다.

 

            SetIcon(m_hIcon, TRUE);   // 큰 아이콘을 설정합니다.
            SetIcon(m_hIcon, FALSE);  // 작은 아이콘을 설정합니다.

 

            // TODO: 여기에 추가 초기화 작업을 추가합니다.

            return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.


}

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

// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
//  아래 코드가 필요합니다.  문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는
//  프레임워크에서 이 작업을 자동으로 수행합니다.

void CMFCModalDlg::OnPaint()
{
 if (IsIconic())
 {
  CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.

  SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

  // 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
  int cxIcon = GetSystemMetrics(SM_CXICON);
  int cyIcon = GetSystemMetrics(SM_CYICON);
  CRect rect;
  GetClientRect(&rect);
  int x = (rect.Width() - cxIcon + 1) / 2;
  int y = (rect.Height() - cyIcon + 1) / 2;

  // 아이콘을 그립니다.
  dc.DrawIcon(x, y, m_hIcon);
 }
 else
 {
  CDialogEx::OnPaint();
 }
}

// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
//  이 함수를 호출합니다.
HCURSOR CMFCModalDlg::OnQueryDragIcon()
{
 return static_cast<HCURSOR>(m_hIcon);
}

 

 

눈 여겨 봐야할 부분만 블록으로 칠해놨습니다.

DoDataExchange() 함수와 OnInitDialog() 함수는 대화상자에서 중요한 역할을 합니다.

실제로 다음 장 글에서 컨트롤 배치와 실습을 통해 변화를 관찰하면 될 것 같습니다.

반응형
728x90
300x250

[MFC] 윈도우 프로그래밍 기초 - 컨트롤(Control) 소개

 

사실 이건 소개할 필요가 없을거 같긴 한데, 소개하면 앞서 소개한 강의에서 대화상자를 살펴봤습니다.

대화상자에 있는 각각의 TextBox, Static Text (Label), Button 등은 다 컨트롤이라는 대화상자에서 여러분의 창의적인 머리를 이용해

구현하실 수 있습니다.

 

자세한 설명은 생략해도 될 것 같습니다.

 

 

 

 

 

Controls - Model

도구 상자 

 

반응형
728x90
300x250

[MFC] 윈도우 프로그래밍 - 대화 상자(Dialog)

 


1. Introduce

 

Dialog -> 영어시간에 많이 들어보셨을 겁니다.

 

 

Dialog Box는 응용 프로그램과 사용자의 의사소통을 하는 통로라고 설명할 수 있습니다.

 

 

 Figure 1) Visual Basic 6.0 (Visual Basic for Application으로 시연함)

 

대부분 Visual Studio의 C++ 모달 환경을 처음 접하게 되면, 프로그래밍을 접고 싶다는 생각을 종종할 수 있습니다.

왜냐하면, 초보자분들 입장에선 위에 그림과 같은 환경에서 개발하면 편하고 해볼만하다는 생각을 할 수 있습니다.

하지만, MFC는 조금 복잡합니다. 만져야 할 게 조금 있습니다. (코드 부분, 화면 부분, 컨트롤러 부분)

 

 

 

 Figure 2) 코드 환경 ( C++ MFC )

 

 

 

 

 Figure 3) 모달 영역

 

모달 영역은 모달 영역대로 분리되어 있습니다.

 


2. 큰 나무를 그려보면,

 

 

 

실제로는 별거 없습니다.

화면 작업이라는 영역은,

 

 

 

 리소스 뷰의 영역 -> Dialog

 

여러분이 만든 버튼의 이벤트 코드는?

 

 

 

 

 버튼 예시 - 실제 화면 캡처함

 이벤트 처리기 추가(A) 마법사

 

마법사를 이용하면, 자동 생성됩니다.

 

 

이벤트 마법사의 예 - 이미 추가된 이벤트 버튼이므로 '추가 및 편집'이 비활성화되어 있음.

 

 


3. 대화상자의 예를 소개합니다.

 

 

 

 

 

 Dialog의 예1) 인터넷 익스플로러 - 파일-> 열기

 Dialog의 예2) 실행 - Dialog

 

 

 

 

 Dialog의 예3) 파일 열기

 Dialog의 예4) 찾기 및 바꾸기

 

이렇게 많은 다이얼로그가 존재하는지 알았으면, 대화상자를 구현할 준비가 된 것입니다.

한번 일상 속에서 다이얼로그가 어떤게 존재하는지 탐구해보셨으면 합니다.

반응형
728x90
300x250

[MFC] 윈도우 프로그래밍 기초 - 팝업메뉴 만들기(리소스의 이해)

 

오늘 실습은 팝업 메뉴 만드는 방법에 대해 실습할 계획입니다.

실습과 더불어 간단하게 리소스의 큰 그림을 이해할 수 있도록 작성하였습니다.

 

 

 

 출력 결과

 


1. 프로젝트 생성하기

 

1. Visual Studio 2013을 켭니다.

2. 새 프로젝트를 만듭니다.

 

 

프로젝트 명은 Lecture로 하겠습니다.

 

3. 다음은 MFC 프로그램에 대한 기본 환경 설정입니다.

아래와 같이 설정하고 마침을 누르겠습니다.

 

 


2. 리소스 뷰에 대한 설명(숲 그리기)

 

2-1. 리소스란?

사전적 의미로 자원이란 의미를 가지고 있습니다.

전쟁으로 비유하면,

 

 

 

리소스는 위의 그림과 같은 관계가 될 수 있습니다.

 

Figure 2-1. <Source And Resource> - Relational Model

 

 

소스코드와 리소스는 각각 컴파일되어서, 소스코드는 *.obj로 변환되고, 리소스 파일은 *.rc로 컴파일이 됩니다.

이들이 Link 단계에서 결합 후에 Execution File로서 결합됩니다.

 

이번 실습에서의 큰 그림은 아래와 같이 소개할 수 있습니다.

 

 

2-2. 리소스 뷰

 

앞서 설명한 이야기를 이해하였으면, 실제 리소스가 MFC에서 어떻게 사용되는지 소개하겠습니다.

프로젝트를 앞서 생성했으면, 왼쪽에 리소스 뷰란 탭을 클릭하면 아래와 같은 창을 살펴볼 수 있습니다.

 

 

 

 

 리소스 뷰

 리소스 파일의 위치 (솔루션 탐색기)

 

리소스 파일 생성에 관해 말씀드리면, MFC 라이브러리를 이용하지 않는 프로그램이면 이용하면 리소스에 대해 관리가 될 수 있다고 보이나 MFC를 이용한 파일이면 굳이 자동으로 생성되는 만큼 별도로 추가 구성을 할 필요가 없습니다.

 

.rc라는 파일은 즉, 다수의 리소스를 모아놓은 하나의 집합이라고 정의할 수 있습니다.

 

2-3. 리소스 식별 접두어 (관례)

* 사용자 정의 리소스 식별 매크로의 접두어

 

설명

접두어

아이콘

IDI_

커서

IDC_

비트맵

IDB_

문자열 항목

IDS_ 또는 IDM_

메뉴

IDR_

메뉴 항목

IDM_

엑셀러레이터

IDR_

엑셀러레이터 키

IDM_

도구 모음

IDR_ 

도구 모음 버튼

IDM_

대화 상자

IDD_

컨트롤

IDC_

 

* MFC 내장 리소스 식별 매크로의 접두어

 

설명

접두어

아이콘 

AFX_IDI_

커서

AFX_IDC_

비트맵

AFX_IDB_

버전

VS_VERSION

문자열 항목

AFX_IDS_ 또는 ID_

메뉴 항목

ID_

엑셀러레이터

AFX_IDR_

엑셀러레이터 키

ID_

도구 모음 버튼

ID_

대화 상자

AFX_IDD_

컨트롤

AFX_IDC_ 또는 ID_

 

2-4. 리소스 뷰 간단하게 살펴보기

 

 


3. 실습(팝업 메뉴 만들기)

 

이번 실습은 "팝업 메뉴 만들기"라는 주제로 실습을 하겠습니다.

 

3-1. 메뉴 만들기

 

 

리소스 추가를 클릭합니다.

 

 

Menu를 선택하고 새로 만들기(N)을 클릭합니다.

 

 

 

3-2. 아래와 같이 메뉴를 꾸며주기.

 

 

 

 

 

 메뉴 구성하기

 리소스뷰 - 방금 만든 메뉴 리소스 ID 변경 -> IDR_POPUP

 

3-3. 클래스 뷰의 CMainFrame 설정하기

WM_CONTEXTMENU라는 영역에 OnContextMenu를 생성하는 방법을 실습해보겠습니다.

 

 

 

 

 

 

<Add> OnContextMenu를 클릭하면

MainFrm.cpp과 MainFrm.h의 파일에 자동 생성되어 구현할 수 있는 상태로 코드가 생성됩니다.

즉, MainFrm.cpp의 함수 원형을 변경할 경우, MainFrm.h 쪽도 저장하셔야합니다.

 

(참고)

 

 

 

 기본 생성된 MainFrm.h의 OnContextMenu 원형 구조

 

 

 

 

 기본 생성된 MainFrm.cpp의 구현 구조

 

3-4. 코딩하기

 

 
void CMainFrame::OnContextMenu(CWnd *pWnd, CPoint point)
{
      CMenu popup;
      CMenu* pMenu;

      popup.LoadMenuW(IDR_POPUP);
      pMenu = popup.GetSubMenu(0);

      pMenu->TrackPopupMenu(TPM_LEFTALIGN || TPM_RIGHTBUTTON, point.x, point.y, this);

}

수정) MainFrm.cpp

 void CMainFrame::OnContextMenu(CWnd *pWnd, CPoint point);

수정) MainFrm.h

 

(참고) 팝업 메뉴 소스코드 분석

 

* < LoadMenu() >의 원형

 

* BOOL CMenu::LoadMenu(LPCTSTR lpszResourceName) 

 

메뉴 리소스를 읽어오는 함수를 의미합니다.

 

* < GetSubMenu() >의 원형

 

* CMenu *CMenu::GetSubMenu(int nPos) const 

 

GetSubMenu() 함수는 메뉴 표시줄에서 하위 메뉴를 구하는 함수입니다.

즉, 구하고자 하는 함수의 하위 메뉴는 0부터 시작함.

 

 

* <TrackPopupMenu() > 의 원형

 

* BOOL CMenu::TrackPopupMenu( UINT nFlags, int x, int y, CWnd *pWnd, LPCRECT lpRect = NULL ) 

 

uFlags에는 여러가지 조합으로 사용가능

인수 uFlags에는 여러 가지 값을 조합하여 설정할 수 있는데, 팝업 메뉴의 정렬과 동작 설정 값을 비트 OR 연산자로 연결해 지정할 수 있음.

 

<팝업 메뉴의 정렬 설정 값>

값 

내용 

TPM_LEFTALIGN

팝업 메뉴를 지정한 위치에서 좌측 정렬 

TPM_RIGHTALIGN

팝업 메뉴를 지정한 위치에서 우측 정렬 

TPM_CENTERALIGN

팝업 메뉴를 지정한 위치에서 가운데 정렬

TPM_TOPALIGN

팝업 메뉴를 지정한 위치에서 위쪽 정렬

TPM_BOTTOMALIGN

팝업 메뉴를 지정한 위치에서 바닥 정렬

TPM_VCENTERALIGN

팝업 메뉴를 지정한 위치에서 수직 중앙 정렬

 

<팝업 메뉴의 동작 설정 값>

 

내용

TPM_LEFTBUTTON

마우스 왼쪽 버튼 클릭시 메뉴 수행

TPM_RIGHTBUTTON

마우스 오른쪽 버튼 클릭시 메뉴 수행

TPM_NONOTIFY

메뉴 항목이 선택되었을 때 통지 메시지를 보내지 않음

TPM_RETURNCMD 

메뉴 항목이 선택되었을 때 선택된 메뉴 항목의 ID를 반환 

 

* int x, int y

-> Point의 좌표 (eg: point.x, point y)

 

* pWnd

pWnd는 팝업 메뉴를 소유하고 있는 윈도우를 지정해주면 됨.

-> pWnd

 

3-5. 컴파일 해보기

마우스 오른쪽 버튼을 클릭해보면, 아래와 같이 정상 동작함을 확인할 수 있습니다.

 

 

반응형
728x90
300x250

[MFC] 윈도우 프로그래밍 기초 - MFC - 배경지식

 

1. MFC란?

Microsoft Foundation Class의 약자이다.

해석하면, 마이크로소프트에서 만든 클래스라고 할 수 있음.

 


2. 왜 MFC를 만들었을까?

윈도우 API를 공부해본 사람이면 알겠지만, 윈도우 운영체제는 수천 가지나 되는 다양한 기능의 API함수들을 제공한다.

개발자가 너무나 많은 함수를 모두 다 기억하기엔 정말 힘들고 어려운 일이다.

일일이 모든 기능을 처음부터 끝까지 학습하는 것 또한 굉장히 고난스러운 일이기 때문에, Microsoft에서는 API함수를 각 기능별로 클래스화한 형태로 만든 것이 MFC라고 할 수 있다.

 


3. MFC의 유래

MFC의 시초는 AFX(Application Framework)에서 유래되었다고 할 수 있다.

AFX는 1990년 마이크로소프트가 윈도우 API 함수를 캡슐화하여 만든 라이브러리라고 할 수 있다.

앞서 윈도우 API함수를 캡슐화하여 만든 것이 MFC라고 하였는데, AFX는 MFC의 전 단계로 수정을 거쳐 지금의 MFC가 완성되었다고 보면 이해가 될 것이다. 1993년 이후부터 MFC 라이브러리는 Visual C++에 포함되어 제공되고 있다.

 

 


4. Visual C++, MFC, Windows의 발전사?

 

 연도

Visual C++ 

 MFC 

 Windows 버전 

 주요 특징

 비고

 1993

 MS-C 7.0

 1.0 (AFX라고 봐야함)

 3.1

 Win16 API 캡슐화

 당시에는
 MFC(Microsoft Foundation Classes)라는
 거창한 이름이 없어서 AFX(Application Framework)
 라고 부름.

 1993

 Visual C++ 1.0 /
 Quick-C 2.5

 2.0

 3.1

 Document/View 구조 정립
 DDX/DDV 매카니즘 지원
 응용 프로그램 프레임워크 구조 도입

 

 1993

 Visual C++ 1.5

 2.5

 3.1

 ODBC 관련 클래스 및 OLE 2.01을 지원

 

 1995

 Visual C++ 2.0

 3.0

 NT 3.51

 Win16에서 Win32로 전환
 Winsock API와 MAPI 클래스 추가

 멀티스레드 관련 클래스 추가

 템플릿과 예외 처리 기능 강화 

 템플릿 기능이 없었던
 시절에서 당시에는 혁명임.?

 1996

 Visual C++ 4.0

 4.0

 95

 DAO 클래스 지원

 ODBC 2.5 지원

 윈도우95 공통 컨트롤 지원

 멀티스레드 동기화를 위한 클래스 지원

 Active X 문서 서버 클래스 지원

 1. 이 때 MFC의 윤곽을

 사실상 잡았다고 봐야함.
 2. MFC42.DLL 파일을 
    보신 분은 이 때
    윤곽잡힌 파일을
    만들었다고 보면 됨.

 1997

 Visual C++ 5.0

 4.21

 95 / WinCE 2.0

 인터넷 프로그래밍 지원
 ATL 포함
 온라인 도움말 제공

 

 1998 

 Visual C++ 6.0

 6.0

 98

 데이터베이스 기능 강화
 향상된 디버깅 환경 제공
 공통 컨트롤 추가

 윈도우98이 출시된 시기.

 Visual C++ 6.0이 한창
 불티나게 팔림.

 2002~

 2005

 Visual C++.NET
 7.0 ~ 8.0

 (2002~2005)

 7.0 ~ 8.0

 XP, 
 서버 2003

 MFC와 ATL 라이브러리 일부 통합

 닷넷 프레임워크 라이브러리 추가

 비주얼 스튜디오 내 각 개발 언어간의
 개발환경통합

 2002년 초기 당시 .NET Framework가 안된다는 말과 Visual Studio 6.0으로도 충분하지 않냐의 갈림길 그리고 이전에 코드는 어떻게 하냐를 두고 갈등이 많았음.

 시간이 지난 후 이러한 갈등은 해결되었음.
(쓰레기 운영체제 윈도우 비스타와 윈도우 7 덕분에)

 

 2013

 Visual C++.NET
 12

 12

 윈도우8.1,

 윈도우 서버 2012

 이 버전부터 다국어 UI를 지원.
 윈도 8, 윈도 RT 전용 소프트웨어인 윈도 스토어 지원 앱을 만들 수 있다.
 ARM 아키텍처에서 구동할 수 있는 윈도 스토어 전용 앱을 만들 수 있다.
 출시 초기에는 윈도 7 이상에서만

구동할 수 있는 실행 파일만 만들 수

있었지만, 업데이트 1 이상으로 갱신하면 윈도 XP에서도 구동할 수 있는 실행 파일을 만들 수 있음.
 테스트 프로페셔녈 버전에는 컴파일러가 포함되어 있지 않음.
 HLSL 컴파일 기능과 DirectX 그래픽 디버거를 포함한다. (XP 지원 모드 제외)

 컴파일 속도가 개선.
 표준 C++11을 도입.

 

 

 


5. MFC 계층도

 

다음 그림은 CObject로부터 파생된 MFC 클래스들을 나타냅니다. 

 

 

다음 그림은 CWnd 및 CCmdTarget로부터 파생된 MFC 클래스들을 나타냅니다.

 

 

다음 그림은 CObject로부터 파생되지 않은 MFC 클래스들을 나타낸다.

 

 

 


6. MFC 계층 구조

 

 

MFC는 크게 CObject로부터 파생되는 클래스CObject로부터 파생되지 않은 클래스 두 가지로 요약할 수 있음.

자세한 사항은 MFC 계층도를 살펴보고 이해하면 됨.

 

 

6-1) CObject 클래스

MFC의 최상위 클래스인 CObject 클래스는 다음과 같이 구성됨.

 

 

 

6-2) 응용 프로그램 아키텍처 클래스(Application Architecture Classes)

 

 

윈도우 응용 프로그램의 가장 기본적인 구조를 제공하는 클래스.

 

MFC는 기본적으로 전체 프레임 구성을 위한 근간을 이루는 클래스가 제공되고, CCmdTarget으로부터 파생된 CWinApp 클래스가 그 기능을 수행.

메시지루프를 돌면서 윈도우 프로시저는 원하는 메시지만을 선별하고, 나머지 메시지는 기본 처리 함수에게 역할을 맡기게 됨.

 


6-3) 윈도우 클래스

CObject 클래스로부터 파생된 클래스인 윈도우 클래스의 구성은 다음과 같음.

 

 

 

사용자 인터페이스를 제공하는 모든 윈도우 관련 클래스의 최상위에 CWnd 클래스가 있다.

CWnd 클래스에서 파생된 클래스로서 응용 프로그램의 주 골격을 만들어주는 CFrameWnd 클래스, 대화 상자인 CDialog 클래스, 사용자 영역을 담당하는 CView 클래스 그리고 윈도우가 제공하는 각종 컨트롤 등이 있음.

 

6-3-1) 일반 클래스(General Class)

 

 

 

응용 프로그램 아키텍처와 윈도우 관련 클래스를 제외한 나머지 클래스를 말한다.

즉, 기본적인 윈도우 골격에 영향을 미치지 않는 클래스를 말함.

 

예) 소켓과 같은 윈속 클래스나 데이터베이스 관련 클래스는 윈도우 골격에 영향을 미치지 않음.

 

6-3-2) CObject 클래스로부터 파생되지 않은 클래스

 

 

반응형
728x90
300x250

[MFC] 윈도우 프로그래밍 기초 - Win32 프로그램 올려보기

 

2, http://yyman.tistory.com/485 / [MFC] 윈도우 프로그래밍 기초 - 윈도우 프로그램의 구조

3, http://yyman.tistory.com/486 / [MFC] 윈도우 프로그래밍 기초 - 윈도우 클래스 만들기

4, http://yyman.tistory.com/487 / [MFC] 윈도우 프로그래밍 기초 - 윈도우 객체 생성, 화면 띄우기

5, http://yyman.tistory.com/488 / [MFC] 윈도우 프로그래밍 기초 - 메시지 루프, 처리하기.

 

2~5번 글까지 잘 읽었다면, 이번에는 프로그램 전체 소스로 만들어 보겠습니다.

 


1. 새 프로젝트 만들기 

 

그림 1-1) 새 프로젝트 만들기, Visual Studio 2013

 

 

그림 1-2) 프로젝트 마법사, Visual Studio 2013

 

 

그림 1-3) 프로젝트 마법사, Visual Studio 2013

 

 

그림 1-4) 솔루션 탐색기, Visual Studio 2013

 

그림 1-5) 소스코드 파일 만들기

 

 


2. 구현(Implements)

 

<Basic.cpp>

#include <Windows.h>
#include <tchar.h>

 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

LPTSTR lpszClass = _T("BasicApi");


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
       HWND hWnd;
       MSG Message;
       WNDCLASS WndClass;


       WndClass.cbClsExtra = 0;
       WndClass.cbWndExtra = 0;
       WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
       WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
       WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
       WndClass.hInstance = hInstance;
       WndClass.lpfnWndProc = (WNDPROC)WndProc;
       WndClass.lpszClassName = lpszClass;
       WndClass.lpszMenuName = NULL;
       WndClass.style = CS_HREDRAW | CS_VREDRAW;

 

       RegisterClass(&WndClass);

 

       hWnd = CreateWindow(lpszClass, LPTSTR(_T("제목")), WS_OVERLAPPEDWINDOW,
         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);

     

       ShowWindow(hWnd, nCmdShow);

      

       while (GetMessage(&Message, 0, 0, 0) )
       {
              TranslateMessage(&Message);
              DispatchMessage(&Message);
       }

 

       return Message.wParam;

}

 

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
      HDC hdc;
      PAINTSTRUCT ps;
 
      switch (iMessage)
     {
           case WM_CREATE:
                return 0;

           case WM_PAINT:
               hdc = BeginPaint(hWnd, &ps);
               EndPaint(hWnd, &ps);
               return 0;

           case WM_DESTROY:
               PostQuitMessage(0);
               return 0;

     }

 

     return (DefWindowProc(hWnd, iMessage, wParam, lParam));

 

 

 

 

 

그림 2-1) 윈도우 화면 출력하기

 


3. 응용 예제) WndProc에 윈도우 창 종료시 알림 메시지 처리

 

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
      HDC hdc;
      PAINTSTRUCT ps;

      int nReturn;
 
      switch (iMessage)
     {
           case WM_CREATE:
                return 0;

 

           case WM_PAINT:
               hdc = BeginPaint(hWnd, &ps);
               EndPaint(hWnd, &ps);
               return 0;

 

          case WM_CLOSE:

               nReturn = MessageBox(hWnd, _T("정말 종료하시겠습니까?"), _T("확인"), MB_YESNO);

 

               if(nReturn == IDYES)

                     DestroyWindow(hWnd);

 

               return 0;

 

 

           case WM_DESTROY:
               PostQuitMessage(0);
               return 0;

     }

 

     return (DefWindowProc(hWnd, iMessage, wParam, lParam));

 

 

 


4. 마치면서

이 코드는 잊어버려도 되지만, 윈도우 프로그램의 기본 구조는 반드시 알고 있어야 한다.

 

1. 윈도우 프로그램의 전체 구조

 

int WINAPI WinMain( .... ) // 프로그램의 시작점

{
      // 기본적인 윈도우의 형태를 생성

      // 메시지 루프를 돌린다.

}

 

LRESULT CALLBACK WndProc(......) // 메시지를 처리하는 프로시저

{

       // 윈도우 메시지를 처리한다.

}

 

2. 윈도우 프로그램의 구성 요소

    -> 1. 클래스 만들기(윈도우)

    -> 2. 객체 생성(윈도우)

    -> 3. 객체 화면 띄우기(윈도우)

    -> 4. 메시지 루프 돌리기

    -> 5. 메시지 처리하기

 


5. 참고자료(Reference)

반응형
728x90
300x250

[MFC] 윈도우 프로그래밍 기초 - 메시지 루프, 처리하기.

 

앞서 두개의 글에서는

http://yyman.tistory.com/487 - [MFC] 윈도우 프로그래밍 기초 - 윈도우 객체 생성, 화면 띄우기

http://yyman.tistory.com/486 - [MFC] 윈도우 프로그래밍 기초 - 윈도우 클래스 만들기

 

윈도우의 객체를 만드는 기본 요소를 구현해보았다.

윈도우의 껍데기를 만드는 방법을 지금까지 수행하였는데, 이번에는 사용자로부터 명령을 받을 수 있는 기반을 만들어보고자 한다.

 


1. 원리

윈도우는 항상 루프(무한 반복)를 돌며 사용자의 메시지를 기다리고 있다가 메시지가 들어오면 받아서 처리한다.

 

1-1) 이벤트 처리 방식

-> 임의의 이벤트 (마우스 입력, 키보드 입력 등)가 발생할 때 처리하는 방식

 

 

음악을 재생하려면 플레이 버튼을 누른다. 버튼을 클릭하는 행위라고 볼 수 있지만, 근본적으로 이벤트 행위라고 볼 수 있다.

 


2. 메시지 루프

 

편집기(Editor) 프로그램의 경우, 키보드로부터 입력받은 문자를 화면에 출력하는 기능을 처리해야 한다.

이 때, IO Device(키보드, 마우스 등)으로부터 발생한 이벤트를 메시지 루프에서 감지하고 그 메시지를 윈도우 프로시져(Procedure) 함수로 보내주면, 화면에 해당하는 문자를 출력해준다.

 

즉, 윈도우 프로시져 함수로 메시지를 보내는 역할을 하는 것이 바로 메시지 루프의 역할이라고 할 수 있겠다.

 

 

 

 

이전 코드에 이어서

 

while ( GetMessage(&Message, 0, 0, 0) )

{

          TranslateMessage(&Message);   // 문자 입력을 처리하는 함수

          DispatchMessage(&Message);    // GetMessage() 함수로부터 전달된 메시지를 윈도우 프로시저로 보내는 역할 수행.

}

 

* 용어 정리

 

  용어 

 설명 

 시스템 큐

 시스템 큐는 운영체제가 가지고 있는 메시지 저장소로서 저장된 이벤트 메시지를 애플리케이션 큐로 넘겨준다.

 애플리케이션 큐

 애플리케이션 큐는 실행 중인 응용 프로그램마다 하나씩 가지고 있는 메시지 저장소이다.

 

while( ) 문으로 이루어진 메시지 루프는 GetMessage( ) 함수의 반환이 거짓이 될 때까지 계속 반복해서 돈다.

 


3. 애플리케이션에 대한 소개(읽어보기)

애플리케이션 큐는 응용프로그램이 소유한 메모리 버퍼라고 생각하면 된다.

우리가 직접 때때로 개발을 하다 보면, 애플리케이션 큐에 직접 메시지를 보내야 하는 경우가 있다.

 

-> 메시지 전달 함수 API에는 SendMessage()와 PostMessage() 함수가 있음.

 

* SendMessage() 함수

모든 메시지는 시스템 큐에서 애플리케이션 큐를 거쳐 윈도우 프로시져 함수로 전달된다고 알고 있으나, 이러한 과정을 모두 무시하고 윈도우 프로시저 함수로 바로 전달되는 메시지가 있다(). SendMessage()가 이러한 역할을 수행해준다.

이 함수는 메시지가 완전히 처리되기 전까진 반환되지 않는다. 메시지 처리 후 반드시 처리 확인이 필요한 경우에 이 함수를 사용하도록 한다.

 

* PostMessage() 함수

PostMessage() 함수를 이용하면 메시지는 시스템 큐를 거치지 않고, 직접 애플리케이션 큐에 보내진다. 이 함수로 메시지를 보내면 곧바로 반환되므로, 해당 메시지를 바로 처리하지 않고도 해당 메시지를 붙인 스레드는 다른 작업을 할 수 있다 즉, 메시지가 비동기적으로 처리 되어도 상관없는 경우에 이 함수를 사용한다.

 

쉽게 이해하려면, 저 함수의 Send, Post라는 단어로 유추해서 생각해보면 쉬울 것 같다.

마치 우편 수화물하고 같은 원리라고 보면 이해하기 쉬울 것 같다. (이메일의 경우, 보낸 후 수신확인을 통해 상대방이 확인했는지 확인하는 과정과 매우 흡사하다.

 


4. 메시지 처리하기

메시지 루프를 통해서 윈도우 프로시저로 전달된 메시지는 윈도우 프로시저가 구분하여 작업을 처리하게 된다.

따라서, 실질적인 코딩은 여기서 이뤄진다고 볼 수 있다.

 

WndProc()의 코드

 

LRESULT CALLBACK WndPrco(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

}

 

       HDC hdc;

       PAINTSTRUCT ps;

      

       switch(iMessage){

             case WM_CREATE:

                    return 0;

             case WM_PAINT:

                    hdc = BeginPaint(hWnd, &ps);

                    EndPaint(hWnd, &ps);

                    return 0;

             case WM_DESTROY:

                    PostQuitMessage(0);

                    return 0;

       }

 

       return(DefWindowProc(hWnd, iMessage, wParam, lParam) );

 

}

 

코드 해설

 

1. WndProc( )의 인수 구성요소

 

 

 인수 

  설명

 hWnd

 메시지를 받을 윈도우 핸들이다.

 iMessage

 전달된 메시지 값이다. 어떤 종류의 메시지인지, 즉 어떤 변화가 발생했는지에 대한 정보를 가지고 있다.

 wParam

 iMessage에 따른 부가 정보를 갖는다.

 예를 들어서 마우스 왼쪽 버튼이 눌렸을 때, 즉, WM_LBUTTONDOWN 메시지가 발생했을 때, 화면 어디쯤 위치에

 마우스 버튼이 눌러졌는지, 조합된 키가 눌러졌는지(Ctrl, Alt, Shift, 등....) 등의 정보가 필요하다.

 이러한 정보들이 wParam과 lParam에 각각 전달되며, 실제로 wParam과 lParam에 저장되어 있는 정보는 다르다.

 lParam

 

 

 

2. 메시지 구분

윈도우 프로시저의 4개의 인수 중에 iMessage에는 전달된 메시지 값이 담겨 있다.

바로 이 값으로 어떤 메시지가 들어왔는지 구분한다.

이 때 switch 문이 쓰인다.

switch 문의 괄호에 iMessage에 값에 따라 case 문으로 분기처리 된다.

 

case WM_LBUTTONDOWN:

return 0;작업처리

       return 0;

 

case 문에서 처리되지 않는 메시지는 DefWindowProc() 함수로 넘긴다.

 

3. DefWindowProc() 함수

이 함수는 WndProc에서 case문으로 처리하지 못한 메시지를 처리해준다.

 

LRESULT CALLBACK DefWindowProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

 

      

 

}

 

 


5. 참고자료

반응형

+ Recent posts