프로젝트 이름은 mfcBitmapBtn으로 생성했다.
그림 리소스 추가 방법
1. 프로젝트 - 우클릭 - [리소스 추가]를 클릭한다.
2. 왼쪽에서 [Bitmap]을 클릭한 뒤 [새로 만들기]를 누른다.
3. 우측 하단 속성 탭에서 이름과 파일 이름을 변경해 준다.
같은 파일을 복사 - 붙여넣기 해서 Off 파일도 만들어 줬다.
저장된 파일을 확인해 보자.
상단의 [빌드] → [솔루션 빌드] 버튼을 누른 후 프로젝트 리소스 파일에 들어가면
경로상에서 리소스 파일이 이름대로 저장된 모습을 확인할 수 있다.
버튼 이미지 다운로드
이미지 출처
https://www.figma.com/community/file/1027548517256824848
여기서 on/off 이미지를 다운받았다.
다운로드 방법은 자신의 피그마 계정에서 이 프로젝트를 연 후
버튼 클릭 - 우측 하단에 있는 [Export]를 선택하면 된다.
PNG → BMP 파일 변환
이 사진은 png 파일 형식으로 저장되는데,
mfc에서는 비트맵 파일 형식으로 파일을 사용하기 때문에 형식을 변환해줘야 한다.
다른이름으로 저장 - 프로젝트 폴더 밑의 리소스 파일 - [bitmap 형식]을 눌러 저장해 준다.
[확인!!] 24비트 비트맵 << 으로 해야 사진이 정상적으로 저장된다!!
그리고 프로젝트에 들어가면 이미지가 나온다. 256비트로 했다가 무슨 추상화 그림인 줄. 24비트로 바꾼 후 빌드하니 다시 정상적으로 사진이 나왔다.
다이얼로그에 버튼 하나 만들어주고
ID도 변경해 준다.
그리고 [속성] - [동작] - [소유자그리기]을 True로 변경해 준다.
사용자의 그림을 사용하겠다는 의미이다.
코드에서 수정하기
Ctrl + K + O 단축키로 헤더로 이동한다.
CBitmapButton를 사용하여 버튼 변수를 생성해 준다.
CBitmapButton는 MFC 라이브러리에서 제공하는 컨트롤로, 표준 버튼 대신 사용자 정의 이미지를 가진 버튼을 만들 수 있다.
// 버튼 선언해주기
CBitmapButton* m_pBtnOnOff;
여기서는 메모리 주소값만 만든 거지, 할당하지는 않느다.
다이얼로그 init 초기화 부분에서 메모리 할당 부분을 작성해 준다.
// TODO: 여기에 추가 초기화 작업을 추가합니다.
CRect rect(0, 0, 100, 50); // (x, y) 위치와 (가로, 세로) 폭을 지정
GetDlgItem(IDC_BTN_ON_OFF)->GetWindowRect(&rect); // 버튼의 위치를 가져온다.
// GetDlgItem(IDC_BTN_ON_OFF)->GetClientRect(&rect);
m_pBtnOnOff = new CBitmapButton; // m_pBtnOnOff라는 포인터에 CBitmapButton을 동작으로 생성하고 할당한다.
m_pBtnOnOff->Create(NULL, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, rect, this, IDC_BTN_ON_OFF); // 버튼에 해당된 속성 지정
m_pBtnOnOff->LoadBitmaps(IDB_ON, IDB_OFF); // 디폴트, 셀렉트, 포커스, 사용하지 않을 때 이미지를 로드할 수 있다.
m_pBtnOnOff->SizeToContent(); //크기에 맞게 사이즈 조정
- CRect rect(0, 0, 100, 50);
CRect는 MFC에서 사각형의 위치와 크기를 표현하는 클래스이다. 여기서 생성된 rect 객체는 왼쪽 상단 모서리가 (0,0)이고, 폭이 100, 높이가 50인 사각형을 표현한다. - m_pBtnOnOff = new CBitmapButton;
m_pBtnOnOff라는 포인터에 CBitmapButton의 인스턴스를 동적으로 생성하고 할당한다. - m_pBtnOnOff->Create(NULL, WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, rect, this, IDC_BTN_ON_OFF);
Create 함수를 호출하여 CBitmapButton 컨트롤을 생성하고 초기화한다.- 첫 번째 인자: 버튼에 표시될 텍스트이다. 여기서는 NULL로 설정되어 텍스트가 없다.
- 두 번째 인자: 버튼 스타일을 지정하는 플래그들이다.
- WS_CHILD: 부모 윈도우에 종속되는 자식 윈도우임을 나타낸다.
- WS_VISIBLE: 윈도우가 생성된 후에 바로 표시된다.
- BS_OWNERDRAW: 사용자가 버튼의 그리기를 직접 처리하겠다는 것을 나타낸다.
- 세 번째 인자: 버튼의 위치와 크기를 나타내는 rect이다.
- 네 번째 인자: 버튼의 부모 윈도우를 나타낸다.
- 다섯 번째 인자: 버튼의 컨트롤 ID. 이를 통해 이후 이벤트 처리 등에서 버튼을 구분할 수 있다.
- m_pBtnOnOff->LoadBitmaps(IDB_ON);
LoadBitmaps 함수를 사용하여 버튼에 표시될 비트맵 이미지를 로드한다. IDB_ON은 리소스에서 정의된 비트맵의 ID이다. - m_pBtnOnOff->SizeToContent();
SizeToContent 함수를 호출하여 버튼의 크기를 현재 로드된 비트맵의 크기에 맞게 조정한다. 이를 통해 이미지에 딱 맞는 버튼 크기를 얻을 수 있다.
코드를 실행하면 0, 0 위치에 100, 50 크기만큼 ON 이미지가 나타난다.
버튼의 위치를 변경시킬 때마다 사진도 변경되게 하기
GetDlgItem(IDC_BTN_ON_OFF)->GetWindowRect(&rect); // 버튼의 위치를 가져온다.
이미지는 기본값, 선택했을 때 값, hover했을 때 값, 사용하지 않을 때 값
이렇게 총 4가지의 사진을 보여줄 수 있다.
m_pBtnOnOff->LoadBitmaps(IDB_ON, IDB_OFF); // 디폴트, 셀렉트, 포커스, 사용하지 않을 때 이미지를 로드할 수 있다.
현재는 클릭했을 때 버튼이 이동하는 것만 보여진다.
배경화면 만들기
피그마에서 비슷한 이미지로 생성하고 png 파일로 export 한 파일을 리소스 파일에 저장해 두었다.
프로젝트 우클릭 - [추가] - [리소스] 선택
[가져오기] 버튼 선택 → 배경 이미지.png 선택하여 가져온다.
가져와진 배경 리소스 파일
[프로젝트] - [클래스 마법사] 선택
클래스 마법사에서 해당 프로젝트 - 클래스 이름은 해당 다이얼로그 창
메세지는 배경을 지워주는 WM_ERASEBKGND
처리기 추가 를 클릭한다.
그럼 해당 함수가 생성되고
그리고 생성된 함수 내에 아래와 같은 코드를 작성해 준다.
// 다이얼로그 박스의 배경을 특정 png로 채우기
BOOL CmfcBitmapBtnDlg::OnEraseBkgnd(CDC* pDC)
{
CPngImage image; // 이미지 객체 생성
image.Load(IDB_BASE, nullptr); // 설정한 id 값을 통해 이미지를 가져옴
CDC dc; // pDC와 호환되는 메모리 DC를 생성
dc.CreateCompatibleDC(pDC);
CBitmap* pOldBitmap = dc.SelectObject(&image);
pDC->BitBlt(0, 0, 640, 480, &dc, 0, 0, SRCCOPY); // dc에서 pDC로 비트맵의 내용을 복사하는 데 사용됨
dc.SelectObject(pOldBitmap); // 메모리 DC에서 원래의 비트맵 객체를 다시 선택함.
return TRUE;
return CDialogEx::OnEraseBkgnd(pDC);
}
- CPngImage image;
CPngImage는 MFC에서 PNG 이미지를 로드하고 처리할 수 있게 해주는 클래스이다. 이 코드에서는 image라는 객체를 생성하였다. - image.Load(IDB_BASE, nullptr);
Load 함수를 사용하여 리소스에서 PNG 이미지를 로드한다. IDB_BASE는 리소스에서 정의된 PNG 이미지의 ID이다. - CDC dc;
CDC는 MFC에서 Device Context (DC)를 나타내는 클래스이다. DC는 그리기 연산을 위한 다양한 설정과 정보를 담고 있는 그래픽 객체이다. 여기에서는 dc라는 임시 DC 객체를 생성한다. - dc.CreateCompatibleDC(pDC);
pDC와 호환되는 메모리 DC를 생성한다. 메모리 DC는 메모리에 그래픽 내용을 그릴 수 있게 해준다. - CBitmap* pOldBitmap = dc.SelectObject(&image);
SelectObject 함수를 사용하여 image를 메모리 DC에 선택한다. 이 함수는 이전에 선택되어 있던 객체의 포인터를 반환한다. 이 포인터는 후에 원래의 객체를 다시 선택하기 위해 사용된다. - pDC->BitBlt(0, 0, 640, 480, &dc, 0, 0, SRCCOPY);
BitBlt 함수는 dc에서 pDC로 비트맵의 내용을 복사하는 데 사용된다. 여기서는 (0,0) 위치에서 시작하여 가로 640, 세로 480의 크기로 이미지를 복사합니다. SRCCOPY는 복사 연산의 방식을 나타낸다. - dc.SelectObject(pOldBitmap);
메모리 DC에서 원래의 비트맵 객체를 다시 선택한다. 이렇게 함으로써 image 객체와의 연결을 끊어준다. - return TRUE;
배경을 지우는 작업이 성공적으로 완료되었음을 나타내기 위해 TRUE를 반환한다. 이 반환 값으로 인해 기본 OnEraseBkgnd 함수가 호출되지 않게 된다. - return CDialogEx::OnEraseBkgnd(pDC);
이 줄은 실제로 실행되지 않는 코드이다 왜냐하면 이전 줄에서 이미 return TRUE;로 함수가 종료되었기 때문. 이 코드는 일반적으로 배경 지우기 동작의 기본 구현을 호출하는 데 사용된다.
코드 실행 결과
그리고 메모리 누수가 발생하지 않게 프로젝트-마법사에서 위의 방식과 동일하게 Destory 를 클릭하여 아래 코드를 작성해 준다.
// 메모리 누수가 발생하지 않게 버튼 생성을 처리해줌
void CmfcBitmapBtnDlg::OnDestroy()
{
CDialogEx::OnDestroy();
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
if (m_pBtnOnOff) delete m_pBtnOnOff;
}
버튼 클릭시 버튼 눌리게 하기
UI에서 버튼을 더블클릭해서 하단의 코드를 작성한다.
버튼이 눌렸을 때 bOn의 bool값을 확인하여 버튼의 기본값을 설정해주는 코드이다.
void CmfcBitmapBtnDlg::OnBnClickedBtnOnOff()
{
static bool bOn = false;
if (bOn) {
m_pBtnOnOff->LoadBitmaps(IDB_ON);
}
else {
m_pBtnOnOff->LoadBitmaps(IDB_OFF);
}
bOn = !bOn;
}
코드 실행 결과
참고 링크
https://youtu.be/eeDIyKPCA0M?list=PLlIX4lkC1JdMx-vfK8I-J3-L-GL7TbMf9
'개발공부 > C++' 카테고리의 다른 글
[C++] MFC 듀얼이미지 다이얼로그 (0) | 2023.09.18 |
---|---|
[C++] MFC 모달리스 다이얼로그 생성하기 (0) | 2023.09.18 |
[C++] MFC CImage 이미지 생성, 저장, 로드, 움직이는 사각형 만들기 (0) | 2023.09.17 |
[C++] MFC 버튼 생성, 에딧컨트롤 생성, 이벤트 연결, 계산기 만들기 (1) | 2023.09.16 |
[C++] MFC 콘솔창 띄우기, 특정 변수의 값 콘솔창 출력 (0) | 2023.09.16 |