MFC 버전이 업그레이드 되면서, 예전 방법을 찾아서 프레임 배경에 이미지를 깔아보려고 했으나 구조가 변경되었는지 안먹네요. 지금 MSVS 2017로 작업 중 입니다...

아주 간단하게 작성해서 바로 써먹을 수 있는 예제를 하나 올립니다.


새로운 MFC 프로젝트를 생성합니다.


MDI 기본 구성으로 설정하고, Finish~


배경으로 사용할 이미지 입니다.


프로젝트 리소스에 이미지를 추가합니다. 이름은 IDB_BITMAP_BACK 으로 하였습니다.


CMainFrame 에 변수를 하나 선언합니다.

CBitmap m_bmp;


그리고, CMainFrame 의 OnCreate 에 코드를 한 줄 추가합니다. 

m_bmp.LoadBitmap(IDB_BITMAP_BACK);

CMainFrame 에 WM_PAINT 이벤트 핸들러를 추가하고, 아래와 같이 코드를 작성합니다.

void CMainFrame::OnPaint()
{
    CPaintDC dc(this);

    if (m_bmp.m_hObject)
    {
        BITMAP bm;
        CDC dcMem;

        CDC* pDC = m_wndClientArea.GetDC();
        VERIFY(m_bmp.GetObject(sizeof(bm), (LPVOID)&bm));

        dcMem.CreateCompatibleDC(pDC);
        CBitmap* pOldBMP = (CBitmap*)dcMem.SelectObject(&m_bmp);

        CRect rect;
        m_wndClientArea.GetClientRect(rect);

        pDC->FillSolidRect(rect, RGB(128, 128, 128));

        pDC->BitBlt((rect.right - bm.bmWidth) / 2,   // centered
            (rect.bottom - bm.bmHeight) / 2,
            bm.bmWidth,
            bm.bmHeight,
            &dcMem,
            0, 0,
            SRCCOPY);

        dcMem.SelectObject(pOldBMP);

        ::ReleaseDC(m_wndClientArea.m_hWnd, pDC->m_hDC);
    }
}


마지막으로 아래처럼 메인프레임 화면이 갱신될 때 MFC 내부에 정의된 배경을 관리하는 클라이언트도 함께 갱신하는 코드를 한 줄 넣어줍니다.

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->message == WM_PAINT)
    {
        if (pMsg->hwnd == m_hWndMDIClient)
            Invalidate();
    }
    ...

    return CMDIFrameWndEx::PreTranslateMessage(pMsg);
}


이제 실행해 보시면, MDI 에서 차일드 창이 하나도 없는 상태일 때 아래 그림처럼 배경에 이미지가 깔립니다.











Picture 컨트롤에 이미지를 넣는 것은 쉬운일이다.
컨트롤 자체가 그러하도록 설계되었기 때문이지만, 이 또한 글자를 제대로 표현할 수 없다.
그렇다면 이미지에 글자를 그려 넣을 것인가?

기존에 Text 의 배경을 투명하게 하고, 색상을 넣을 수 있다면 이미지도 넣을 수 있지 않을까?
답은 그렇다이다.

MFC에서 제공해주는 많은 객체중에 CBrush는 상당히 잘 꾸며진 객체이다.
그중에 관심을 가져볼만한것이 Hatch와 Partten 기능이다.
해치는 제공해준 패턴만을 그려주지만, 패턴기능은 사용자가 비트맵을 제공함으로써
배경을 원하는 형태로 그릴 수 있도록 해준다.

아래는 비주얼 스튜디오에서 리소스 편집창의 일부를 캡쳐한 화면이다.

저 배경에 아래의 그림을 깔아보자 ^^;

어디서 많이본 그림인데??
윈도우즈에서 기본으로 제공해주는 커피잔.bmp이다 저걸 컨트롤의 배경으로 사용할 것이다.

아래의 그림은 그걸 구현해 놓은 실행화면이다.

위의 그림은 Text 컨트롤(스태틱에서 문자열만을 제공하도록 특화됨)의 배경에 비트맵을 패턴으로
깔은 것이다.
하나의 그림을 전체 배경으로 넣으려면 그림 크기를 컨트롤 크기와 동일하게 맞추면 된다.

