이 영역을 누르면 첫 페이지로 이동
웬디의 기묘한 이야기 블로그의 첫 페이지로 이동

웬디의 기묘한 이야기

페이지 맨 위로 올라가기

웬디의 기묘한 이야기

C/C++ Windows Hooking 개발자의 블로그 입니다! 이곳은 개발 외에도 저의 취미들이 공유되는 기묘한 이야기가 펼쳐집니다.

[MFC] Dialog Load GIF image

  • 2019.07.28 21:47
  • ⌨ DEVELOPMENT/C++
반응형

MFC GIF Example

MFC Dialog에서 gif image 동작을 기본적으로 지원하지 않습니다. Loading Image 또는 다른 애니메이션 동작을 보여주기 위해선 Static Control (Picture Control)을 이용하는 방법이 있습니다.

 

gif_control.hpp

주의 먼저 gif 이미지를 로드하기위해선 GDI+를 이용해야 합니다. 이전에도 말씀드린 대로 GDI+를 사용하기 위해선 초기화가 되어있어야 합니다. 초기화에 관련된 내용은 아래 링크를 참조하면 됩니다.

https://wendys.tistory.com/118

 

[C++] How to use GDIPlus Library in c++

C++, MFC에서 GDI+ 사용법 윈도우 프로그램을 개발하다 보면 UI 작업이 필요한 경우가 많이 있습니다. 이때 주로 gdiplus.dll library를 사용하게 되는데, 코드를 가져와서 동작시키려는데 특별히 문제가 없는데..

wendys.tistory.com

#pragma once

class gif_control : public CStatic {
    DECLARE_MESSAGE_MAP()

public:
    gif_control();
    ~gif_control();

protected:
    virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
    virtual void PreSubclassWindow();

public:
    afx_msg void OnTimer(UINT_PTR nIDEvent);

public:
    bool verify() const;
    bool load(LPCTSTR file_name);
    void play();
    void stop();
    void clear();

private:
    Gdiplus::Image* _image;
    GUID* _dimension_ids;
    UINT _frame_count;
    UINT _current_frame;
    Gdiplus::PropertyItem* _property_item;
    bool _is_playing;
};

 

gif_control.cpp

#include <pch.h>

BEGIN_MESSAGE_MAP(gif_control, CStatic)
    ON_WM_TIMER()
END_MESSAGE_MAP()

gif_control::gif_control() {
    _image = nullptr;
    _current_frame = 0;
    _frame_count = 0;
    _is_playing = false;

    _dimension_ids = nullptr;
    _property_item = nullptr;
}

gif_control::~gif_control() {
    clear();
}

void gif_control::clear() {

    KillTimer(1);

    if (nullptr != _image) {
        delete _image;
        _image = nullptr;
    }

    if (nullptr != _dimension_ids) {
        delete _dimension_ids;
        _dimension_ids = nullptr;
    }

    if (nullptr != _property_item) {
        delete _property_item;
        _property_item = nullptr;
    }
}

bool gif_control::verify() const {
    bool result = false;

    do {
        if (nullptr == _image) {
            break;
        }

        result = true;

    } while (false);

    return result;
}

bool gif_control::load(LPCTSTR file_name) {
    bool result = false;

    do {
        if (nullptr != _image) {
            clear();
        }

        _image = Gdiplus::Image::FromFile(file_name);
        if (Gdiplus::Ok != _image->GetLastStatus()) {
            delete _image;
            _image = nullptr;
            break;
        }

        UINT frame_dimension_count = _image->GetFrameDimensionsCount();
        if (frame_dimension_count <= 0) {
            break;
        }

        _dimension_ids = (GUID*)new GUID[frame_dimension_count];
        if (nullptr == _dimension_ids) {
            break;
        }

        _image->GetFrameDimensionsList(_dimension_ids, frame_dimension_count);

        wchar_t guid_string[39] = L"";
        StringFromGUID2(_dimension_ids[0], guid_string, 39);

        _frame_count = _image->GetFrameCount(&_dimension_ids[0]);

        UINT total_buffer = _image->GetPropertyItemSize(PropertyTagFrameDelay);
        _property_item = (Gdiplus::PropertyItem * )new char[total_buffer];
        _image->GetPropertyItem(PropertyTagFrameDelay, total_buffer, _property_item);

        result = true;
    } while (false);

    return result;
}

void gif_control::play() {

    do {
        if (_is_playing) {
            break;
        }

        if (nullptr == _image) {
            break;
        }

        _current_frame = 0;
        GUID guid = Gdiplus::FrameDimensionTime;
        _image->SelectActiveFrame(&guid, _current_frame);

        UINT elapse = ((UINT*)(_property_item->value))[_current_frame] * 10;
        SetTimer(1, elapse, nullptr);
        _current_frame++;

        Invalidate(FALSE);

        _is_playing = true;

    } while (false);
}

void gif_control::stop() {

    do {
        if (false == _is_playing) {
            break;
        }

        KillTimer(1);

        _is_playing = false;

    } while (false);
}

void gif_control::PreSubclassWindow() {

    ModifyStyle(0, SS_OWNERDRAW | SS_NOTIFY);
    CStatic::PreSubclassWindow();
}

void gif_control::OnTimer(UINT_PTR nIDEvent) {

    if (nIDEvent == 1)
    {
        KillTimer(nIDEvent);

        GUID guid = Gdiplus::FrameDimensionTime;
        _image->SelectActiveFrame(&guid, _current_frame);

        UINT elapse = ((UINT*)(_property_item->value))[_current_frame] * 10;
        SetTimer(1, elapse, nullptr);
        _current_frame = (++_current_frame) % _frame_count;

        Invalidate(FALSE);
    }

    CStatic::OnTimer(nIDEvent);
}

