출처 : 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++(메시지로 각 역할의 시작과 종료) | ||
인사 자리안내 주문접수 요리 요리서빙 계산 | 인사함수() 자리함수() 주문함수() 요리함수() 서빙함수() 계산함수() | 종업원 | 인사 자리안내 주문접수 요리서빙 |
요리사 | 요리 | ||
카운터 | 계산 |
- 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);
-------------------------------------------------------------------
펜 스타일
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);
레스터 오퍼레이션 코드 의미
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 |