단축키
ctrl + K + O → 헤더 파일로 이동
C++ 접근 지정자
C++에서 클래스나 구조체의 멤버에 대한 접근 지정자(access specifier)는 총 3가지이다: private, public, protected.
각 접근 지정자에 대한 설명은 다음과 같다.
1. private
- private으로 지정된 멤버는 해당 클래스 내에서만 접근이 가능하다.
- 외부에서 직접 접근하려고 하면 컴파일 에러가 발생한다.
- 기본적으로 클래스의 멤버들은 private으로 설정된다.
class MyClass {
private:
int myPrivateVar;
};
2. public
- public으로 지정된 멤버는 어디서든지 접근이 가능하다.
- 주로 클래스의 인터페이스로 사용되는 메서드들을 public으로 지정한다.
class MyClass {
public:
void myPublicMethod() {}
};
3. protected
- protected로 지정된 멤버는 해당 클래스와 파생된 클래스 내에서만 접근이 가능하다.
- private과 유사하지만, 상속을 받은 클래스에서도 접근이 가능하다는 차이점이 있다.
class BaseClass {
protected:
int myProtectedVar;
};
class DerivedClass : public BaseClass {
public:
void accessProtectedVar() {
myProtectedVar = 10; // 가능
}
};
이러한 접근 지정자들은 객체 지향 프로그래밍에서 캡슐화(encapsulation)의 원칙을 구현하기 위해 사용된다.
멤버 변수와 함수의 접근을 적절히 제한함으로써 클래스의 내부 동작을 보호하고 안정성을 유지하는 데 도움을 준다.
그림 그리기
mfcImage라는 프로젝트를 생성했다.
UI는 아래와 같은 식으로 제작했고, 우측 상단의 image 버튼의 ID는 IDC_BTN_IMAGE 이다.
mfcCImageDIg.h 파일 다이얼로그에 이미지 변수를 private로 생성한다.
// CmfcCImageDlg 대화 상자
class CmfcCImageDlg : public CDialogEx
{
// 외부에서 사용하지 않는다는 표시를 해줌 private
private:
CImage m_image;
다이얼로그 UI에서 우측 상단의 버튼 image를 더블클릭하여 클릭했을 때 발생할 이벤트 함수르 생성한다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
}
mfcCImageDIg.h 파일에서 버튼 클릭 이벤트 함수 밑에 삽입할 이미지 변수를 생성한다.
- nWidth, nHeight: 가로폭, 세로폭
- m_image.Create(가로, 세로, gray level): 가로폭과 세로폭, gray Level 에 맞춰 이미지 생성
- CClient DC dc(this): 클라이언트 형태의 변수를 dc라고 선언한 후 초기화를 this에 한다고 설정(this는 현재 다이얼로그)
- m_image.Draw(dc, 0, 0) : dc 객체의 0.0에 이미지를 그리겠다고 선언한다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
// 클래스에서 사용하는 변수(n이 붙는다)
// 멤버변수 지역변수
int nWidth = 640; // 가로폭
int nHeight = 480; // 세로폭
int nBpp = 8; // gray level
// 이미지 생성
m_image.Create(640, 480, 8);
// 이미지 그리기
CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)
}
코드를 실행시킨 후 버튼을 누르면 0.0 위치에 크기만큼 검은 화면이 나타난다.
위에서 설정한 변수를 사용하여 코드를 수정한다.
파라미터로 넘겨주는 값은 숫자를 쓰면 나중에 디버깅할때나 유지보수에 불편한다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
// 클래스에서 사용하는 변수(n이 붙는다)
// 멤버변수 지역변수
int nWidth = 640; // 가로폭
int nHeight = 480; // 세로폭
int nBpp = 8; // gray level
// 이미지 생성
m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
// 이미지 그리기
CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)
}
이 코드 내에 rgb값을 설정해준다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
// 클래스에서 사용하는 변수(n이 붙는다)
// 멤버변수 지역변수
int nWidth = 640; // 가로폭
int nHeight = 480; // 세로폭
int nBpp = 8; // gray level
// 이미지 생성
m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
// 조건 작성
// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.
if (nBpp == 8) {
static RGBQUAD rgb[256]; // RGBQUAD 구조체 타입의 배열인 'RGB'를 선언하고 초기화하는 코드
for (int i = 0; i < 25; i++) // 각각 RGB값 설정
rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
m_image.SetColorTable(0, 256, rgb);
}
// 이미지 그리기
CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)
}
이미지 색 변환하기
아래의 코드를 추가해 준다. 아래 코드는 각 픽셀마다 색을 할당해 주는 코드이다.
for (int j = 0; j < nHeight; j++) {
for (int i = 0; i < nWidth; i++) {
// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다.
// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
fm[j * nPitch + i] = 255;
}
}
전체 코드
- GetPitch() 함수
- 이미지의 픽셀 데이터가 메모리에서 연속적으로 배열되는 방식을 설명하기 위해 사용되는 값
- 이 값은 이미지의 한 줄(한 행)의 데이터가 메모리에서 차지하는 바이트 수를 나타냄
- 일반적으로 이미지 데이터는 행 단위로 연속적으로 저장되며, 각 행의 끝과 다음 행의 시작 사이에는 일정한 간격(패딩)이 있을 수 있음
- GetPich() 함수는 이러한 간격을 고려하여 이미지 데이터의 한 행이 메모리에서 차지하는 바이트 수를 반환한다. 이를 통해 이미지 데이터를 직접 다룰 때 각 픽셀의 위치를 올바르게 계산할 수 있다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
// 클래스에서 사용하는 변수(n이 붙는다)
// 멤버변수 지역변수
int nWidth = 640; // 가로폭
int nHeight = 480; // 세로폭
int nBpp = 8; // gray level
// 이미지 생성
m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
// 조건 작성
// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.
if (nBpp == 8) {
static RGBQUAD rgb[256];
for (int i = 0; i < 256; i++)
rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
m_image.SetColorTable(0, 256, rgb);
}
int nPitch = m_image.GetPitch();
unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.
for (int j = 0; j < nHeight; j++) {
for (int i = 0; i < nWidth; i++) {
// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다.
// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
fm[j * nPitch + i] = 255;
}
}
// 이미지 그리기
CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)
}
적용 사진
흰색 사각형이 0, 0 에 위치한다.
여기서 255 값을 j%255로 바꾸면 아래와 같이 그라데이션 모양이 나온다.
특정 위치에 원하는 색으로 점 찍기(각 숫자는 y축, x축에 위치하게 된다)
= 뒤에 원하는 색을 지정해 준다.
// 특정 위치에 원하는 색으로 점 찍기(y, x)
fm[12 * nPitch + 16] = 0;
fm[0*nPitch + 0] = 255;
사진 저장하기
<이미지 객체>.Save(_T("<사진경로>"));
// 이미지 저장하기
m_image.Save(_T("c:\\image\\save.bmp"));
전체 코드
void CmfcCImageDlg::OnBnClickedBtnImage()
{
// 클래스에서 사용하는 변수(n이 붙는다)
// 멤버변수 지역변수
int nWidth = 32; // 가로폭 픽셀
int nHeight = 24; // 세로폭 픽셀
int nBpp = 8; // gray level
// 이미지 생성
m_image.Create(nWidth, nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
// 조건 작성
// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.
if (nBpp == 8) {
static RGBQUAD rgb[256];
for (int i = 0; i < 256; i++)
rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
m_image.SetColorTable(0, 256, rgb);
}
int nPitch = m_image.GetPitch();
unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.
for (int j = 0; j < nHeight; j++) {
for (int i = 0; i < nWidth; i++) {
// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다.
// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
fm[j * nPitch + i] = (j*10)%255;
}
}
// 특정 위치에 원하는 색으로 점 찍기(x, y)
fm[12 * nPitch + 16] = 0;
fm[0*nPitch + 0] = 255;
// 이미지 그리기
CClientDC dc(this); // 클라이언트 형태의 변수를 dc로 만들고 초기화를 this로 하겠다. -> this는 현재 가지고 있는 다이얼로그를 의미함
m_image.Draw(dc, 0, 0); // 그리기 (어디에 그릴지, 위치를 x, y 축을 설정해 준다.)
// 이미지 저장하기
m_image.Save(_T("c:\\image\\save.bmp"));
저장한 사진을 보면 0, 0 위치에 흰색이, 가운데에 검은색 점이 찍혀있는걸 확인할 수 있다.
이 사진들은 가로로 나열되어 저장된다.(아래 사진 참조)
이미지 데이터가 메모리에 어떻게 배열되어 있는지 이해하기(nPitch)
이미지 데이터는 일반적으로 행 기반(row-based)으로 메모리에 저장된다. 그러나 각 행(row)이 꼭 연속적인 메모리 공간에 위치하는 것은 아니다. 대신 각 행의 시작과 다음 행의 시작 사이에 추가적인 메모리 공간(padding 또는 stride라고 부릅니다)이 존재할 수 있다.
이 때, nPitch는 다음과 같은 의미를 가진다.
1. 양수 값: 각 행의 시작과 다음 행의 시작 사이의 전체 바이트 수를 나타낸다. (픽셀 데이터 + 추가 메모리 공간)
2. 음수 값: 일부 구현에서는 이미지 데이터가 메모리에 상단에서 하단이 아닌, 하단에서 상단으로 저장되기 때문에 음수 값을 가질 수 있다.
따라서, j * nPitch는 j번째 행의 시작 주소를 나타낸다. 그리고 + i를 통해 그 행에서 i번째 픽셀에 접근한다.
for문에서 fm[j * nPitch + i] 를 사용하는 이유는, 이미지 데이터들이 아래와 같이 배열로 저장되기 때문이다.
memset 사용하기
아래 한 줄의 코드를
memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지
이 코드 대신 대체할 수 있다.
for (int j = 0; j < nHeight; j++) {
for (int i = 0; i < nWidth; i++) {
// 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다.
// 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
// nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
fm[j * nPitch + i] = (j*60)%255;
}
}
하지만 이미지 생성 부분에서 nHeight에 -(마이너스)를 붙여줘야 한다.
그 이유는 MFC의 CImage 클래스의 특별한 특성과 관련이 있다.
// 이미지 생성
m_image.Create(nWidth, -nHeight, nBpp);
CImage는 nHeight 값이 음수일 때와 양수일 때 이미지 데이터를 메모리에 다르게 저장한다.
1. nHeight가 양수일 때:
이미지 데이터는 일반적인 행 순서로 저장된다. 첫 번째 행이 메모리의 첫 번째 위치에 있고, 마지막 행이 마지막 위치에 있다. 하지만 이 경우에는 nPitch (stride 또는 간격) 때문에 각 행 간에 추가 메모리 공간이 있을 수 있다.
2. nHeight가 음수일 때:
이미지 데이터는 메모리에 역순으로 저장된다. 마지막 행이 메모리의 첫 번째 위치에 있고, 첫 번째 행이 마지막 위치에 있다. 이 방식은 BMP 이미지 형식과 같이 데이터가 기본적으로 역순으로 저장되는 경우에 유용하다.
memset(fm, 0xff, nWidth * nHeight); 코드는 모든 픽셀 값을 255(0xff)로 설정한다. 그러나 원래의 루프는 각 픽셀에 (j*60)%255 값을 할당하므로, 두 코드 사이에는 차이가 있다. memset은 모든 픽셀을 흰색으로 만들지만, 원래의 루프는 행에 따라 다양한 그레이스케일 값을 픽셀에 할당하게 된다.
이미지 저장 & 로드하기
// 전역변수로 선언
CString g_strFileImage = _T("c:\\image\\save.bmp");
void CmfcCImageDlg::OnBnClickedButton2()
{
// 이미지 저장하기
m_image.Save(g_strFileImage);
}
void CmfcCImageDlg::OnBnClickedButton3()
{
// 이미지가 없으면 제거
if (m_image != NULL) {
m_image.Destroy();
}
// 이미지 로드하기
m_image.Load(g_strFileImage);
CClientDC dc(this);
m_image.Draw(dc, 0, 0);
}
함수화 해보기
아래 부분이 반복되기 때문에 함수화를 하여 간단하게 해 보자.
CClientDC dc(this);
m_image.Draw(dc, 0, 0);
사각형 움직이게 하기
void CmfcCImageDlg::OnBnClickedBtnImage()
{
// 클래스에서 사용하는 변수(n이 붙는다)
// 멤버변수 지역변수
int nWidth = 640; // 가로폭 픽셀
int nHeight = 480; // 세로폭 픽셀
int nBpp = 8; // gray level
// 이미지 생성
m_image.Create(nWidth, -nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
BOOL vaildImgPos(int x, int y);
// 조건 작성
// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.
if (nBpp == 8) {
static RGBQUAD rgb[256];
for (int i = 0; i < 256; i++)
rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
m_image.SetColorTable(0, 256, rgb);
}
int nPitch = m_image.GetPitch();
unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.
memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지
//for (int j = 0; j < nHeight; j++) {
// for (int i = 0; i < nWidth; i++) {
// // 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다.
// // 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
// // nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
// fm[j * nPitch + i] = (j*60)%255;
//
// }
//}
// 이미지 그리기
UpdateDisplay(); // 이미지 업데이트 하는 함수 호출
}
// 전역변수로 선언
CString g_strFileImage = _T("c:\\image\\save.bmp");
void CmfcCImageDlg::OnBnClickedButton2()
{
// 이미지 저장하기
m_image.Save(g_strFileImage);
}
void CmfcCImageDlg::OnBnClickedButton3()
{
// 이미지가 없으면 제거
if (m_image != NULL) {
m_image.Destroy();
}
// 이미지 로드하기
m_image.Load(g_strFileImage);
UpdateDisplay();
}
// 이미지 업데이트 하는 함수 생성
void CmfcCImageDlg::UpdateDisplay()
{
CClientDC dc(this);
m_image.Draw(dc, 0, 0);
}
void CmfcCImageDlg::moveRect()
{
static int nSttX = 0;
static int nSttY = 0;
int nGray = 80;
int nWidth = m_image.GetWidth(); // 가로폭 픽셀
int nHeight = m_image.GetHeight(); // 세로폭 픽셀
unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
int nPitch = m_image.GetPitch();
memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지
for (int j = nSttY; j < nSttY + 48; j++) {
for (int i= nSttX;i < nSttX + 64;i++) {
if(vaildImgPos(i, j))
fm[j * nPitch + i] = nGray;
}
}
nSttX++;
nSttY++;
UpdateDisplay();
}
void CmfcCImageDlg::OnBnClickedBtnAction()
{
for (int i = 0;i < 640; i++) {
moveRect();
Sleep(1);
}
}
BOOL CmfcCImageDlg::vaildImgPos(int x, int y)
{
int nWidth = m_image.GetWidth(); // 가로폭 픽셀
int nHeight = m_image.GetHeight(); // 세로폭 픽셀
CRect rect(0, 0, nWidth, nHeight);
// 주어진 x, y 에 대해서 영역 안에 들어가면 그 값을 리턴해 준다.
return rect.PtInRect(CPoint(x, y)); // Cpoint값으로 바꿔 준다.
}
원 움직이게 하기
사각형을 움직이는 로직을 원으로 바꾸려면, 주어진 원의 중심(nSttX, nSttY)와 반지름(r) 을 이용하여 각 픽셀이 원 내부에 있는지 여부를 판단해야 한다.
원의 내부에 있는 픽셀을 회색으로 채우려면, 주어진 픽셀 (i, j)가 원의 중심(nSttX, nSttY)로부터 거리가 r보다 작거나 같은지 검사해야 한다.
코드에서 (dx*dx + dy*dy <= r*r) 부분이 원의 내부에 있는 픽셀을 확인하는 조건이다.(위의 공식 참고)
여기서 (i, j) 픽셀의 원점 (nSttX, nSttY)에 대한 상대적인 위치는 (dx, dy)이다.
void CmfcCImageDlg::OnBnClickedBtnImage()
{
// 클래스에서 사용하는 변수(n이 붙는다)
// 멤버변수 지역변수
int nWidth = 640; // 가로폭 픽셀
int nHeight = 480; // 세로폭 픽셀
int nBpp = 8; // gray level
// 이미지 생성
m_image.Create(nWidth, -nHeight, nBpp); // 모든 변수를 만들때는 파라마터 값에 숫자를 안 주는게 중요하다. -> 위에서 설정한 변수를 사용해 준다.
BOOL vaildImgPos(int x, int y);
// 조건 작성
// 흑백을 기준으로 display 하게 되어있기 때문에 컬러로 할려면 설정을 따로 해줘야 한다.
if (nBpp == 8) {
static RGBQUAD rgb[256];
for (int i = 0; i < 256; i++)
rgb[i].rgbRed = rgb[i].rgbGreen = rgb[i].rgbBlue = i;
m_image.SetColorTable(0, 256, rgb);
}
int nPitch = m_image.GetPitch();
unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
// fm은 이미지 데이터의 시작 포인터를 가리킨다. 이미지 데이터는 메모리에 연속적으로 배열된 행으로 구성된다.
// 각 행의 끝과 다음 행의 시작 사이에는 간격(nPitch)가 있을 수 있다.
memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지
//for (int j = 0; j < nHeight; j++) {
// for (int i = 0; i < nWidth; i++) {
// // 2d 이미지 좌표 (i, j)를 1D메모리 주소로 변환한다.
// // 255는 해당 픽셀의 값에 할당된다. 255를 할당하면 흰색으로 표시된다.
// // nBpp=8이 그레이스케일이미지므로 0(검은색) 부터 255(흰색)까지 값이 할당된다.
// fm[j * nPitch + i] = (j*60)%255;
//
// }
//}
// 이미지 그리기
UpdateDisplay(); // 이미지 업데이트 하는 함수 호출
}
// 전역변수로 선언
CString g_strFileImage = _T("c:\\image\\save.bmp");
void CmfcCImageDlg::OnBnClickedButton2()
{
// 이미지 저장하기
m_image.Save(g_strFileImage);
}
void CmfcCImageDlg::OnBnClickedButton3()
{
// 이미지가 없으면 제거
if (m_image != NULL) {
m_image.Destroy();
}
// 이미지 로드하기
m_image.Load(g_strFileImage);
UpdateDisplay();
}
// 이미지 업데이트 하는 함수 생성
void CmfcCImageDlg::UpdateDisplay()
{
CClientDC dc(this);
m_image.Draw(dc, 0, 0);
}
void CmfcCImageDlg::moveCircle()
{
static int nSttX = 0;
static int nSttY = 0;
int nGray = 80;
int nWidth = m_image.GetWidth(); // 가로폭 픽셀
int nHeight = m_image.GetHeight(); // 세로폭 픽셀
unsigned char* fm = (unsigned char*)m_image.GetBits(); // 내가 만든 이미지의 첫번째 포인터의 값을 가져오겠다.
int nPitch = m_image.GetPitch();
// 전체 이미지를 흰색으로 초기화한다.
memset(fm, 0xff, nWidth * nHeight); // 메모리를 어떠한 값으로 연결할 것인지
// 원의 반지름을 설정한다.
int r = 24;
for (int j = nSttY - r; j < nSttY + r; j++) {
for (int i = nSttX - r; i < nSttX + r; i++) {
int dx = i - nSttX;
int dy = j - nSttY;
if (vaildImgPos(i, j) && (dx * dx + dy * dy <= r * r)) {
// 픽셀이 이미지 내에 있고, 원의 내부에 있는 경우에만 그레이로 채웁니다.
fm[j * nPitch + i] = nGray;
}
}
}
nSttX++;
nSttY++;
UpdateDisplay();
}
void CmfcCImageDlg::OnBnClickedBtnAction()
{
for (int i = 0;i < 640; i++) {
moveCircle();
Sleep(1);
}
}
BOOL CmfcCImageDlg::vaildImgPos(int x, int y)
{
int nWidth = m_image.GetWidth(); // 가로폭 픽셀
int nHeight = m_image.GetHeight(); // 세로폭 픽셀
CRect rect(0, 0, nWidth, nHeight);
// 주어진 x, y 에 대해서 영역 안에 들어가면 그 값을 리턴해 준다.
return rect.PtInRect(CPoint(x, y)); // Cpoint값으로 바꿔 준다.
}
'개발공부 > C++' 카테고리의 다른 글
[C++] MFC 모달리스 다이얼로그 생성하기 (0) | 2023.09.18 |
---|---|
[C++] MFC Bitmap Image로 버튼 만들기, 클릭시 이미지 전환 (1) | 2023.09.17 |
[C++] MFC 버튼 생성, 에딧컨트롤 생성, 이벤트 연결, 계산기 만들기 (1) | 2023.09.16 |
[C++] MFC 콘솔창 띄우기, 특정 변수의 값 콘솔창 출력 (0) | 2023.09.16 |
[C++] MFC 개발환경 설정하기 (0) | 2023.09.15 |