void gif_control::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {

    Gdiplus::Graphics grapics(lpDrawItemStruct->hDC);

    CRect rect;
    GetClientRect(&rect);

    grapics.DrawImage(_image, rect.left, rect.top, rect.Width(), rect.Height());
}

코드를 보게되면 CStatic을 상속받아 SubClassing 할 것을 볼 수 있습니다.

TIP MFC Dialog Control을 subclass 하게되면 OnInitDialog가 아니고 PreSubclassWIndow에서 초기화를 하게 됩니다.

 

gif의 동작 방식은 한번 이미지를 로드하는 방식이 아니라 동영상처럼 프레임으로 이루어져있기때문에 지속적으로 프레임을 바꿔서 움직이는 이미지로 보여주어야 합니다. 그렇기 때문에 void Play()를 호출하게 되면 SetTimer를 이용하여 프레임에 맞춰 일정 시간별로 이미지를 갱신하는 방법으로 이미지를 반복 재생하면 gif player가 완성됩니다.

 

저렇게 만들어진 gif control을 어떻게 사용하면 될까요

IDC_STATIC 이름은 변수로 할당이 불가능하기때문에 특정 이름으로 변경을 해주어야 합니다.

 

MFC static control 선언

위와같이 컨트롤에 변수를 추가하게 되면 Dialog Header에는 다음과 같이 gif_control 타입에 _gif_control이 추가되고 아래처럼 CStatic Control이 DDX_CONTROL을 이용하여 연결되게 됩니다.

만약 CStatic 변수로 이미 선언되어있는경우엔 아래처럼 직접 변경해주어도 전혀 문제 없습니다.

MFC static control 을 gif_control 형태로 선언
MFC CStatic control gif control 연결

 

위와 같이 준비가 되었다면 사용하는곳에선 다음과 같이 load 하고 play 처리를 해주시며 됩니다.
//
// play
//

_gif_control.load(L"loading.gif");
_gif_control.play();


//
// stop
//

_gif_control.stop();

 

MFC Gif Image Load Play

Sample Project

wendy_gif.zip
0.25MB

반응형

'⌨ DEVELOPMENT > C++' 카테고리의 다른 글

[Solved] Resolver error: The VS Code Server failed to start  (3) 2019.12.14
[C/C++] Get Process Name by Process Id 3가지 방법  (0) 2019.12.12
[MFC] Dialog based - class name 지정하는 간단한 방법  (3) 2019.09.08
[C++] Boost ASIO를 이용한 안전한 TCP/IP 비동기 소켓 서버 예제  (5) 2019.08.07
[C++] How to use GDIPlus Library in c++  (0) 2019.07.28
[MFC] 다이얼로그의 윈도우 소멸자 호출 순서  (1) 2019.07.28
[C/C++] string wstring format 사용하기  (1) 2019.07.27
[C/C++] 윈도우10 Boost 최신버전 설치 및 사용법  (13) 2019.07.27

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [MFC] Dialog based - class name 지정하는 간단한 방법

    [MFC] Dialog based - class name 지정하는 간단한 방법

    2019.09.08
  • [C++] Boost ASIO를 이용한 안전한 TCP/IP 비동기 소켓 서버 예제

    [C++] Boost ASIO를 이용한 안전한 TCP/IP 비동기 소켓 서버 예제

    2019.08.07
  • [C++] How to use GDIPlus Library in c++

    [C++] How to use GDIPlus Library in c++

    2019.07.28
  • [MFC] 다이얼로그의 윈도우 소멸자 호출 순서

    [MFC] 다이얼로그의 윈도우 소멸자 호출 순서

    2019.07.28
다른 글 더 둘러보기

정보

웬디의 기묘한 이야기 블로그의 첫 페이지로 이동

웬디의 기묘한 이야기

  • 웬디의 기묘한 이야기의 첫 페이지로 이동

검색

메뉴

  • 홈
  • 태그
  • 방명록
  • 이야기

카테고리

  • 분류 전체보기 (204)
    • MY STORY (2)
    • 📸 WALKING WITH YOU (85)
      • 아이슬란드 신혼여행 이야기 (14)
      • 대한민국 구석구석 (62)
      • CONTAX N1 + T* 28-80mm (4)
      • SAMSUNG NX3000 (1)
      • 어느 멋진 날 (4)
    • ⌨ DEVELOPMENT (80)
      • BOOK:Review (1)
      • AI (13)
      • C++ (26)
      • Python (10)
      • WIndows Hooking (9)
      • Windows Kernel (3)
      • Design Pattern (3)
      • Debugging (9)
      • Tools (0)
      • Project (1)
      • Android (1)
      • 상업용 무료폰트 (4)
    • OS (4)
      • News (0)
      • Windows 일반 (4)
    • 모바일 (2)
      • 모바일 게임 (2)
    • 멘사 퍼즐 (9)
    • 생활 꿀 TIP (7)
      • 건강 (3)
      • 일상 (2)
    • 물생활 (8)
      • 골든볼 라미네지 롱핀 (8)
    • IT 기기 (2)
    • BLOG (4)
      • TISTORY BLOG TIP (3)

최근 글

인기 글

댓글

공지사항

아카이브

태그

  • AI
  • 카페
  • 해외여행
  • 신혼여행
  • windbg
  • 아이슬란드
  • c
  • c++

나의 외부 링크

  • kernel undocument api
  • 지구 관찰자의 일기
  • 지구와 지구곰

정보

WENDYS의 웬디의 기묘한 이야기

웬디의 기묘한 이야기

WENDYS

블로그 구독하기

  • 구독하기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. © WENDYS. Designed by Fraccino.

티스토리툴바