이미지 오버레이로 그림 그리기
메모리 릭 제거하기
메모리 릭을 막기 위해 새로 생성한 m_pDlgImgResult 에 대해서도 생성 후 삭제를 해 준다.
안전하게 존재하는지 if문을 걸어 작성해 준다.
// 메모리 릭을 막기 위해 생성된
void CgPrjDlg::OnDestroy()
{
CDialogEx::OnDestroy();
if(m_pDlgImage) delete m_pDlgImage;
if(m_pDlgImgResult) delete m_pDlgImgResult;
}
타원 그리기
자식 다이얼로그에 타원을 그리는 코드를 만들어 볼 것이다.
먼저 헤더 폴더에 함수를 drawData를 정의해 주고
선언만 해 줬으니 cpp 파일에서 정의를 해 준다.
CDlgImage 클래스 안에 있어야 하니 CDlgImage:: 를 함수 앞에 붙여 준다.
CRect rect(0, 0, 100, 100) 은 0, 0 위치에 100 * 100 사각형을 그린다는 뜻이다.
이 rect 변수를 Ellipse 메서드의 파라미터로 넣고 원을 그린다.
datwData 함수는 OnPaint() 함수 안에 넣어 준다.
void CDlgImage::datwData(CDC* pDC)
{
CRect rect(0, 0, 100, 100);
pDC->Ellipse(rect);
}
이 다이얼로그 이미지 클래스는 두번 호출되므로(왼쪽, 오른쪽)
코드를 실행시키면 원 2개가 각각 다이얼로그의 (0, 0) 자리에 위치한 것을 볼 수 있다.
여기서 rect 변수의 뒤의 두 값을 변환하면 그 값 안에 꽉 찬 원이 그려진다.
예를 들어 CRect rect(0, 0, 100, 100);
이렇게 값을 지정하면 각 다이얼로그만다 꽉 찬 원의 모습을 볼 수 있다.
왼쪽에서 오른쪽으로 값 넘겨주기
정보들을 헤더에 먼저 선언 해 준다.
int m_nDataCount = 0; // 몇개를 그릴 것인지
CPoint m_ptData[100]; // 배열(좌표값)
그리고 기존의 drawData 함수를 수정한다
m_nDataCount 값을 0으로 설정해 줬으므로 이 함수는 실행되지 않는다.
void CDlgImage::datwData(CDC* pDC)
{
CRect rect;
for (int i = 0; i < m_nDataCount; i++) {
rect.SetRect(m_ptData[i], m_ptData[i]); // 좌표값 설정
rect.InflateRect(5, 10); // 좌로 5만큼, 우로 10만큼 벌린다
pDC->Ellipse(rect); //원을 그린다
}
}
gPrjDlg.cpp 코드에서 test 버튼을 클릭했을 때 코드를 수정한다.
영상이 이해가 빨리 안 되서 주석을 자세히 달았다.
void CgPrjDlg::OnBnClickedBtnTest()
{
// 이미지 가져오기
// 화살표(->)는 포인터, 점(.)은 클래스를 의미
unsigned char* fm = (unsigned char*)m_pDlgImage->m_image.GetBits(); // 리턴값을 unsigned cha로 받는다는 뜻
// 가로 세로 피치 값 가져오기
int nWidth = m_pDlgImage->m_image.GetWidth(); // 가로
int nHeight = m_pDlgImage->m_image.GetHeight(); // 세로
int nPitch = m_pDlgImage->m_image.GetPitch(); // 픽셀마다 행 간격을 나타내는 값
// 값 리셋
memset(fm, 0xff, nWidth * nHeight);
// 점찍기
for (int k = 0; k < 100; k++) {
int x = rand() % nWidth;
int y = rand() % nHeight;
fm[y * nPitch + x] = 0;
}
// 인덱스 값 변수 선언(초기값 0)
int nIndex = 0;
// 찍힌 점의 좌표를 m_ptData 배열에 저장
// 모든 픽셀을 탐지하기 위한 이중 for문: 너비만큼, 높이만큼 반복: (i, j)는 픽셀의 (x, y)에 해당
for (int j = 0; j < nHeight;j++) {
for (int i = 0; i < nWidth; i++) {
if (fm[j * nPitch + i] == 0) { // 좌표의 픽셀 값이 0인지(점이 찍혀 있는지) 확인
// 찍힌 점을 찾았다면, 그 점의 좌표를 m_ptData 배열에 저장함
if (m_pDlgImgResult->m_nDataCount <= 100) { // 먼저 m_nDataCount가 100 이하인지 확인(배열의 크기가 100이므로)
m_pDlgImgResult->m_ptData[nIndex].x = i; // 찾은 점의 x 좌표를 배열에 저장
m_pDlgImgResult->m_ptData[nIndex].y = j; // 찾은 점의 y 좌표를 배열에 저장
// m_nDataCount 값을 1씩 증가시키며, 동시에 nIndex값을 1 증가시킨다. (++nIndex의 결과는 nIndex 증가 후의 값이므로)
m_pDlgImgResult->m_nDataCount = ++nIndex;
}
}
}
}
// 이미지 잘 가져왔는지 테스트
// 뒤의 숫자는 얼만큼 칠할것인지
// memset(fm, 0, 640 * 480); // 메모리셋에 fm(이미지포인터), 뒤에오는 것은 값:
// 화면에 업데이트
m_pDlgImage->Invalidate(); // 왼쪽 화면 업데이트
m_pDlgImgResult->Invalidate(); // 오른쪽 화면 업데이트
}
그리고 코드를 실행하면 Test 버튼을 클릭할 때마다 왼쪽에 찍힌 랜덤값에 따라 오른쪽에 원이 생성된다.
CPen Class로 색 변경, 굵기 바꾸기
void CDlgImage::datwData(CDC* pDC)
{
CRect rect;
CPen pen; // 선 객체 생성
pen.CreatePen(PS_SOLID, 1, RGB(0xff, 0, 0)); // 실선, 두께, 빨간색
CPen* pOldPen = pDC->SelectObject(&pen); // 현재 펜 저장
for (int i = 0; i < m_nDataCount; i++) {
rect.SetRect(m_ptData[i], m_ptData[i]); // 좌표값 설정
rect.InflateRect(5, 10); // 좌로 5만큼, 우로 10만큼 벌린다
pDC->Ellipse(rect); //원을 그린다
}
pDC->SelectObject(pOldPen); // 저장해 둔 펜 가져오기
}
'개발공부 > C++' 카테고리의 다른 글
[C++] <chrono> 헤더 사용하여 함수 실행시간 측정 (0) | 2023.09.19 |
---|---|
[C++] 여러 조건 변경하기, Cpen 색 변경, define (0) | 2023.09.19 |
[C++] MFC 듀얼이미지 다이얼로그 (0) | 2023.09.18 |
[C++] MFC 모달리스 다이얼로그 생성하기 (0) | 2023.09.18 |
[C++] MFC Bitmap Image로 버튼 만들기, 클릭시 이미지 전환 (1) | 2023.09.17 |