티스토리 뷰
이번에 해볼 실습은 빈 화면에 왼쪽 마우스를 클릭하면 사각형이 만들어지는 것을 하려고 한다.
먼저 프로젝트 탭에서 클래스 마법사를 클릭해 왼쪽 마우스를 클릭시 어떠한 행위가 나타나는 소스를 추가해보자.
위와 같은 화면이 나오면서 클래스 이름이 반드시 뒤에 Dlg가 붙어야하고, 메시지 탭에서 WM_LBUTTONDOWN을 검색해 소스를 추가시키면 된다. 그러면 아래와 같은 소스가 추가된다.
첫번째 인자는 마우스 왼쪽 버튼을 눌렀을때, 조합키가 있는지 확인하는 변수이고, 두번째 변수는 클릭한 마우스의 좌표를 의미하는 변수이다.
API를 가지고 그리는 방법과 MFC를 이용하여 그리는 방법 2가지가 있다.
먼저 API에 대해서 설명하겠다. 윈도우에서 그리기를 하려면 해당 윈도우에서 사용할 수 있는 DC를 얻어와야 한다. API는 모든 것에 대한 핸들 값을 반환한다. 이때 DC의 핸들 값을 얻어오기 위해 HDC라는 타입의 변수를 선언하고, 특정 윈도우로부터 DC를 얻어오는 함수인 GetDC()를 입력한다. GetDC() 함수가 MFC에서도 동일하게 가지므로, 잘못 호출되는 경우를 막아주기 위해 :: Scope 연산자를 이용해준다. 어떤 윈도우로부터 DC를 얻는지 알수 있는 방법은 GetDC() 안에 윈도우 핸들이 들어오면 된다. 윈도우 핸들을 알 수 있는 방법은 현재 이 대화상자가 윈도우 클래스에서 상속받은 것이다. 윈도우 클래스는 자기가 관리하는 윈도우의 핸들을 멤버 변수로 가지고 있는데 이 변수 이름이 m_hWnd 이다. 따라서 이 변수를 GetDC()함수 안에 넣어주면 된다.
작업시 자원을 얻었으면 이를 해제하는 코드를 미리 짜둬는 것이 나중에 버그 생성을 막아준다. 그러므로 GetDC()함수를 더 이상 사용하지 않으면 ReleaseDC()를 입력해준다. 어느 윈도우에서 어떤 dc를 해제할 것인지 명시해줘야 한다. 여기서는 m_hWnd 윈도우의 h_dc를 해제해주기에 이 변수들을 ReleaseDC()안에 넣어주면 된다.
마우스가 클릭하는 곳을 중심으로 하는 사각형을 만드는 함수는 Rectangle()이란 함수이다.
Rectangle(HDC hdc, int left, int top, int right, int bottom) 순으로 들어가게 된다.
위의 그림이 완성된 코드이다. 그리고 아래가 실행하고 마우스 클릭시 나타나는 그림이다.
이제 MFC를 이용하여 사각형 그리기를 해보도록 하겠다. MFC는 DC를 관리하는 클래스가 여러가지가 있다.
지금 처럼 윈도우에서 타이틀바와 테두리를 클라이언트 구간이라한다. 이 클라이언트 구간에 그려지는 담당 DC가 따로 존재한다. 그 DC 클래스의 이름이 CClientDC이다. CClientDC dc(this) 라 선언하는데 여기서 this를 의미하는것은 클래스가 나중에 인스턴스가 되었을때, 그 실제 주소를 의미한다. 그러므로 this는 COmockDlg을 의미하게 된다. 그리고 이 함수는 나중에 해제도 같이 해주기 때문에 ReleaseDC()를 사용하지 않아도 된다.
위의 그림이 완성된 코드이다. 그리고 아래가 실행하고 마우스 클릭시 나타나는 그림이다.
이번에는 사각형의 색을 바꾸려고 한다. 윈도우에서 기본으로 사용되는 색은 검은색 테두리에 하얀색 배경이다. 이를 변경하려고 한다. MFC는 테두리, 배경색을 변경하기 해주는 함수들이 존재하는 CPen , CBrush이다. 이 두개를 이용하면 된다. 기본색에서 우리가 바꿀 색은 빨간색 테두리에 파란색 배경이다.
먼저 소스를 보자.
CPen my_pen(PS_SOLID, 1, RGB(255, 0, 0));
CPen *p_old_pen = dc.SelectObject(&my_pen);
CBrush my_brush(RGB(0, 0, 255));
CBrush *p_old_brush = dc.SelectObject(&my_brush);
dc.Rectangle(point.x - 15, point.y - 15, point.x + 15, point.y + 15);
dc.SelectObject(p_old_pen);
dc.SelectObject(p_old_brush);
하나씩 설명을 하도록 하겠다.
CPen my_pen(PS_SOLID, 1, RGB(255, 0, 0));
여기서 사용된 CPen 이라는 클래스가 테두리를 그려주는 역할을 한다. 그려지는 사각형의 선의 스타일, 두께, 색을 표현한다.
CPen *p_old_pen = dc.SelectObject(&my_pen);
새로운 펜을 지정하면 처음에 설정된 펜을 버리게 된다. 이때 마우스 왼쪽 버튼 클릭함수가 끝나게 되면, 새로운 펜은 지역변수이기 때문에 없어지게 된다. 문제는 여기서 원래 처음에 설정된 팬이 없기 때문에 프로그램이 버그를 생성하면서 죽게된다. 그렇기 때문에 예전에 사용하던 펜을 다시 설정해줘야 한다. 그렇기 때문에 옛 팬의 변수를 만들어 저장을 해준다.
CBrush my_brush(RGB(0, 0, 255));
CBrush라는 클래스는 사각형의 배경을 그리는 역할을 한다. 그려지는 사각형의 배경을 색을 의미한다.
CBrush *p_old_brush = dc.SelectObject(&my_brush);
위에서 설명한것과 동일하게 배경색 역시 처음걸 돌려줘야 하므로 똑같이 설정해준다.
dc.Rectangle(point.x - 15, point.y - 15, point.x + 15, point.y + 15);
사각형을 그리는 클래스
dc.SelectObject(p_old_pen);
사각형을 그리는 함수가 끝났기 때문에 예전 펜을 돌려줘야 한다.
dc.SelectObject(p_old_brush);
사각형을 그리는 함수가 끝났기 때문에 예전 붓을 돌려줘야 한다.
이제 오목을 만들어 보자.
// OmokDlg.h : 헤더 파일
//
#pragma once
// COmokDlg 대화 상자
class COmokDlg : public CDialogEx
{
// 생성입니다.
private:
char m_is_white = 0;
char m_dol[20][20] = { {0,} , };
public:
COmokDlg(CWnd* pParent = NULL); // 표준 생성자입니다.
// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_OMOK_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.
// 구현입니다.
protected:
HICON m_hIcon;
// 생성된 메시지 맵 함수
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};
// OmokDlg.cpp : 구현 파일
//
#include "stdafx.h"
#include "Omok.h"
#include "OmokDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// COmokDlg 대화 상자
COmokDlg::COmokDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_OMOK_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void COmokDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(COmokDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
// COmokDlg 메시지 처리기
BOOL COmokDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
// 프레임워크가 이 작업을 자동으로 수행합니다.
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.
// TODO: 여기에 추가 초기화 작업을 추가합니다.
return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}
// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
// 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는
// 프레임워크에서 이 작업을 자동으로 수행합니다.
void COmokDlg::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();
CPaintDC dc(this);
for (int y = 1; y <= 19; y++) {
for (int x = 1; x <= 19; x++) {
dc.Rectangle(x*30, y*30, x*30+31, y*30+31);
}
}
CBrush black_brush(RGB(0, 0, 0)), *p_old_brush;
for (int y = 1; y <= 20; y++) {
for (int x = 1; x <= 20; x++) {
if (m_dol[y - 1][x - 1] > 0) {
if (m_dol[y - 1][x - 1] == 1) {
p_old_brush = dc.SelectObject(&black_brush);
}
dc.Ellipse(x * 30 - 15, y * 30 - 15, x * 30 + 15, y * 30 + 15);
if (m_dol[y - 1][x - 1] == 1) {
dc.SelectObject(p_old_brush);
}
}
}
}
}
}
// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
// 이 함수를 호출합니다.
HCURSOR COmokDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void COmokDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
CClientDC dc(this);
CBrush black_brush(RGB(0, 0, 0));
CBrush *p_old_brush;
int x = (point.x+15) / 30, y = (point.y+15) / 30;
if (x > 0 && y > 0 && x <= 20 && y <= 20 && m_dol[y-1][x-1] == 0) { //바둑판의 크기 및 돌의 놓여져 있는지에 대한 여부
m_dol[y][x] = m_is_white + 1;
x = x * 30;
y = y * 30; // 중간값이 없어진다.
if (m_is_white == 1) {
p_old_brush = dc.SelectObject(&black_brush);
}
dc.Ellipse(x - 15, y - 15, x + 15, y + 15);
if (m_is_white == 1) dc.SelectObject(p_old_brush);
m_is_white = (m_is_white + 1) % 2;
}
CDialogEx::OnLButtonDown(nFlags, point);
}
'TIPS' 카테고리의 다른 글
[TIPS 프로그래밍 강좌] 13차시 정리 (1) (0) | 2017.02.17 |
---|---|
[TIPS 프로그래밍 강좌] 12차시 정리 (0) | 2017.02.16 |
[TIPS 프로그래밍 강좌] 10차시 정리 (0) | 2017.02.08 |
[TIPS 프로그래밍 강좌] 9차시 정리 (0) | 2017.02.06 |
[TIPS 프로그래밍 강좌] 8차시 정리 (0) | 2017.01.31 |
- Total
- Today
- Yesterday
- 와이어샤크
- CBrush
- 오일러
- 화투이미지맞추기
- Tips
- tipsoft
- 키보드 메시지 이벤트
- 오일러 프로젝트 14번
- 비손실 압축
- 이미지게임
- MFC
- 오일러 프로젝트 12번
- 오일러 프로젝트 16번
- 서버
- 2의 1000승
- 약수 500개
- 팁스강좌
- 허프만 알고리즘
- 패킷
- tipsr강좌
- tipssoft
- 실행 압축
- 오일러 프로젝트 10본
- 오일러 프로젝트 13
- 오일러 프로젝트 11번
- 오일러 프로젝트 8번
- Omok
- arp
- TIPS강좌
- 헤더
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |