소연의_개발일지
article thumbnail

프로젝트 이름은 mfcBitmapBtn으로 생성했다.

 

그림 리소스 추가 방법

 

1. 프로젝트 - 우클릭 - [리소스 추가]를 클릭한다.

2. 왼쪽에서 [Bitmap]을 클릭한 뒤 [새로 만들기]를 누른다.

3. 우측 하단 속성 탭에서 이름과 파일 이름을 변경해 준다.

같은 파일을 복사 - 붙여넣기 해서 Off 파일도 만들어 줬다.

저장된 파일을 확인해 보자.

상단의 [빌드] → [솔루션 빌드] 버튼을 누른 후 프로젝트 리소스 파일에 들어가면

 

경로상에서 리소스 파일이 이름대로 저장된 모습을 확인할 수 있다.

 


버튼 이미지 다운로드

 

이미지 출처

https://www.figma.com/community/file/1027548517256824848

 

Toggle Buttons 3D | Figma Community

Figma Community file - Hey! I would like to share my work on neumorphic 3D buttons. The project consists of components, each of which can be edited.

www.figma.com

여기서 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 

 

profile

소연의_개발일지

@ssoyxon

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!