'Graphic'에 해당되는 글 1건

  1. 2015.02.24 [C/C++] GDI 를 이용한 그래픽 by TwoTen 3

출처 : http://blog.naver.com/PostView.nhn?blogId=kjg5345&logNo=150106170859


C &  C++  GDI 를 이용한 그래픽 .대화상자와 컨트롤 . 객체지향 프로그래밍의 이해(Object Oriented Programming) Dialog . control    


- 객체지향 프로그래밍의 이해(Object Oriented Programming)

 

프로그램을 작성할 때 객체를 기본으로 프로그램 작성

클래스(Class)를 이용하여 객체 표현

C와 C++ 프로그래밍 구조 비교

C

C++

구조적 프로그래밍

객체지향 프로그래밍

프로그램을 기능 단위로 세분

프로그램을 객체단위로 세분

함수로 구성

클래스로 구성

중형 프로그램

대형 프로그램


-객체지향 프로그래밍의 예

중국집에서의 작업

C(별도의 메시지가 필요 없음)

C++(메시지로 각 역할의 시작과 종료)

인사

자리안내

주문접수

요리

요리서빙

계산

인사함수()

자리함수()

주문함수()

요리함수()

서빙함수()

계산함수()

종업원

인사

자리안내

주문접수

요리서빙

요리사

요리

카운터

계산


- Class의 생성

ClassView에서 생성:

ClassView->오른쪽마우스->New Class선택->Class 이름 및 base Class선택

변수추가: Class이름 오른쪽마우스->Add Member varibles

함수추가: Class이름 오른쪽마우스->Add Member Functions


ClassWizard를 사용해서 생성:

ClassWizard->add Class선택 이후 과정은 동일

변수추가: Member variables탭 사용

함수추가: 메시지 연동 함수만 추가 가능 message선택 -> add function


- 지역변수 전역변수

지역변수: 함수내에서만 사용

전역변수: 프로그램 전체에서 사용

int a;

void function()

{

        int b,c;

        ...

}


- 데이터 캡슐화

C

C++

변수만을 캡슐화

변수와 함수를 캡슐화

외부의 함수에 의해 수동으로 제어

내부의 함수를 통해 능동적으로 동작

struct Point{

   int x;

   int y;

};

class Point{

   int m_nX;

   int m_nY;

   void Move(int nX, int nY);

}


- Class의 개요

클래스의 선언(*.h)

Class Test{

public:

        int m_nX;

        int m_nY;

        

        void SetPosition(int nX, int nY);

}

        

클래스의 구현(*.cpp)