지금까지 스태틱 컨트롤 강좌를 살펴보면 저 기능을 구현하는 것은 아주 쉽다.
1. CBitmap 객체를 선언한 후 커피잔.bmp를 로딩한다.
2. CBrush 객체를 선언한 후 패턴브러쉬로 생성하고 저 비트맵을 설정해준다.
3. 기존의 강좌에서 나온 배경에 색칠하기 기능을 이용하여 그 브러쉬를 리턴해준다.
끝~

BOOL CSssDlg::OnInitDialog() 
{
    CDialog::OnInitDialog();
    
    bm.LoadBitmap(IDB_BITMAP3);
    brh.CreatePatternBrush(&bm);
    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}

HBRUSH CSssDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
    
    switch(nCtlColor)
    {
    case CTLCOLOR_STATIC:
        {
            pDC->SetTextColor(RGB(255, 255, 0));
            pDC->SetBkMode(TRANSPARENT);
            return brh;
        }
    }
    return hbr;
}

저 형태로 모든 코드가 마무리되었다.
지금까지 스태틱 컨트롤에 대한 기본적인 내용을 다루었으며, 저러한 기능을 모아
클래스로 생성해 둔다면 나중에 편하게 사용할 수 있을 것이다.
이것이 바로 C로는 가져보기 힘든, C++만의 장점이다.

리소스 편집창에는
그룹박스,  버튼이 다음 순서로 나오지만..
MFC를 다루는 대부분의 서적에서 다루는 내용만으로 사용에 전혀 무리가 없을 것이다.

그룹박스 투명화는 지금까지의 방법을 사용하면 테두리 사각형에 어색하게 찍힌 글자가 나오고
버튼 자체는 상속받아 이러저러한 기능을 구현하지 않으면 부모윈도우에서 처리해줄 일이 거의 없다.

다음으로는 버튼의 기능중에 특화된 첵크박스와 라디오 버튼을 함께 다루어 보겠습니다.
첵크 박스와 라디오 버튼도 CButton의 일부이지만 특화된 만큼 따로 다룰 것입니다.
즐거운 주말 되세요. ^^;

65.zip
0.09MB

스태틱 컨트롤을 이미지 형태로 사용할 경우 보통은 리소스에 있는 이미지를 연결시킨다.


왼쪽은 리소스 편집기에서 정적으로 이미지를 연결시킨 픽처 컨트롤이고,
오른쪽은 속성을 비트맵으로 설정해 놓고, 아무런 작업도 진행하지 않은 경우이다.

그렇다면 파일에서 비트맵을 로딩하여 필요할 때마다 바꾸려면 어떤 과정을 거쳐야할까?

아래는 디스크에 있는 파일을 읽어 들여서 오른족에 보이는 컨트롤에 동적 로딩한 화면이다.

복잡한 과정은 전혀 필요없다.

BOOL CSssDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
   
    //
파일에서 이미지를 비트맵 타입으로 읽어온다.
    //
현재는 커렌트 경로에 존재하므로 전체 경로를 넣지 않았지만.
    //
실행파일과 다른 경로에 존재한다면 절대 경로를 넣어야한다.
    //
전달되는 인자값은 MSDN에 자세히 설명이 나와있다.
    HANDLE h = ::LoadImage(AfxGetInstanceHandle(), "image_file.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

    //
화면의 픽처 컨트롤을 임시로 CStatic 컨트롤로 받아들인다.
    CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC_FILE);

    //
이미지 핸들과 스태틱 컨트롤이 제대로 값을 가지고 있다면
    if(h && pStatic) {
        //
컨트롤에 비트맵을 연결시킨다.
       pStatic->SetBitmap((HBITMAP)h);
    }
  
    return TRUE; // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}


아이콘일 경우도 위의 과정에서 필요한 형태만 변경한다면 아주 쉬울것이다.

참고. 만약 이미 비트맵이 로딩되어 있다면.. GetBitmap()으로 비트맵 핸들을 받은 후에
그 핸들을 CloseHandle()을 이용하여 해제해주고, 새로이 SetBitmap()을 해주어야 한다.

이렇게 생성하거나 할당한 리소스를 필요할 때 해제해 주지 않으면 나중에 [리소스가 부족합니다.]
라는 엉뚱한 메시지를 볼 수 있을것이다.

58.zip
0.05MB




+ Recent posts