void Test::SetPosition((int nX, int nY)

{

        m_nX=nX;

        m_nY=nY;

}

클래스의 사용

Test a;

a.m_nX=10;

a.m_nY=20;

a.SetPosition(30,40);


- 생성자, 소멸자

Class CTest{

        CTest();

        virtual ~CTest();

}

생성자: Class초기화 메모리 생성, 변수에 초기값 지정

       생성자 호출: CTest a;

소멸자: 메모리 정리

        소멸자 호출: 자동


- public, private, protected

public:  클래스 외부에서도 사용

private: 클래스 내부에서만 사용

protect: 클래스 내부에서만 사용


- 연산자 오버로딩: 연산자를 함수처럼 사용

연산자의 종류

단항연산자: (전위형)a++; (후위형)++a;

이항연산자: a = a + b;


void Point::Increase()

{

        m_nX++;

        m_nY++;

}


main()

{

        Point p;

        p.Increase();

}

전위형 연산자의 연산자 오버로딩을 할 경우

main()

{

        Point p;

        ++p;

}


class Point

{

        void Increase();

        void operator++();

}

클래스의 사용

p.operator++(); -> ++p;

void Point::operator++()

{

        m_nX++;

        m_nY++;

}

아래 형식이 가능하게 할려면

Point p,q;

q = ++p;

Point Point::operator++()

{

        m_nX++;

        m_nY++;

        Point newPoint;

        newPoint.m_nX = m_nX;

        newPoint.m_nY = m_nY;

}


이항연산자의 오버로딩

Point a,b,c;

a = b + c;

a = b.operator+(c);


Point Point::operator+(Point &point)

{

        Point temp;

        temp.m_nX = m_nX + point.m_nX;

        temp.m_nY = m_nY + point.m_nY;

        return temp;

}


- 상속성: 이미 존재하는 클래스의 모든 특성을 물려받아서 새로운 클래스 생성

기반클래스, 파생클래스

class BaseClass{

public:

        int BaseVariable1;

        int BaseVariable2;


        void BaseFunction1();

        void BaseFunction2();

}


class DerivedClass : public BaseClass{

        int DrivedVarivariable;

        void DrivedFunction();

}


Protected와 Private의 차이

public: 클래스내부와 외부에서 모두 사용

protected: 클래스내부에서만 사용, 파생클래스 내부에서 사용가능

private: 클래스내부에서만 사용, 파생클래스 내부에서 사용 불가능


public상속과 private상속

public상속: 기반클래스의 public 멤버를 외부에서 사용 가능

private상속: 기반클래스의 public 멤버를 외부에서 사용 불가능


멤버함수의 재정의(Overriding)***: 파생클래스를 생성 후 기존 함수 중 필요한 함수를 재 정의


class Point3D : public Point

{

public:

        int m_nZ;

        void Show();

}

void Point3D::Show()

{

        cout << "Z=" << m_nZ << "Y=" << m_nY << "X=" <<m_nX;

}


void Point3D::Show()

{

        cout << "Z=" << m_nZ;

        Point::Show();

}


오버로딩(overloading)과 오버라이딩(overriding)

오버로딩: 중첩해서 여러 개의 기능을 하나의 함수나 연산자에게 추가하는 것

오버라이딩: 옛날의 기능을 없애고 새로운 기능을 부여


함수 오버로딩

class test

{

        int max(int a, int b);

        double max(double a, double b);

}

int test::max(int a, int b)

{

        if(a > b) return a;

        else     return b;

}

double test::max(double a, double b)

{

        if(a > b) return a;

        else     return b;

}


가상함수(Virtual Function): 동적 바인딩

함수의 바인딩: 컴파일을 하면 함수의 메모리상의 위치가 저장

        정적바인딩: 컴파일을 할 때 바인딩이 되는 경우

        동적바인딩: 실행을 할 때 바인딩(점프할 위치를 결정)이 되는 경우

                    단점-속도저하, 메모리 번지를 저장할 포인터 필요


Point *p;

Point point;

Point3D point3d;


p = &point;

p->Show();

p = &point3d;

p->Show();


두 가지 경우 모두 Point 클래스의 Show함수를 호출


기반 클래스의 Show를 가상함수로 선언하면 문제 해결된다.-실행할 때 바인딩을 해 주기 때문에

virtual void Show();


inline함수: 함수를 호출하는 부분에 통째로 복사; 수행속도가 빨라짐, 실행파일의 크기가 큼


inline함수의 선언

묵시적인방법: 헤더파일에서 함수의 본체 선언

명시적인방법: 함수를 선언할 때 inline이라는 예약어를 사용

              inline void SetPosition(int x, int y)

              {

              }


-레퍼런스

값 복사에 의한 호출: call by value

void Swap(int a, int b)

{

        int temp;

        temp = a;

        a = b;

        b = temp;

}


main()

{

        int x=10, y=20;

        Swap(x,y);

        cout << x << y;

}


레퍼런스에 의한 호출: call by reference

void Swap(int &a, int &b)

{

        int temp;

        temp = a;

        a = b;

        b = temp;

}


-this 포인터

class Where

{

        int data;

        void PrintPointer();

}


void Where::PrintPointer()

{

        cout << “오브젝트의 주소는” << this << “ 번지입니다.\n";

}//각 객체의 주소 출력, 파라미터로 자신의 주소를 다른 함수에 넘겨줄 때 활용


main()

{

        Where a,b,c;

        a.PrintPointer();

        b.PrintPointer();

        c.PrintPointer();

}


-const 변수/함수: 변수의 값을 변경 못하게 함

const double pi = 3.141592;

pi = 10; //에러


class Count {

        int GetCount() const; //멤버변수를 변경 시키지 못함

        int m_nCount;

}

int GetCount() const

{

        return m_nCount;

}


2. Visual C++의 구성


-MFC: 약 300개의 클래스로 구성

프로그램의 뼈대: AFX(application frameworks)

윈도우

그래픽

자료구조

파일 및 데이터베이스

인터넷

OLE: 분산 환경 컴포넌트

에러처리 디버깅


-간단한 자료구조 클래스들

CPoint: 2차원 좌표계

CSize: 가로세로의 길이를 지정

CRect: 사각형의 좌측상단과 우측하단의 좌표지정, 사각형의 현태 지정

CString: 문자열의 저장


3. 코딩의 규칙: 의미 있는 변수 명 지정

클래스 멤버변수 표기법: m_

헝가리안 표기법: 표1-7참조

        m_lpszFilename = m_ + lp + sz +Filename

데이터형:

        BOOL: 0 or 1

        BYTE: 8bits unsigned 정수

        LONG: 32bits signed 정수

        FLOAT: 소숫점

        UINT: 32bits unsigned 정수

        LPSTR: 널 문자로 끝나는 윈도우 문자열 포인터


Chapter 2


1. 프로그램의 뼈대


-일관된 사용자 인터페이스

-프로그램의 뼈대:AFX 공통적으로 수행하는 기능을 자동 구현

-윈도우 프로그램의 객체지향적 분할

CFramWnd: 윈도우의 틀(윈도의 모양변화)

  CView: 윈도우(데이터를 화면에 표시)

  CDocument: 자료,데이터, 여러 개의 View윈도우와 관련 가능





-AFX클래스들의 계층구조

CObject: 기반클래스

        CCmdTarget: 이벤트 처리

                CWinApp: 프로그램 구동

                CDocument: 자료

                CWnd: 윈도우

                        CFrameWnd: 윈도우 틀

                        CView: 윈도우 내부


CWinApp클래스

-윈도우 프로그램의 동작방식: 메시지 구동 방식

WM_CREATE

WM_ACTIVATE

WM_PAINT

WM_MOUSEMOVE/ LBUTTONDOWN/ LBUTTONUP/ LBUTTONDBLCLK

WM_COMMAND

WM_KEYDOWN/ KEYUP

WM_SIZE/ MOVE/ TIMER/ DESTROY


****spy++ 프로그램으로 메시지 확인


-메시지 구조

typedef struct tagMSG{

        HWND       hwnd;            윈도우 핸들,포인터

        UINT        message;         메시지 종류

        WPARAM    wParam;          추가정보; 키보드문자, 마우스버튼

        LPARAM     lParam;           추가정보

        DWORD      time;              시간

        POINT       pt;               마우스 좌표

}


-CWinApp의 역할: 프로그램을 구동

파생클래스 생성(APP Wizard)






CWinApp의 프로그램 구동 원리








- CWnd 클래스: 윈도우 프로그램의 핵심

300여개의 멤버함수(100: 윈도우 상태제어, 200: 메시지 처리 함수)

WM_CREATW          ->     OnCreate()

WM_PAINT            ->     OnPaint()


- 메시지 처리기의 구조








- CDocument 클래스: 데이터를 불러오고 저장하고 처리하는 모든 기능


- AFX 클래스들간의 상호 작용






2. 뼈대 만들기와 살 붙이기


뼈대만들기


-AppWizard: SDI, MDI, Dialog

생성되는 클래스들: CMyApp, CMyDoc, CMainFrame, CMyView


-ClassView, FileView


살붙이기


- 프로그램의 뼈대에 있는 기능의 수정 보완

멤버함수의 재정의(overriding)

ClassWizard의 사용: [ctrl-w] or View | ClassWizard 선택


- 프로그램의 뼈대에 새로운 기능 추가

멤버 변수/함수 추가

ClassView에서 원하는 클래스명 위에서 오른쪽 마우스 버튼 클릭 - add member Fuction 또는 Variable선택


이벤트처리기 추가(메뉴에 기능 구현)


3. 프로그램 뼈대 구조 이해


마우스 왼쪽 버튼을 누르면 화면에 "X"표시하는 프로그램


step 1: AppWizard로 SDI project생성

step 2: CView클래스에서 함수 추가(DrawX) - add member function


#define SIZE 10

void CDrawXView::DrawX(CPoint point)

{

        CClientDC dc(this);


        dc.MoveTo(point.x-SIZE*m_nMag, point.y-SIZE*m_nMag);

        dc.LineTo(point.x+SIZE*m_nMag, point.y+SIZE*m_nMag);

        dc.MoveTo(point.x-SIZE*m_nMag, point.y+SIZE*m_nMag);

        dc.LineTo(point.x+SIZE*m_nMag, point.y-SIZE*m_nMag);

}


step 3: 마우스 버튼이 클릭될 때 마다 호출되는 메시지 WM_LBUTTONDOWN에 연동되는 함수를 만들고 그 안에서 DrawX를 호출하게 프로그램밍

void CDrawXView::OnLButtonDown(UINT nFlags, CPoint point)

{

        DrawX(point);

        CView::OnLButtonDown(nFlags, point);

}


도큐먼트/뷰 구조를 이용한 프로그램


- 깨진 화면 복원 방법

메뉴나 마우스 커서의 화면 복원 방법: 그 부분을 메모리에 저장 후 다시 그려 줌

일반 윈도우 화면 복원 방법: 저장하는 방법은 메모리의 소모가 너무 크다->밑에 깔린 윈도우에 역할 맡김; 다시 한번 그림

윈도우가 다시 그려져야 할 필요가 있을 때 발생하는 메시지: WM_PAINT ->OnPaint()

CView클래스:OnPaint()함수 안에서 OnDraw()함수를 호출? 프린터기능도 부여하기 위해서


*깨진 화면 복원 방법*


Step 1: Document클래스에 그려야 할 데이터를 저장한다.

        CPoint m_ptData[100]; //위치를 저장할 변수 추가

        int m_nCount;          //저장된 위치 값의 개수 표시

        생성자 함수에서 m_nCount의 초기화 -> m_nCount = 0;

        

Step 2: CView에서 마우스를 클릭할 때 마다 화면에 "X"를 표시하고 또한 이값을 Document에 저장

        OnLButtonDown함수에서

        CDoc     *pDoc = GetDocument();

        if(pDoc->m_nCount <100)

        {

                pDoc->m_ptData[pDoc->m_nCount] = point;

                pDoc->m_nCount++;


                DrawX(point);

        }


Step 3: OnDraw()함수를 이용한 화면 복원

        CDoc *pDoc = GetDocument();

        ASSERT_VALID(pDoc);

        for(int i=0;i<pDoc->m_nCount;i++){

                DrawX(pDoc->m_ptData[i]);

        }



*메뉴 이벤트 처리: WM_COMMAND처리(메뉴의 종류가 너무 많아서 일반 윈도우 메시지와는 다른 Menu의 ID를 보조 정보로 사용)

ResoureView-Menu-마우스 더블클릭-Menu Item Properties


ID: 프로그램 내부적으로 사용 되는 이름

Caption: 메뉴 화면에 보이는 항목


데이터보기에 관련된 메뉴 처리의 예: X표 크기 조절 CView에서 수행


그래픽 처리 -> 145page그림 참조

classwizard - object IDs: ID_ORIGINALSIZE, Messages: COMMAND


void CDrawXView::OnOriginalsize()

{

        m_nMag = 1;

        Invalidate();            //WM_PAINT발생

}

void CDrawXView::OnMagnify()

{

        m_nMag = 2;

        Invalidate();

}

m_nMag의 클래스 멤버변수 등록


그리는 루틴에 (위치 값 * m_nMag)


* X표 좌우로 이동

step 1: 메뉴추가

        데이터처리 - 좌로이동(&L)  ID_LEFT

                   - 우로이동(&R)  ID_RIGHT


step2: 이벤트 처리 추가

        classwizard에서 ID_LEFT, ID_RIGHT에 아래 함수 추가

void CDrawXDoc::OnLeft()

{

        for(int i=0;i<m_nCount;i++){

                m_ptData[i].x -= 50;

        }

        UpdateAllViews(NULL);//현재Document에 연결된 모든 View에 WM_PAINT발생

}

void CDrawXDoc::OnRight()

{

        for(int i=0;i<m_nCount;i++){

                m_ptData[i].x += 50;

        }

        UpdateAllViews(NULL);

}


데이터 저장 및 읽어오기: CDocument - Serialize()


-파일 입출력 메뉴: 그림 2-45참조

ID_FILE_New-CWinApp::OnFileNew()-CDocument::OnNewDocument()//인스턴스 선언

ID_FILE_OPEN-CWinApp::OnFileOpen()-CDocument::OnOpenDocument()-Serialize()

ID_FILE_SAVE-CWinApp::OnFileSave()-CDocument::OnSaveDocument()-Serialize()

ID_FILE_SAVW_AS-CWinApp::OnFileSaveAs()-CDocument::OnOpenDocument()-Serialize()


* Serialize함수를 이용하여 저장하기


void CTest1Doc::Serialize(CArchive& ar)

{

        if (ar.IsStoring())  //저장

        {

                ar << n;  //연산자 오버로딩

        }

        else              //읽기

        {

                ar >> n;

        }

}


CArchive클래스: 데이터의 저장/읽어오기를 담당하는 클래스 CDocument <> CFile을 연결

                 OnOpenDocument()과 OnSaveDocument()에서 인스턴스 선언이 된다.


- DrawX데이터 저장 및 읽어오기


void CDrawXDoc::Serialize(CArchive& ar)

{

        int i;

        if (ar.IsStoring())  //저장

        {

                ar << m_nCount;

                for(i=0;i<m_nCount;i++){

                        sr << m_ptData[i];

                }

        }

        else              //읽기

        {

                ar >> m_nCount;

                for(i=0;i<m_nCount;i++){

                        sr >> m_ptData[i];

                }

        }

}


-파일대화 상자부터 CArchive를 이용해서 데이터를 입출력하는 과정까지 한 번에 처리


char szFilter[] = "Text File(*.txt)|*.txt|All Files(*.*)|*.*||";


void CFileDialogDoc::OnFileOpen()

{

        // TODO: Add your command handler code here

        int i;

        CFileDialog dlg(true, NULL, NULL, OFN_HIDEREADONLY, szFilter);

        if(IDOK==dlg.DoModal())

        {

                CFile file;

                file.Open(dlg.GetPathName(), CFile::modeRead);

                CArchive ar(&file,CArchive::load);

                ar >> m_nCount;

                for(i=0;i<m_nCount;i++){

                        ar >> m_ptData[i];

                }

        }

}


void CFileDialogDoc::OnFileSave()

{

        // TODO: Add your command handler code here

        int i;

        CFileDialog dlg(false, NULL, NULL, OFN_HIDEREADONLY, szFilter);

        if(IDOK==dlg.DoModal())

        {

                CFile file;

                file.Open(dlg.GetPathName(), CFile::modeCreate|CFile::modeWrite);

                CArchive ar(&file,CArchive::store);

                ar << m_nCount;

                for(i=0;i<m_nCount;i++){

                        ar << m_ptData[i];

                }

        }

}


Chap 3 GDI를 이용한 그래픽


1. 윈도우 그래픽의 이해


하드웨어 독립적인 프로그래밍: Hardware Independent Programming


-디바이스 드라이버에 의한 독립적 프로그래밍

응용프로그램

윈도우운영체제                  하드웨어 독립

----------------

디바이스드라이버                하드웨어 종속

디바이스(하드웨어)


-컬러모드 독립적 프로그래밍

다양한 컬러 모드가 존재: 1bits,4bits,8bits,16bits,24bits,32bits 이러한 모드에 상관없이 프로그래밍


윈도우 그래픽


그래픽 디바이스 인터페이스(GDI:Graphic Device Interface):

        그래픽에 관련된 모든 기능

디바이스 컨텍스트(DC:Device Context):

        화가, 그래픽에 필요한 모든 옵션들

GDI 오브젝트(GDI object):

        도구, Pen, Brush, Font, Bitmap, Palette, Region


그래픽 관련 MFC클래스


-디바이스 컨텍스트 클래스

CDC클래스: 윈도우마다 각각의 DC가 존재한다.

        CDC *pDC = GetDC();

        pDC->Rectangle(10,10,100,100);

        ReleaseDC(pDC);


CClientDC클래스

        CClientDC dc(this);

        pDC->Rectangle(10,10,100,100);


-GDI 오브젝트 글래스

펜: CPen

브러시(붓):CBrush

글꼴: CFont

비트맵: CBitmap

팔레트: CPalette

영역: CRgn


2. 펜과 브러시


펜과 브러시를 이용한 그래픽:

함수

그리기 기능

MoveTo, LineTo

Rectangle, FillRect, FrameRect, Draw3DRect

사각형

Ellipse

타원

Pie

파이

Arc, ArcTo, AngleArc, Chord

Polygon

다각형

PolyDraw, PolyBezier, PolyBezierTo

베지어 곡선

FrameRgn

영역의 경계선


GDI오브젝트 생성 함수

클래스

멤버 함수

CPen

CreatePen

CBrush

CreateSolidBrush, CreateHatchBrush, CreatePatternBrush

CFont

CreateFont, CreateFontIndirect

CBitmap

CreateBitmap, CreateCompatibleBitmap, LoadBitmap

CPalette

CreatePalette

CRgn

CreateRectRgn, CreateEllipseRgn, CreatePolygonRgn,


그래픽 옵션 바꾸기


CPen pen;

pen.CreatePen(PS_SOLID,3,RGB(255,0,0));

CClientDC dc(this);

CPen *pOldPen = dc.SelectObject(&pen);

dc.Rectangle(10,10,100,100);

dc.SelectObject(pOldPen);


내장(stock)GDI 오브젝트: 자주 사용하는 오브젝트는 미리 만들어 놓음, 메모리 상주


내장 GDI 오브젝트

GDI 오브젝트 종류

내장 GDI 오브젝트

BLACK_PEN

WHITE_PEN

NULL_PEN

브러시

BLACK_BRUSH

WHITE_BRUSH

DKGRAY_BRUSH

GRAY_BRUSH

HOLLOW_BRUSH

LTGRAY_BRUSH

NULL_BRUSH

글꼴

ANSI_FIXED_FONT

ANSI_VAR_FONT

DEVICE_DEFAULT_FONT

OEM_FIXED_FONT

SYSTEM_FONT


그래픽 옵션 바꾸기

CClientDC dc(this);

dc.SelectStockObject(RED_PEN);

dc.Rectangle(10,10,100,100);

-------------------------------------------------------------------

펜 스타일

펜스타일

 

PS_SOLID

실선

PS_DASH

파선

PS_DOT

점선

PS_DASHDOT

일점점선

PS_DASHDOTDOT

이점점선

PS_NULL

선을 그리지 않음


3. 펜과 브러시로 그리기


예제: 무작위로 정해진 색깔, 모양, 위치등을 이용하여 다양한 도형을 그리는 프로그램

        SetTimer(타이머번호, 시간, NULL)      ;정해진 시간마다 WM_TIMER발생

        KillTimer(타이머번호)                   ;타이머를 제거

        WM_TIMER->OnTimer()함수            ;함수호출

        OnIntialUpdate()함수                    ;View의 초기화

        WM_DESTROY->OnDestroy()함수       ;윈도우의 종료 시 수행


void CGDIDemoView::OnInitialUpdate()

{

        CView::OnInitialUpdate();

        

        // 0.1초마다 WM_TIMER 메시지가 발생하도록 설정

        SetTimer(0, 100, NULL);

}


void CGDIDemoView::OnDestroy()

{

        CView::OnDestroy();

        

        // 타이머를 꺼줌

        KillTimer(0);

}


#define OBJ_LINE              0

#define OBJ_RECTANGLE      1

#define OBJ_ELLIPSE          2

#define OBJ_ROUNDRECT      3

#define OBJ_CHORD           4

#define OBJ_PIE                       5


void CGDIDemoView::OnTimer(UINT nIDEvent)

{

    CClientDC dc(this);                         // 화면 출력을 위한 DC 클래스

    CRect rect;                                 // 화면 크기를 얻기 위한 변수

    CBrush brush, *pOldBrush;                 // 브러시 오브젝트

    CPen pen, *pOldPen;                        // 펜 오브젝트


    int  x1,y1,x2,y2,x3,y3,x4,y4;               // 화면 좌표

    int  r,g,b;                                   // 컬러

    int  nObject;                                // 그래픽 타입

        

    GetClientRect(rect);                        // 화면의 크기를 얻는 함수


    r = rand() % 255;                          // 컬러를 랜덤하게 설정

    g = rand() % 255;

    b = rand() % 255;

    brush.CreateSolidBrush(RGB(r,g,b));         // 브러시 생성

    pOldBrush = (CBrush *)dc.SelectObject(&brush); // DC에 브러시 선택


    r = rand() % 255;                          // 컬러를 랜덤하게 설정

    g = rand() % 255;

    b = rand() % 255;

    pen.CreatePen(PS_SOLID, 5, RGB(r,g,b));   // 펜 생성

    pOldPen = (CPen *)dc.SelectObject(&pen);  // DC에 펜 선택


    x1 = rand() % rect.right;                   // 좌표를 랜덤하게 설정

    y1 = rand() % rect.bottom;

    x2 = rand() % rect.right;

    y2 = rand() % rect.bottom;

    x3 = rand() % rect.right;

    y3 = rand() % rect.bottom;

    x4 = rand() % rect.right;

    y4 = rand() % rect.bottom;


    nObject = rand() % 6;                      // 그래픽 타입을 랜덤하게 설정


    switch(nObject)

    {

        case OBJ_LINE:                        // 라인 그리기

            dc.MoveTo(x1,y1);

            dc.LineTo(x2,y2);

            break;


        case OBJ_RECTANGLE:                // 사각형 그리기

            dc.Rectangle(x1,y1,x2,y2);

            break;


        case OBJ_ELLIPSE:                    // 타원 그리기

            dc.Ellipse(x1,y1,x2,y2);

            break;


        case OBJ_ROUNDRECT:                 // 둥근 사각형 그리기

            dc.RoundRect(x1,y1,x2,y2,x3,y3);

            break;


        case OBJ_CHORD:                      // 현 그리기

            dc.Chord(x1,y1,x2,y2,x3,y3,x4,y4);

            break;


        case OBJ_PIE:                         // 파이 그리기

            dc.Pie(x1,y1,x2,y2,x3,y3,x4,y4);

            break;

    }


    dc.SelectObject(pOldPen);                          // DC 복원

    dc.SelectObject(pOldBrush);                         // DC 복원


    CView::OnTimer(nIDEvent);

}


예제: 벽에 부딪히면 튀는 공

        SetTimer(타이머번호, 시간, NULL)      ;정해진 시간마다 WM_TIMER발생

        KillTimer(타이머번호)                   ;타이머를 제거

        WM_TIMER->OnTimer()함수            ;함수호출

        OnIntialUpdate()함수                    ;View의 초기화

        WM_DESTROY->OnDestroy()함수       ;윈도우의 종료 시 수행


void CBounceView::OnInitialUpdate()

{

        CView::OnInitialUpdate();

        

        // 0.05초마다 WM_TIMER 메시지가 발생하도록 설정

        SetTimer(0, 50, NULL);

}


void CBounceView::OnDestroy()

{

        CView::OnDestroy();

        

        // 타이머를 꺼줌

        KillTimer(0);

}


#define R 20

#define STEP 5


void CBounceView::OnTimer(UINT nIDEvent)

{

        CClientDC dc(this);

        static int nX=R, nY=R;                         // 현재 공의 위치

        static int nCX=STEP, nCY=STEP;              // 공의 이동 방향


        CRect rect;                            // 클라이언트 영역의 크기

        GetClientRect(&rect);                   // 클라이언트 영역의 크기를 얻음


        // 이전 공을 지우기 위해 흰색 브러시를 선택

        dc.SelectStockObject(WHITE_BRUSH);

        dc.Ellipse(nX-R,nY-R,nX+R,nY+R);     // 원 그리기


        // x 좌표 변경

        if(nX < R) nCX = STEP;

        else if(nX > rect.Width()-R) nCX = -STEP;

        nX += nCX;

        

        //y 좌표 변경

        if(nY < R) nCY = STEP;

        else if(nY > rect.Height()-R) nCY = -STEP;

        nY += nCY;

        

        // 새로 공을 그리기 위해 빨간색 브러시 생성

        CBrush brush, *pOldBrush;

        brush.CreateSolidBrush(RGB(255,0,0));


        // DC에 빨간색 브러시 선택

        pOldBrush = (CBrush *)dc.SelectObject(&brush);

        dc.Ellipse(nX-R,nY-R,nX+R,nY+R);             // 원 그리기

        dc.SelectObject(pOldBrush);                    // DC 복원

        CView::OnTimer(nIDEvent);

}


4. 펜과 브러시의 레스터 오퍼레이션: 새로운 그림과 기존의 그림을 합성하는 방법


int SetROP2(int nDrawMode);    


레스터 오퍼레이션 코드 의미

레스터 오퍼레이션 코드

연산

R2_COPYPEN

P

R2_XORPEN

P^D

PS_NOTXORPEN

~(P^D)

PS_NOT

~(P&D)

P: 새로운 그림, D: 기존 배경, ^: XOR, ~: NOT, &: AND


R2_COPYPEN                  : 새로운 그림

R2_XORPEN                    : 기존 그림과 새로운 그림 XOR


x

y

z(결과)

0

0

0

0

1

1

1

0

1

1

1

0

 

R

G

B

바탕색

1100

0101

1111

새로운색

0101

1110

1010

결과XOR

1001

1011

0101

새로운색

0101

1110

1010

결과XOR

1100

0101

1111

->애니메이션에 활용, 한번 그려주면 그림이 그려지고 다시 한번 그리면 원래의 바탕 그림이 회복되는 모드


-마우스를 드래그하면서 선을 그리는 프로그램 예제


class CRop2View : public CView

{

public:

        CPoint m_Pt1, m_Pt2;                          //라인을 그리기 위한 두 지점

};


void CRop2View::OnLButtonDown(UINT nFlags, CPoint point)

{

        m_Pt1 = m_Pt2 = point;

        

        CView::OnLButtonDown(nFlags, point);

}


void CRop2View::OnMouseMove(UINT nFlags, CPoint point)

{

        if(nFlags & MK_LBUTTON)

        {

                CClientDC dc(this);

                

                //레스터 오퍼레이션을 R2_XORPEN으로 설정

                dc.SetROP2(R2_XORPEN);      


                //흰색 펜을 선택

                dc.SelectObject( GetStockObject(WHITE_PEN) );


                //이전에 그려진 선을 지웁니다.

                dc.MoveTo(m_Pt1);

                dc.LineTo(m_Pt2);

                

                //새로 선을 그립니다.

                dc.MoveTo(m_Pt1);

                dc.LineTo(point);


                //현재 점을 다음에 지워질 점으로 저장해 둡니다.

                m_Pt2 = point;

        }

        

        CView::OnMouseMove(nFlags, point);

}


5. 글꼴 및 텍스트 출력하기: Font GDI = CFont


논리적인 글꼴: 모양 형태 등의 논리적인 정의 = 구조체(structure)

typedef struct tagLOGFONT{

        LONG lfHeight         //높이

        LONG lfWidth          //너비

        LONG lfEscapement    //방향

        LONG lfOrientation     //회전각도

        LONG lfWeight         //굵기

        BYTE lfItalic           //기울임

        BYTE lfUnderline      //밑줄

        BYTE lfStrikeOut       //취소선

        BYTE lfCharSet         //문자세트

        BYTE lfOutPrecision   //출력정확도

        BYTE lfClipPrecision   //클리핑정확도

        BYTE lfQuality         //출력의 질

        BYTE lfPitchAndFamily  //자간

        CHAR lfFaceName     //글꼴이름

}LOGFONT;


글꼴형 변수 선언: 

LOGFONT m_logFont


        m_logFont.lfHeight             = 100;

        m_logFont.lfWidth              = 0;

        m_logFont.lfEscapement         = 0;

        m_logFont.lfOrientation         = 0;

        m_logFont.lfWeight             = FW_NORMAL;

        m_logFont.lfItalic               = FALSE;

        m_logFont.lfUnderline          = FALSE;

        m_logFont.lfStrikeOut           = FALSE;

        m_logFont.lfCharSet            = DEFAULT_CHARSET;

        m_logFont.lfOutPrecision       = OUT_CHARACTER_PRECIS;

        m_logFont.lfClipPrecision       = CLIP_CHARACTER_PRECIS;

        m_logFont.lfQuality             = DEFAULT_QUALITY;

        m_logFont.lfPitchAndFamily     = DEFAULT_PITCH|FF_DONTCARE;

        strcpy(m_logFont.lfFaceName, _T("Times New Roman"));


물리적인 글꼴: 현재 컴퓨터에 설치되어 있는 글꼴 중 가까운 글꼴 선택


-CFont를 이용한 글꼴 생성:

크기와 이름만 입력 나머지는 디폴트 사용:CreatePointFont

CFont font;

font.CreatePointFont(100,_T("Times New Roman"));

세밀한 글꼴의 생성: CreateFontIndirect 또는 CreateFont


font.CreateFontIndirect(&logFont);   //미리 logFont에 옵션을 다 채워야 함

or

font.CreateFont(100,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,

        DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,

        CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,

        DEFAULT_PITCH|FF_DONTCARE,_T("Times New Roman"));


CFontDialog공통대화 상자: 옵션을 공통 다이얼로그 박스에서 채워줌  = 가장 보편적임


텍스트 출력함수:

(1) BOOL TextOut(int x, int y, const CString& str)                    :점을 기준

정렬방법

의미

TA_CENTER

수평 중심으로 정렬

TA_LEFT

왼쪽 기준

TA_RIGHT

오른쪽 기준

TA_BASELINE

선택된 폰트의 베이스라인과 일치

TA_BOTTOM

사각형의 바닥 기준

TA_TOP

사각형의 상단 기준

CClientDC dc(this)

dc.SetTextAlign(TA_LEFT | TA_TOP);

dc.TextOut(x,y,"This is a Test");


(2) int DrawText(const CString& str, LPRECT lpRect, UINT nFormat) :사각형을 기준

정렬방법

의미

DT_BOTTOM

사각형의 바닥 기준

DT_CENTER

수평 중심 기준

DT_RIGHT

오른쪽 기준

DT_LEFT

왼쪽 기준

DT_SINGLELINE

한줄 만

DT_VCENTER

수직 중심 기준

CClientDC dc(this)

dc.DrawText("This is a Test", &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER);


텍스트 색상설정 함수:

(1) SetTextColor(RGB(255,0,0));         //글꼴의 색상 선택

(2) SetBkColor(RGB(255,0,0));          //배경색의 설정

(3) SetBkMode(OPAQUE);              //배경을 투명(TRANSPARENT)하게 또는 불투명(OPAQUE)하게 할거냐 선택


- 텍스트 출력하는 예제 프로그램 구현


(1) 멤버 변수 선언

class CFontView : public CView

{

        BOOL m_bTransparent;         // 텍스트의 배경을 투명하게 할 것인지

        COLORREF m_colorText;       // 텍스트 전경색

        COLORREF m_colorBk;         // 텍스트 배경색

        LOGFONT m_logFont;          // 텍스트를 출력할 논리적 글꼴


(2) 멤버 변수 초기화


CFontView::CFontView()

{

        m_bTransparent = FALSE;

        m_colorText = RGB(0, 0, 255);

        m_colorBk = RGB(255, 255, 0);

        

        m_logFont.lfHeight             = 100;

        m_logFont.lfWidth              = 0;

        m_logFont.lfEscapement = 0;

        m_logFont.lfOrientation = 0;

        m_logFont.lfWeight             = FW_NORMAL;

        m_logFont.lfItalic               = FALSE;

        m_logFont.lfUnderline  = FALSE;

        m_logFont.lfStrikeOut   = FALSE;

        m_logFont.lfCharSet            = DEFAULT_CHARSET;

        m_logFont.lfOutPrecision       = OUT_CHARACTER_PRECIS;

        m_logFont.lfClipPrecision       = CLIP_CHARACTER_PRECIS;

        m_logFont.lfQuality             = DEFAULT_QUALITY;

        m_logFont.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;

        strcpy(m_logFont.lfFaceName, _T("Times New Roman"));

}


(3)텍스트 출력


void CFontView::OnDraw(CDC* pDC)

{

        // 클라이언트 영역의 크기를 얻어냄

        CRect rect;

        GetClientRect(&rect);


        // LOGFONT로부터 글꼴을 생성

        CFont newFont, *pOldFont;

        newFont.CreateFontIndirect(&m_logFont);


        // 생성된 글꼴을 DC에 선택

        pOldFont = (CFont *)pDC->SelectObject(&newFont);


        // 텍스트의 전경색과 배경색 설정

        pDC->SetTextColor(m_colorText);

        pDC->SetBkColor(m_colorBk);

        

        // 배경 모드를 설정

        if(m_bTransparent) pDC->SetBkMode(TRANSPARENT);

        else pDC->SetBkMode(OPAQUE);


        // 텍스트 출력

        pDC->DrawText("Hello",&rect,

                          DT_SINGLELINE|DT_CENTER|DT_VCENTER);

}


(4)메뉴 편집


텍스트옵션                      

글꼴변경                        IDM_FONT

텍스트 전경색                   IDM_FORECOLOR

텍스트 배경색                   IDM_BACKCOLOR

텍스트 배경 투명하게            IDM_BKMODE


(4-1)글꼴변경                  IDM_FONT

void CFontView::OnFont()

{

        CFontDialog dlg(&m_logFont);

        if(dlg.DoModal() == IDOK)

        {

                dlg.GetCurrentFont(&m_logFont);

                Invalidate();

        }

}


(4-2)텍스트 전경색             IDM_FORECOLOR

void CFontView::OnForecolor()

{

        CColorDialog dlg(m_colorText); 

        if( dlg.DoModal() == IDOK )

        {

                m_colorText = dlg.GetColor();

                Invalidate();

        }

}

(4-3)텍스트 배경색             IDM_BACKCOLOR

void CFontView::OnBackcolor()

{

        CColorDialog dlg(m_colorBk);   

        if( dlg.DoModal() == IDOK )

        {

                m_colorBk = dlg.GetColor();

                Invalidate();

        }

}


(4-4)텍스트 배경 투명하게      IDM_BKMODE

void CFontView::OnBkmode()

{

        m_bTransparent = !m_bTransparent;

        Invalidate();

}


Chap 4 대화상자와 컨트롤


1. 대화상자와 컨트롤의 이해: 사용자의 입력=컨트롤들의 관리


(1) 대화상자의 역할

대화상자 리소스: ResourceView->Insert Dialog, 모양 디자인

[alt]+[Enter] 또는 Right MouseButton On Form ->[Dialog Properties]: ID를 이용하여 대화상자와 소스코드 연결


컨트롤배치:     나이와 이름을 입력받는 대화상자 작성,

                layout 또는 RMouseButton On Menu->Dialog선택


탭순서: 컨트롤들의 포커스가 움직이는 순서

        Layout->Tab Order 또는 [ctrl]+[D] 탭 순서 조정


리소스 파일: *.rc, Resource.h = 리소스 정보 저장


(2) 대화상자와 컨트롤 관련 MFC클래스

대화상자 클래스: CDialog               -> 파생클래스 사용

컨트롤 클래스들: CEdit, CButton, etc.   -> 원본클래스 사용


(3) CDialog 클래스에 구현되어 있는 기능들

대화상자 화면에 출력단계:       

        모양디자인

        CDialog파생 클래스 생성: Form DoubleClick

        DoModal()함수 호출


재정의 가능한 함수: OnInitialDialog()=초기화 루틴

메시지 처리기: 윈도우와 동일

이벤트 처리기: CDialog클래스안에서 IDOK=OnOK(), IDCANCEL=OnCancel()


void CMyView::OnDialog()

{

        CMyDlg dlg;

        if(dlg.DoModal() == IDOK){

                

        }

}


Value형 멤버변수       : 값을 입력받는 기능

Control형 멤버변수     : 컨트롤을 제어 모양/기능을 조정


멤버변수와 컨트롤 연결  : ClassWizard->MemberVariables선택

                          또는 컨트롤위에서 [ctrl]+[Mouse DoubleClick]


-사람의 이름과 나이를 입력받아서 처리하는 다이얼로그 박스 테스트

void CMyView::OnTest()

{

        // TODO: Add your command handler code here

        CMyDialog dlg;

        CString   str;

        if(dlg.DoModal() == IDOK){

                MessageBox(dlg.m_strName,NULL,MB_OK);

                str.Format("%d",dlg.m_nAge);

                MessageBox(str,NULL,MB_OK);

        }


}


2. Value형 멤버 변수


컨트롤과 멤버변수 사이의 데이터 전송

void CMyDialog::DoDataExchange(CDataExchange* pDX)

{

        CDialog::DoDataExchange(pDX);

        //{{AFX_DATA_MAP(CMyDialog)

        DDX_Text(pDX, IDC_EDIT1, m_strName);

        DDX_Text(pDX, IDC_EDIT2, m_nAge);

        //}}AFX_DATA_MAP

}


UpdateData 함수를 이용한 데이터 전송

그림 4-14참조

        UpdateData(TRUE):    컨트롤 -> 변수

        UpdateData(FALSE):    변수 -> 컨트롤


기본적으로 호출되는 UpdateData 함수

시작할 때: OnInitDialog() 함수안에서 UpdateData(FALSE)호출

종료할 때: OnOk() 함수안에서 UpdateData(TRUE) 호출


입력된 값의 유효성 검사

ClassWizard에서 변수마다 유효한 값의 범위를 설정 가능

->설정된 범위가 DoDataExchange()함수에 표시


3. Control형 멤버 변수

컨트롤들이 모두 클래스로 구성->인스턴스를 선언해서 컨트롤의 멤버함수들을 활용할 수 있다.

목적:

  입력 시 사용자의 편의 도모: 주소 선택을 할 경우, ComboBox=시,구(군),동,나머지

  논리적으로 모순 되는 입력 방지: 신상입력을 할 경우, 남자: 병역,  여자: 비활성화


-본인과 배우자의 신상 입력: 기혼일 경우 배우자 신상 입력


(1) 대화상자 리소스 편집

그림 4-18참조, ID=IDD_PROFILE


(2) 파생클래스 생성: Form Double-Click

CProfileDlg


(3) 컨트롤과 Value형 변수 연결

표4-6참조

ClassWizard활용하여 연결



(4) 메뉴 리소스 편집

IDM_PROFILE  Caption:인적사항입력


(5) 이벤트 처리기 작성: ClassWizard사용-View클래스


void CProfileView::OnProfile()

{

  CProfileDlg dlg;

  if(dlg.DoModal() == IDOK)

  {

    CString str;

    if(dlg.m_bMarried)  // 기혼의 경우

    {

      str.Format("본인이름: %s, 나이: %d, \n배우자이름: %s, 나이: %d",

                dlg.m_strName1, dlg.m_nAge1, dlg.m_strName2, dlg.m_nAge2);

    }

    else                 // 미혼의 경우

    {

      str.Format("본인이름: %s, 나이: %d", dlg.m_strName1, dlg.m_nAge1);

    }

    AfxMessageBox(str);

  }

}


(6) 컨트롤과 Control형 멤버변수 연결: 기혼 체크박스가 체크되지 않으면 배우자 항목 비활성화

배우자 정보 관련 컨트롤들을 Control형 멤버변수 연결: 이름, 나이

ClassWizard에서 [Member Variabls]-[Add Variable]-[Category]항을 Control로 설정

변수 위에서 [ctrl]+mouse double-click: [Category]항을 Control로 설정


member variable name = 이름: m_ctrlName, 나이: m_ctrlAge


(7) 컨트롤 비활성화: EnableWindow()함수 활용

시작할 때는 배우자 입력은 비활성화 시켜야 함


BOOL CProfileDlg::OnInitDialog()

{

        CDialog::OnInitDialog();

        

        m_ctrlName.EnableWindow(FALSE);

        m_ctrlAge.EnableWindow(FALSE);

        

        return TRUE;  // return TRUE unless you set the focus to a control

                      // EXCEPTION: OCX Property Pages should return FALSE

}


Check Box가 클릭될 때 마다 활성화 또는 비활성화 필요: 대화상자의 컨트롤들이 동작에 대한 메시지를 발생시키는데 이를 검출해서 처리하는 함수를 생성


ClassWizard에서 Object IDs항에서 컨트롤 ID를 찾고 해당하는 메시지함수 추가

void CProfileDlg::OnCheck1()

{

        UpdateData(TRUE);

        

        m_ctrlName.EnableWindow(m_bMarried);

        m_ctrlAge.EnableWindow(m_bMarried);

}


m_bMarried: Check Box연동 변수=Bool변수

UpdateData(TRUE): 는 다이얼로그 박스에서 체크한 값을 m_bMarried에 넘겨주는 역할



- Control형 변수를 이용한 컨트롤 제어

Control형 멤버 변수와 관련 코드

class CProfileDlg

{

        CEdit m_ctrlName;

        CEdit m_ctrlAge;

}


void CProfileDlg::DoDataExchange(CDataExchange* pDX)

{


        DDX_Control(pDX, IDC_EDIT4, m_ctrlAge);

        DDX_Control(pDX, IDC_EDIT3, m_ctrlName);

}


컨트롤에 사용되는 중요 클래스들

CWnd: 기반 클래스

CEdit: CButton: CSpinButtonCtrl: CScrollBar: CListBox/CComboBox


대화상자와 컨트롤의 초기화: OnInitDialog()함수에서 수행 예) EnableWindow(컨트롤이 생성된 후 작동

변수의 초기화: 생성자 함수

동작 순서: 생성자 함수 호출 -> OnInitDialog()함수 호출


윈도우메시지: WM_                     = 컨트롤에 메시지 전송

통지(Notification) 메시지; xxN_         = 대화상자로 메시지 전송, 대화상자위의 모든 컨트롤의 파생 클래스를 만들지 않아도 됨


4. 능동적인 대화상자 만들기


-인터넷 쇼핑몰에서 물건을 구매하는 예제


(1) 뼈대만들기: SDI


(2) 메뉴 만들기

ID                       Caption

ID_LISTBOXDLG       : 물품 구입(&B)

ID_SPINDLG           : 수량(&Q)

ID_RADIODLG          : 결재 및 배송 방법(&D)

ID_COMBODLG         : 주소(&A)


(3) ListBox 컨트롤(IDD_LISTBOXDLG): 완쪽에서 더블 클릭을 하면 오른쪽으로 이동 반대도 가능(표 4-17참조)





(3-1) CListboxDlg라는 다이얼로그 박스 파생 클래스 생성


(3-2) 멤버변수 추가: Classwizard사용

        CListBox       m_ctrlRight;

        CListBox       m_ctrlLeft;

        CString         m_strLeft;

        CString         m_strRight;


(3-3) 컨트롤 초기화

BOOL CListboxDlg::OnInitDialog()

{

        CDialog::OnInitDialog();

        

        CString strProduct[] = {_T("CPU"), _T("Mainboard"), _T("Mouse"),

                _T("Keyboard"), _T("Case"), _T("Video card"), _T("Sound card"),

                _T("HDD"), _T("FDD"), _T("Modem"), _T("LAN card"), _T("DVD Rom")};


        for(int i=0 ; i<sizeof(strProduct)/sizeof(CString) ; i++)

                m_ctrlLeft.AddString(strProduct[i]);

        

        return TRUE;  // return TRUE unless you set the focus to a control

                      // EXCEPTION: OCX Property Pages should return FALSE

}


(3-4) LBN_DBLCLK이벤트 처리

Classwizard - [Object IDs]:IDC_LIST1, IDC_LIST2선택 - [Messages]:LBN_DBLCLK


void CListboxDlg::OnDblclkList1()

{

        int nSel = m_ctrlLeft.GetCurSel();

        if(nSel >= 0)

        {

                UpdateData(TRUE);


                m_ctrlLeft.DeleteString(nSel);

                m_ctrlRight.AddString(m_strLeft);

        }

}


void CListboxDlg::OnDblclkList2()

{

        int nSel = m_ctrlRight.GetCurSel();

        if(nSel >= 0)

        {

                UpdateData(TRUE);


                m_ctrlRight.DeleteString(nSel);

                m_ctrlLeft.AddString(m_strRight);

        }

}


(3-5) 대화 상자의 값 저장: Listbox에 연결된 변수에는 현재 선택한 값만 저장

원하는 결과는 오른쪽 Lisbox에 있는 모든 값들

변수 추가

CString m_strSelected


void CListboxDlg::OnOK()

{

        CString strItem;


        UpdateData(TRUE);

        m_strSelected.Empty();


        for(int i=0 ; i<m_ctrlRight.GetCount() ; i++)

        {

                m_ctrlRight.GetText(i, strItem);


                if(!m_strSelected.IsEmpty()) m_strSelected+= _T(", ");

                m_strSelected += strItem;

        }

        

        CDialog::OnOK();

}


(3-6) 대화 상자 출력: 화면에 표시

void CDialogExampleView::OnListboxdlg()

{

        CListboxDlg dlg;

        if(dlg.DoModal() == IDOK)

        {

                AfxMessageBox(dlg.m_strSelected);

        }

}


(4) ComboBox 컨트롤(그래픽 디자인)





(4-1) 콤보박스 속성지정

Combo박스의 화살표를 눌러서 펼침메뉴의 크기 조절 수행


(4-2) 클래스 추가 및 멤버변수 지정: CComboDlg

역할            ID                     Value형 변수        Control형 변수

시(도)          IDC_COMBO1          int m_nCity         CComboBox m_ctrlCity

구(군)          IDC_COMBO2          int m_nGu           CComboBox m_ctrlGu

동(면)          IDC_COMBO3          int m_nDong        CComboBox m_ctrlDong

나머지주소      IDC_EDIT1             CString m_strRest

전체주소        IDC_ADDRESS         m_strAddress


(4-3) 컨트롤 초기화

전역변수

static CString g_strCity[] = {"경기도", "서울특별시", "광주광역시"};


static CString g_strGu1[] = {"광명시", "안양시", "부곡시"};

static CString g_strGu2[] = {"구로구", "금천구", "강동구"};

static CString g_strGu3[] = {"광산구", "남구", "북구"};


static CString g_strDong1[] = {"철산동", "하안동", "개봉동"};

static CString g_strDong2[] = {"갈산동", "관양동", "귀인동"};

static CString g_strDong3[] = {"고잔동", "원곡동", "사사동"};


BOOL CComboDlg::OnInitDialog()

{

        CDialog::OnInitDialog();

        

        for(int i=0 ; i<3 ; i++)

                m_ctrlCity.AddString(g_strCity[i]);

        

        return TRUE;  // return TRUE unless you set the focus to a control

                      // EXCEPTION: OCX Property Pages should return FALSE

}

(4-4) 전체 주소 표시기능

void CComboDlg::ShowAddress()

{

        UpdateData(TRUE);

        

        CString strCity, strGu, strDong;

        if(m_nCity >= 0) m_ctrlCity.GetLBText(m_nCity, strCity);

        if(m_nGu >= 0) m_ctrlGu.GetLBText(m_nGu, strGu);

        if(m_nDong >= 0) m_ctrlDong.GetLBText(m_nDong, strDong);


        m_strAddress.Format("%s %s %s %s", strCity, strGu, strDong, m_strRest);

        UpdateData(FALSE);

}


(4-5) CBN_SELCHANGE 이벤트 처리

앞의 콤보박스가 변경이 되면 뒤에 있는 콤보박스의 내용을 따라서 변경

예)     시(도) 콤보박스에서 서울시 선택

        구(군) 콤보박스에서 서울시에 있는 구(군)만 표시


void CComboDlg::OnSelchangeCombo1()

{

        UpdateData();


        //구(군), 동(면) Combo Box 컨트롤 내용 모두 삭제

        m_ctrlGu.ResetContent();

        m_ctrlDong.ResetContent();


        CString *pGu;

        switch(m_nCity)

        {

                case 0: pGu = g_strGu1;       break;

                case 1: pGu = g_strGu2;       break;

                case 2: pGu = g_strGu3;       break;

        }


        for(int i=0 ; i<3 ; i++)

                m_ctrlGu.AddString(pGu[i]);

        

        ShowAddress();

}


void CComboDlg::OnSelchangeCombo2()

{

        UpdateData();


        // 동(면) Combo Box 컨트롤 내용 모두 삭제

        m_ctrlDong.ResetContent();


        CString *pDong;

        switch(m_nGu)

        {

                case 0: pDong = g_strDong1;  break;

                case 1: pDong = g_strDong2;  break;

                case 2: pDong = g_strDong3;  break;

        }


        for(int i=0 ; i<3 ; i++)

                m_ctrlDong.AddString(pDong[i]);


        ShowAddress();

}


void CComboDlg::OnSelchangeCombo3()

{

        ShowAddress();

}


(4-6) Edit 박스의 EN_CHANGE 이벤트 처리: 나머지 주소 변경

void CComboDlg::OnChangeEdit1()

{

        ShowAddress();

}


(4-7) 대화상자 출력

#include "ComboDlg.h"

void CDialogExampleView::OnCombodlg()

{

        CComboDlg dlg;

        if(dlg.DoModal() == IDOK)

        {

                AfxMessageBox(dlg.m_strAddress);

        }

}


(5) Spin 컨트롤(그래픽 디자인)





property설정:   Edit컨트롤이 Spin컨트롤 바로 앞에 오게 조정

                [Auto Buddy], [Set Buddy Integer], [Alignment]-[Right]


(5-1) 클래스 생성 멤버변수 추가: CSpinDlg

컨트롤          ID             Value형 멤버변수       Contorl형 멤버변수

Edit            IDC_EDIT1     int m_nAmount

Spin           IDC_SPIN1                             CSpinButtonCtrl m_ctrlSpin


(5-2) 컨트롤 초기화

BOOL CSpinDlg::OnInitDialog()

{

        CDialog::OnInitDialog();

        

        m_ctrlSpin.SetRange(0, 100);

        

        return TRUE;  // return TRUE unless you set the focus to a control

                      // EXCEPTION: OCX Property Pages should return FALSE

}


IDC_EDIT1의 범위도 동일하게 0 - 100으로 제한


(5-3) 대화 상자 출력

#include "SpinDlg.h"

void CDialogExampleView::OnSpindlg()

{

        CSpinDlg dlg;

        if(dlg.DoModal() == IDOK)

        {

                CString str;

                str.Format("주문수량: %d개", dlg.m_nAmount);

                AfxMessageBox(str);

        }

}


(6) Radio 버튼 컨트롤(그래픽 디자인)






step 1: [ctrl-D] 탭 순서 조절을 이용하여 Radio 버튼들을 순서대로 정리

step 2: Radio버튼들을 하나의 선택 집단으로 만들 때 첫 번째 버튼에 “Group“ 속성을 지정

step 3: “Group“ 속성 이 지정된 Radio버튼 컨트롤에 Value형 멤버 변수 연결, 이 변수는 그 범주내에 어떤 Radio버튼이 선택되었는가를 0부터 시작하는 숫자로 출력


(6-1) 클래스 생성 멤버변수 추가: CRadioDlg

ID                     Value형 멤버변수       

IDC_RADIO1           int m_nPayment

IDC_RADIO4           int m_nDelivery


(6-2) 대화 상자 출력

#include "RadioDlg.h"

void CDialogExampleView::OnRadiodlg()

{

        CRadioDlg dlg;

        if(dlg.DoModal() == IDOK)

        {

                CString str;

                str.Format("결재방법: %d\n배송방법: %d", dlg.m_nPayment, dlg.m_nDelivery);

                AfxMessageBox(str);

        }

}


'여러이야기 > IT' 카테고리의 다른 글

스마트 펜  (0) 2015.02.27
스마트 칠판(smart marker)  (0) 2015.02.25
[우분투] 10.04 APM 설치 및 셋팅  (0) 2015.02.23
[우분투] Zend Guard 설치  (0) 2015.02.23
[우분투] Zend Optimizer 설치  (0) 2015.02.23
Posted by TwoTen
l