Programming - cpueblo.com

MFC 잡기술 시리즈


글쓴이 : 유광희 날짜 : 2002-05-13 (월) 21:28 조회 : 23962

[미친왕자] MFC 잡기술 시리즈 탄생예고
--------------------------------------------------------------------------------
게 시 자 : drdk(이동기)
게 시 일 : 97/04/13 00:20:26
수 정 일 : 97/05/05 12:33:41
크    기 : 1.5K
조회횟수 : 803

안녕하십니까.

MFC 프로그래밍에 반은 미쳐있는 자칭 왕자 이동기 입니다.

저도 MFC  프로그래밍을 시작한지 얼마 되지는 않았지만 많은 분들의 도움으로 인

해 하루하루 배워나가고 있습니다.

이 강좌(?)는 이제 막 MFC를 시작하신 분들에게 적합하리라고 생각됩니다.

아래의 윈도우즈(API) 프로그래밍에 비하면  너무 초라할지 모르지만 제가 프로그

래밍 제작을 하면서 골머리를 앓았던 문제들에 대하여 혹시나 저같은 고민에 휩싸

여있는 분들이 있지 않을까 해서, 적지만 저의 지식을 동호회 회원님들과 함께 공

유하고자 글을 올립니다.

이번 MFC 잡기술 시리즈는 MFC의 특성상 윈도우즈 프로그래밍에 관한 전반적인 문

제를 다루지는 않습니다. 

(MFC는 그림으로 설명해야할 부분이 너무 많으니까요 ....!)

이 글은 적어도 AppWizard를 통하여 기본적인 윈도우 정도는 생성시킬 수 있는 정

도의 프로그래머를 대상으로 합니다.

그러니 왕초보 - 윈도우 프로그래밍을 완전히 모르는 분 - 프로그래머분께는 어쩌

면 도움이 안될지도 모르겠군요.

저도 아직 학생이고 또 배우고 있는 입장이라서  많은 양을 한꺼번에 올리지는 못

하고, 또 올린 글들도 완벽한 최신 기술은 아닐 수도 있음을 양지하시기를 바랍니

다.

저와 같은 병아리 프로그래머님들의 많은 기대와 참여를 부탁드립니다.


" 삐약, 삐약, !!!!....???? "


                                            The Boss   [미친왕자] ..........


# P.S. : 아 참, (혹시 시삽님께서 이글을 읽으시면) 이 강좌란이 아무나 글을 올

         릴 수 있는 곳이 아니라면 - 시삽님의 허락이 있어야 할 경우 - 제게 메

         일을 보내주시거나 아니면 공개 안내문을 올려주시기 바랍니다.

         제가 읽는 즉시 글을 모두 삭제하겠습니다.



[미친왕자] MFC 잡기술 시리즈 #1.
--------------------------------------------------------------------------------
게 시 자 : drdk(이동기)
게 시 일 : 97/04/13 17:17:58
수 정 일 : 97/05/05 12:39:39
크    기 : 2.8K
조회횟수 : 984

안녕하십니까.

81번에 예고해드린대로 MFC에 관한 잡기술 시리즈를 시작하겠습니다.

지난번에  말씀드린대로 이 강좌(?)는  이제 막 MFC를 시작하신 저와 같은 병아리

프로그래머를 위한 것이므로, 이미 중닭(?)이 되신 분들이나 아직 달걀(?) 상태에

계신 분들은 그냥 지나치시기 바랍니다.

자 그럼 시작해볼까요?



# 기능 : 이번 잡기술은 매우 기초적인 것으로서 윈도우에 스크롤바를 생성시키고

         화면 스크롤시에 - Line scroll 이든지 Page scroll 이든지 - 어느 정도

         씩 스크롤 되도록 할 것인지, 그리고 전체 스크롤의 범위는 어떻게 정하

         는지에 관한 것입니다.



# 방법 : 1) 처음 프로잭트를 생성 시킬때에 'AppWizard'의 마지막 단계에서 View

            의 기반 클래스(Base Class)를 CScrollView로 설정합니다.

         2) 1)번을 실행하시면 ~~View.cpp ('~~' 는 프로잭트명을 의미함.) 화일

            에 OnInitialUpdate() 함수가 생성되어 있는데, 이 함수 에서 각각에

            해당하는 인수들의 값을 정합니다.



# 코딩 : /////  이 프로잭트의 이름은 DKScroll 입니다. /////


         //  DKScrollView.cpp //
     
         // 이 함수는 자동적으로 생성되어집니다.
         void CDKScrollView::OnInitialUpdate()
         {
             CScrollView::OnInitUpdate();

             // 스크롤의 정보 입력을 위한 변수 설정.
             CSize sizeTotal;  // 스크롤의 총 크기를 설정할 변수.
             CSize sizePage;   // 스크롤의 페이지단위 이동값을 설정할 변수.
             CSize sizeLine;   // 스크롤의 줄단위 이동값을 설정할 변수.

             // TOTO : calculate the total size of this view

             // 스크롤의 총 크기값을 1000*1000으로 설정하겠습니다.
             // 참고로 말씀드리면 디스플레이 되는 화면의 크기 보다 스크롤 영
             // 역의 크기가 더 작으면 스크롤바는 생성되지 않습니다.
             sizeTotal.cx=1000;
             sizeTotal.cy=1000;

             // 스크롤의 페이지단위 이동값을 50으로 설정하겠습니다.
             sizePage.cx=50;
             sizePage.cy=50;

             // 스크롤의 줄단위 이동값을 5로 설정하겠습니다.
             sizeLine.cx=5;
             sizeLine.cy=5;

             // 이제 위에서 설정한 값들을 실제 프로그램에 등록시킵니다.
             // SetScrollSizes()에 관한 자세한 내용은 On-Line Help 를 이용하
             // 시기 바랍니다.
             SetScrollSizes(MM_TEXT,sizeTotal,sizePage,sizeLine);

         }  // 파일의 끝입니다.



위와 같이 코딩하신 후에 컴파일(또는 빌드)하시면 원하는 크기와 스크롤 이동 단
     
위의 스크롤 화면을 구성하실 수 있습니다.


이로써 이번 강좌를 마칠까 합니다. (써 ~ 어 ~ ㄹ ~ 러 ~ ㅇ ~ )

너무 쉽지요???   큭큭큭....

앞으로 더욱 고난도의 잡기술들을 올리도록 노력하겠습니다.

많은 관심과 격려를 부탁드립니다.

(저역시 초보자라 여러분의 격려가 없으면 실의에 빠질 수도 있음.) 

더욱 썰렁 ~~~

감사합니다.

                                            The Boss   [미친왕자] ..........


[미친왕자] MFC 잡기술 시리즈 #2.
--------------------------------------------------------------------------------
게 시 자 : drdk(이동기)
게 시 일 : 97/04/19 02:19:19
수 정 일 : 97/05/05 14:51:42
크    기 : 5.5K
조회횟수 : 619

일주일 동안 잘 지내셨습니까.

삐약 조직의 영원한 보스 [미친왕자] 이동기 입니다.

지난번(수요일이던가?)에 게시판에 말씀드린대로 오늘 2탄을 올립니다.

지난 1탄은 벌써 50분에 달하는 분이 동참해 주셨더군요..

조직원님들의 성원에 감사드립니다. (감동의 물결)

그러면 이번 강좌를 시작하도록 하죠..

흠흠,,,,



# 기능 : 이번 잡기술은  예고드린대로 메인 프레임 윈도우의 위치와 크기를 저장

         하는 기법입니다.   간단하게 말해서 프로그램이 실행될 때 생성되는 메

         인 프레임 윈도우가 가장 최근에 사용을 종료했을때의 위치로 뜨도록 하

         는 기법입니다.   프로그램이 새로 실행될 때마다 임의의 윈도우가 임의

         의 위치에 뜬다면  사용자 입장에서는 그리 환호할 만한 사항이 아닐 것 

         입니다.


# 방법 : 1) AppWizard 를 이용하여 프로젝트를 만드시면  MainFrm.cpp 라는 파일

            이 생성 됩니다.

         2) 프로그램 시작시에 MainFrm.cpp 안에 자동으로 생성되어 있는 Oncre-

            ate() 함수에서 이전의 위치를 로드합니다.

         3) Classwizard 를 이용하여 MainFrm.cpp 내부에  WM_DESTROY 메시지 핸

            들러를 만듭니다.

         4) 3)번을 실행하시면 일반적으로  OnDestroy() 핸들러가 생성되는데 이 

            함수에서  윈도우가 파괴되기 직전에 현재의 위치를 파일에 저장합니

            다.

         ※ 참고로 윈도우 위치를 저장하는 파일의 이름은 'WndRect.dat' 입니다.

# 코딩 :  /////  이 프로잭트의 이름은 DKWndpos 입니다. /////


          //   MainFrm.cpp   //


          // 이 함수는 자동적으로 생성되어집니다.
          // 이곳에서 이전 윈도우의 위치를 파일로부터 로드합니다.
          int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
          {

              // 이곳은 자동생성되는 부분입니다.
              if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
                  return -1;

              if (!m_wndToolBar.Create(this) ||
                      !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
              {
                  TRACE0("Failed to create toolbar\\n");
                  return -1;      // fail to create
              }

              if (!m_wndStatusBar.Create(this) ||
                      !m_wndStatusBar.SetIndicators(indicators,
                          sizeof(indicators)/sizeof(UINT)))
              {    
                  TRACE0("Failed to create status bar\\n");
                  return -1;      // fail to create
              }

              // TODO: Remove this if you don't want tool tips or a resizea-
              // ble toolbar
        
              m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
                      CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

              // TODO: Delete these three lines if you don't want the toolb-
              // ar to be dockable
              m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
              EnableDocking(CBRS_ALIGN_ANY);
              DockControlBar(&m_wndToolBar);


              // 윈도우 생성시에 과거의 위치를 파일에서 로드하는 부분.
              RECT Rect;  // 과거 윈도우의 위치를 로드할 구조체 변수 선언.
              CFile File;  // 파일 함수를 이용하기 위한 파일 변수 선언.


              // 파일의 오픈이 잘 이루어졌을 경우에 실행.
              // Open() 이나 Read() 함수에 관한 자세한 사항은 On-Line Help를
              // 참조하시기 바랍니다.
              if(File.Open("WndRect.dat",CFile::modeRead))
              {
                  if(File.Read((LPVOID)&Rect,sizeof(Rect))==sizeof(Rect))
                  {
                      // 윈도우를 원하는 위치와 크기로 이동합니다.
                      // MoveWindow() 함수에 관한 자세한 사항은 On-Line Help
                      // 를 참조하시기 바랍니다.
                      MoveWindow(Rect.left,Rect.top,Rect.right-Rect.left,
                                     Rect.bottom-Rect.top);
                  }

                  File.Close();  // 파일을 닫습니다.
               }

               return 0;  // 자동 생성된 부분입니다.
           }



          // 이 함수는 ClassWizard를 이용하여 만든  WM_DESTROY 메시지 핸들러
          // 입니다.
          // 이곳에서 현재 윈도우의 위치를 파일에 저장합니다.
          void CMainFrame::OnDestroy() 
          {
              // 윈도우 파괴시에 현재의 위치를 파일에 저장하는 부분.
              RECT Rect;  // 과거 윈도우의 위치를 로드할 구조체 변수.
              CFile File;  // 파일 함수를 이용하기 위한 파일 변수.

              // 현재의 윈도우의 위치를 구조체 변수에 저장함.
              GetWindowRect(&Rect);

              // 파일의 오픈이 잘 이루어졌을 경우에 실행.
              // 파일이 존재하지 않으면 새로 생성시킴. 
              if(File.Open("WndRect.dat",CFile::modeCreate | 
                              CFile::modeWrite))
              {
                  //구조체 변수에 저장한 현재 윈도우의 위치를 파일에 저장함.
                  File.Write((LPVOID)&Rect,sizeof(Rect));

                  File.Close();  // 파일을 닫음.
              }


              // 이곳은 자동생성되는 부분입니다.
              CFrameWnd::OnDestroy();
        
              // TODO: Add your message handler code here

          }

위와 같이 코딩하신 후에 컴파일(빌드)  하시면 처음에는 임의의 위치에 윈도우가

생성 되고  그 이후에는 윈도우가 지난번 끝마쳤을 때의 위치에 생성되는 것을 알 

수 있습니다.

이번 강좌도 썰렁하다고요???

그렇다면 다음 강좌를 기대해주십시요.

더욱 새로와진 모습으로 글을 올리겠습니다.

그리고 주변 친구들에게 많은 선전 부탁드립니다.

푸하하하....

삐약 조직의 영원한 발전을 기약하며...


                                             The Boss   [미친왕자]..........


[미친왕자] MFC 잡기술 시리즈 #3.
--------------------------------------------------------------------------------
게 시 자 : drdk(이동기)
게 시 일 : 97/04/30 01:53:31
수 정 일 : 97/05/14 11:00:05
크    기 : 7.6K
조회횟수 : 524

안녕하십니까?    오랜만입니다.

삐약 조직의 보스 [미친왕자] 이동기 입니다.

힘든 중간고사가 마무리 지어져가고 있습니다. (어휴 ~~~~ )

이번주에 너무나 안타까운 일이 발생하고야 말았습니다.

아기다리고기다리던 번개모임에 나가지 못한 것입니다.    어  ~~~  헉!  

그런데 2차가 있다네요... 끼욧!

가야지.. (必)!

지금 내가 뭔소리 하고 있는겨 ~~~~.  꾸  ~~~~  엑!


서두는 이것으로 마치고 본론으로 들어가지요.

이번 강좌는 View 화면(Client Area 라고 하지요.)에 점, 선, 면을 그리는 방법에

관하여 알아보고자 합니다.

이것은 많이 알려진 것이지만 우리는 삐약이들 이니까 다시 한번 짚어보겠습니다.

참고로 이번 강좌는 다음 강좌에 다루어질 애니매이션의 기본이 되는 BitBlt() 함

수를 설명하는 기초가 되니까 아시는 분들도 한번쯤 기억을 되살려 보심이 어떨까 

합니다.



# 기능 : 이번 잡기술은 단순히 화면에 그림을 그리는 것입니다.   그래픽의 기초

         가 되는 점, 선, 면의 출력을 어떻게 할 것인지에 관한 내용이며 그려질

         그림이 어떠한 것인가는 아래 코딩란을 보시면 자세히 알 수 있습니다.



# 점을 그리는 방법 : 1) SetPixel() 함수를 이용하여 바로 화면에 출력한다.



# 선을 그리는 방법 : 1) 외각선 펜을 생성한다.
            
                     2) 새로만든 펜을 설정하고 기존의 펜은 pOldPen 변수에 저

                        장한다.

                     3) 설정한 펜으로 선을 그린다.

                     4) 예전의 펜을 다시 복귀시킨다.

                     5) 설정한 펜을 지운다.



# 면을 그리는 방법 : 1) 브러쉬를 생성한다.
            
                     2) 새로 만든  브러쉬를 설정하고 기존의 브러쉬는 pOldBr-

                        ush 변수에 저장 한다.

                     3) 설정한 브러쉬로 면을 그린다.

                     4) 예전의 브러쉬를 다시 복귀시킨다.

                     5) 설정한 브러쉬를 지운다.

          ※ 참고로  면을 그리는 경우,  면의 외각선은 펜에 의하여 설정되어지

             므로 외각선의 색과  면의 색을 동일하게 하기 위해서는  펜의 색과

             브러쉬의 색을 동일하게 생성해야 합니다. 

             (언뜻 이해가 안가시는 분들은 아래 코딩란을 보시기 바랍니다.)



# 코딩 : // Drawing 함수는 거의 대부분이(전부라고 해도 과언이 아님) CDC 클래

         // 스의 멤버함수 입니다.   따라서 CDC에 해당하는 클래스의 상속을 받

         // 아야 하지요.   이 프로그램은 기본적인 프로그램이므로 가정 보편적

         // 인 방법인 OnDraw() 함수의 인자인 CDC* pDC 포인터 변수를 이용하였

         // 습니다.

         // 구체적인 코딩은 다음과 같습니다.


         ///////  이 프로젝트 이름은 Drawing 입니다.  ///////


         //    DrawingView.cpp    //         

        void CDrawingView::OnDraw(CDC* pDC)
        {

            // 이 부분은 자동으로 생성된 부분입니다.        
            CDrawingDoc* pDoc = GetDocument();
            ASSERT_VALID(pDoc);

            // TODO: add draw code for native data here


            // 이 부분은 헤더 파일에 선언하는 것이 바람직 합니다.
            int i,j;  // for 루프를 돌리기 위한 counting 변수.
            CPen Pen; // 펜의 생성을 위한 변수.
            CBrush Brush;  // 브러쉬 생성을 위한 변수.
            CPen* pOldPen;  // 기존의 펜을 저장하기 위한 포인터 변수.
            CBrush* pOldBrush; // 기존의 브러쉬를 저장하기 위한 포인터 변수.



            // 점찍기 방법입니다.
            // 가로 길이 90, 세로 길이 90 만큼 빨강색 점을 찍습니다.
            // SetPixel()에 관한 자세한 사항은 On-Line Help를 참조하시기
            // 바랍니다.
        
            for(j=10;j<100;j++)
                for(i=10;i<100;i++)
                    pDC->SetPixel(i,j,RGB(255,0,0));  // 빨강색 점을  지정된
                                                      // 위치에 찍음.



            // 선그리기 방법입니다.        
            // 점(150,0)과 점(200,100)을 잇는 파랑색 선을 그립니다.
            // 아래 사용된 각 함수에 관한 자세한 사항은  On-Line Help를 참조
            // 하시기 바랍니다.
        
            Pen.CreatePen(PS_SOLID,0,RGB(0,0,255));  // Pen을 생성시킴.

            pOldPen=(CPen*)pDC->SelectObject(&Pen);  // 새로 생성한  펜을 설
                                          // ↑      // 정하고  기존의  펜을 
                                                     // pOldPen  변수에 저장
                                                     // 함.

            // ★★★★  경고  ★★★★

            // 너무나도 중요한 사실 하나!!!!
            // 바로 윗문장의 번지를 나타내는 기호(화살표)가  프린터로 찍으면
            // 면 'P'의 아래에 밑줄의 모양(_)으로 나타납니다.
            // 이점에 각별히 주의바랍니다.



            pDC->MoveTo(150,10);  // 선의 시작점으로 이동.
            pDC->LineTo(200,100);  // 선의 끝점으로 선을 그림.

            pDC->SelectObject(pOldPen);  // 기존의 펜을 다시 복귀시킴.

            Pen.DeleteObject();  // 생성시켰던 펜을 지움.



            // 면을 그리는 방법입니다.
            // (left,top,right,bottom)=(250,10,300,100) 의  좌표를 가지는 빨
            // 강색 테두리에 파랑색 내부 색상을 가지는 사각형면을 그립니다.
            // 아래 사용된 각 함수에 관한 자세한 사항은 On-Line Help를 
            // 참조하시기 바랍니다.

            Pen.CreatePen(PS_SOLID,0,RGB(255,0,0));  // Pen을 생성시킴.
            Brush.CreateSolidBrush(RGB(0,0,255));  // Brush를 생성시킴.

            pOldPen=(CPen*)pDC->SelectObject(&Pen);  // 새로 생성한  펜을 설
                                                     // 정하고  기존의  펜을
                                                     // pOldPen  변수에 저장
                                                     // 함.
            pOldBrush=(CBrush*)pDC->SelectObject(&Brush);  // 새로 생성한 브
                                                           // 러쉬를  설정하
                                                           // 고 기존의 브러
                                                           // 쉬를 pOldBrush
                                                           // 변수에 저장함.

            pDC->Rectangle(250,10,300,100);  // 사각형을 그림.
                                             // 사각형 이외에 원이나 타원 또
                                             // 는 호와 같은 기타 다른 Draw-
                                             // ing 함수도 됩니다.
                                             // Drawing 함수에  관한  자세한
                                             // 내용은 On-Line Help를 참조하
                                             // 시기 바랍니다.

            pDC->SelectObject(pOldPen);  // 기존의 펜을 다시 복귀시킴.
            pDC->SelectObject(pOldBrush);  // 기존의 브러쉬를 다시 복귀시킴.

            Pen.DeleteObject();  // 생성시켰던 펜을 지움.
            Brush.DeleteObject();  // 생성시켰던 브러쉬를 지움.

        }  // OnDraw() 함수의 끝입니다.


위와 같이 코딩하신 후에 컴파일(빌드) 하시면 화면에  점찍기로 그려진 사각형과

선그리기로 그려진 선 하나,  그리고 사각형 그리기로 그려진 사각형 하나가 화면

에 나타납니다.  

이미 다 아는 사실이라고요??

저도 알고 있습니다.

그래도 천리길도 한걸음부터이고, 아는 길도 물어가라 했으므로 기초를 다지는 마

음으로 한번 적어보았습니다.

조금이나마 도움이 되셨기를 진심으로 바랍니다.

그러면 다음 강좌에는 서두에서 말씀드린 바와 같이 애니매이션의 기본이 되는

BitBlt() 함수를 이용한 CDC 메모리 카피 방법에 관한 글을 올리겠습니다.

그리고, 혹시라도 제 강좌에 대한 소스를 원하시면 제게 메일 주시거나 공개 계시

판에 올려주십시요.  

소스 파일을 보내드리겠습니다. (원하는 사람이 있을려나????....!!!!)

푸하하하....

그럼 일주일 내지는 열흘 안에 다음 강좌(4탄)를 올리겠습니다.

안녕....... ( 룰루 랄라 ~~~~ )

삐약 조직이여 영원하라 !!!!!  

푸하하하.....

                                              The Boss  [미친왕자]..........


[미친왕자] MFC 잡기술 시리즈 #4.
--------------------------------------------------------------------------------
게 시 자 : drdk(이동기)
게 시 일 : 97/05/08 01:22:35
수 정 일 : 97/09/09 13:03:18
크    기 : 5.9K
조회횟수 : 552

반갑습니다.  오래간만이네요.

The Boss [미친왕자] 입니다.  잡기술 3탄 올린지 벌써 일주일이 지났네요.  별로

도움이 안되셨나?  조회 횟수가 영 ~ .

그래도 계속 하겠습니다.  달래 [미친왕자] 겠습니까?

헤헤....

이번 강좌는 기초 설명이 좀 길 것 같군요.  하지만 중요한 내용이므로 꼭 끝까지

읽어주시면 감사하겠습니다.

그럼 시작하지요.

지난 강좌에서는 화면에 점, 선, 면을 그리는 방법을 설명드렸습니다.   이번에는 

예고 대로 애니메이션의 기초가되는 CDC 메모리 Copy에 관하여 설명드리겠습니다.

이때 사용되는 함수가 바로 BitBlt() 함수이며 예상하신대로 CDC 클래스의 멤버함

수 입니다.

먼저 가상의 CDC를 메모리에 생성시킵니다.  이 때 사용되는 함수는 CreateCompa-

tibleDC() 입니다.  보통의 경우 DC(Device Context)는 일반적으로 사용되는 Dis-

play 장치 즉, 모니터가 됩니다.

쉽게말해서, 눈에 보이지는 않지만 메모리상에 우리가 쓰고 있는 모니터와 똑같은

녀석이 하나 더 생기는 것입니다.

두 번째로, CompatibleBitmap을 만듭니다.   그 이유는 방금 만든 CompatibleDC는 

그림을 Bitmap 형식으로 인식하기 때문입니다.  이 과정을 거치지 않고 냅다 Com-

patibleDC에 그림을 그려대면  CompatibleDC가 그러죠.  " 짜샤, 그래봐야 소용없

어.  지렁이가 기도한다고 용되냐? "   우리가 기껏 고철 나부랭이한테 이런 소리

를 들어야 되겠습니까?  (어휴, 이걸 그냥 뽀솨버려? )

세 번째로, 새로 만든 CompatibleBitmap과 CompatibleDC를 접목시킵니다.  안그러

면 CompatibleDC가 CompatibleBitmap한테 그러죠.   "난 너 몰라.  그러니깐 너랑

안놀아. "   그러면 CompatibleBitmap도 질세라 " 똥싸구 있네, 짜식.  누가 너랑

논데? " 라고 하죠.   서로 싸우다가 아무 일도 못하고 프로그램이 종료되면 각자

집에 가죠.

으........이런 괴씸한 놈들!

그러니깐 꼭 CompatibleBitmap을 CompatibleDC에 등록시켜주세요.

앞의 과정이 모두 끝나면 이제 CompatibleDC에 그림을 그립니다.

그다음에 그린 그림을 BitBlt() 함수를 이용하여 메모리에 Copy 시킵니다.

그러면 끝나죠.

그러나 여기에서 참고하실 것이 있어요. 아래 코딩란과 같이 코딩하시면 점찍기로

그린 빨강색 사각형과 검정색 선이 하나 그려지구요,  나머지 바탕은 요상한 색이

막 나타나있어요.  그 이유는 우리가 메모리상에 생성한 CompatibleDC에 쓰레기값

들이 들어있는데 요놈의 '띨빵'한 컴이 그것을 색상 정보로 인식하기 때문이죠.

이것을 막기 위해서는 CompatibleDC에  CompatibleBitmap과 동일한 크기의 사각형

을 그려주시던가 아니면 다른 적절한 방법으로 바탕색상을 초기화 하면 됩니다.

제가 일부러 바탕색을 초기화하지 않은 이유는 CompatibleDC에 관해서 좀 더 친숙

해지시라고....

헤헤.....

이제 본론으로 들어가겠습니다.


# 기능 : 이번 잡기술은 메모리상에 그림을 그려 그 그려진 그림을 화면으로 복사

         하는 방법입니다.   이 기법은 애니메이션을 구현하는데 가장 기초가 되

         는 것인데 그 이유는 메모리 Copy의 속도가 캡 빠르기 때문입니다.

         움직이는  동작이 빠른 속도로 지나가는  프레임들의 연속이라는 사실을 

         상기하면 쉽게 그 내용을 이해하실 수 있을 것입니다.


# 방법 : 1) CompatibleDC와  CompatibleBitmap을 생성시킬 메모리 공간을 확보한

            다.

         2) CompatibleDC와 와 CompatibleBitmap을 생성한다.

         3) CompatibleBitmap을 CompatibleDC에 등록시킨다.

         4) CompatibleDC에 그림을 그린다.

         5) CompatibleDC에 그린 그림을 화면으로 복사한다.

         6) 이전의 DC를 회복시킨다.

         7) 1)번에서 확보한 메모리를 해제한다.
 

# 코딩 :  /////    이 프로젝트의 이름은 Bit입니다.    ////

          //     BitView.cpp     //

         void CBitView::OnDraw(CDC* pDC)
         {
             // 이곳은 자동적으로 생성되는 부분입니다.
             // 참고로 아래 사용된 함수들에 관한 자세한 사항은  On-Line Help
             // 를 이용하시기 바랍니다.
             CBitDoc* pDoc = GetDocument();
             ASSERT_VALID(pDoc);

             // TODO: add draw code for native data here

             // CompatibleDC와 CompatibleBitmap을 사용하기 위한 클래스 선언. 
             CDC* pCompDC;
             CBitmap* pBitmap;
             CBitmap* pOldBitmap;

             // CompatibleDC와 CompatibleBitmap을 생성시키기 위해서 메모리를
             // 확보한다.
             pMemDC = new CDC;
             pBmp= new CBitmap;

             // CompatibleDC와 CompatibleBitmap을 생성시킨다.
             // CompatibleBitmap의 크기는 800*600으로 설정하겠습니다.
             pMemDC->CreateCompatibleDC(pDC);
             pBmp->CreateCompatibleBitmap(pDC,800,600);

             // CompatibleBitmap을 CompatibleDC에 등록시킨다.
             pOld=pMemDC->SelectObject(pBmp);

             // CompatibleDC에 점찍기로 사각형을 그린다.
             for(j=10;j<150;j++)
                 for(i=10;i<150;i++)
                     pMemDC->SetPixelV(i,j,RGB(250,0,0));

             // CompatibleDC에 선을 그린다.
             pMemDC->MoveTo(170,10);
             pMemDC->LineTo(200,150);

             // CompatibleDC에 그린 그림을 실제의 화면으로 복사한다.
             pDC->BitBlt(0,0,600,500,pMemDC,0,0,SRCCOPY);

             // 이전 DC로 회복시킨다.
             pMemDC->SelectObject(pOld);

             // 확보한 메모리를 해제한다.
             delete pMemDC;
             delete pBmp;

         }  // 코딩의  끝입니다.

쉽죠?

하지만 전 이 기술을 배우기 위해 두달을 투자했습니다.   결국 모 동호회의 회원

님께서 조언을 주셔서 터득할 수 있었지요.  역시, 지식은 공유할수록 그 힘을 발

발휘한다는 저의 지론이 타당한 것 같습니다.  이 지면을 빌어 도움을 주신 모 회

원님께 다시 한번 감사의 말씀을 전합니다.

이땅의 모든 이기적인 프로그래머들이 사라지기를 바랍니다.

( 물론 상업적인 프로그램의 독창기법에 대한 기밀은 제외해야 겠지요!  헤헤.. )


그러면 이번 강좌는 여기에서 마치고 다음 강좌를 예고할까합니다.   다음에는 마

우스의 모양을 바꾸어주는 기법에 관해서 설명하겠습니다.   윈도우즈에서 제공해

주는 화살표 마우스만 사용하면 재미 없잖아요.

상관없다고요?

읔, 이런! (캡 충격이군..)

그러나 저는 충격에 강하죠....

왜냐하면 프로니까..  

헤헤헤..

열흘 정도 있다가 5탄 올릴께요.

그때 봐~~~~~~ 어.

                                               The Boss [미친왕자]..........



[미친왕자] MFC 잡기술 시리즈 #5.
--------------------------------------------------------------------------------
게 시 자 : drdk(이동기)
게 시 일 : 97/05/19 11:05:43
수 정 일 : 97/06/08 23:37:26
크    기 : 7.5K
조회횟수 : 497

안녕하십니까.

The Boss [미친왕자]  이동기 입니다.

이번 강좌는 마우스 Cursor를 프로그래머가 직접 만든 것으로 바꾸는 기법입니다.

프로그램의 내용을 설명드리자면  Client Area 내에서 마우스의 왼쪽 버튼을 누르

면 프로그래머가 만든 Cursor의 모양으로 바뀌고 또 한번 누르면  다시 원래의 화

살표 모양의 Cursor로 바뀌는 토글 형식의 간단한 프로그램입니다.

이번에도 서두가 좀 길겠군요.



우선 마우스 Cursor를 그려야 겠지요.

그리는 방법은 매우 간단합니다.  Microsoft Developer Studio 의 맨 위에 보시면

Tool Bar내에 New Cursor 버튼이 있습니다.  

이 버튼을 누르시면 Resource의 Icon 항목에 새로운 Cursor 항목이 첨가됩니다.

이 새로 생성된 Resource 항목을 더블클릭 하면 Resource 편집기가 뜨지요.

이 편집기 내에서 원하시는 그림을 그리면 됩니다.

그다음 'ALT+ENTER' 를 누르시면 아래쪽에  다이얼로그 박스 하나가 뜨는데 그 다

이얼로그박스 에서 방금 그린 Cursor의 ID를 설정하시면 됩니다.

다음에는 '~~View.h' 파일에 마우스 버튼에 대한 토글변수를 설정합니다.

이유는 아시죠? (선택 사항이 2개 밖에 없으니까요.)

위에서 사용된 '~~'는 아시는 것처럼 프로젝트명을 의미합니다.

다음에는 '~~View.cpp'에 WM_LBUTTONDOWN 메시지 핸들러를 만듭니다.  

이 핸들러에서 토글 작업과 SetCursor를 명령합니다.

다음에는 마지막 단계로서 '~~View.cpp'에  WM_SETCURSOR 메시지 핸들러를 만듭니

다.

이 핸들러에서 토글 변수를 기반으로 실질적인 SetCursor 작업이 이루어집니다.


위의 설명으로 이번 강좌의 전반적인 내용은 파악을 하셨을줄 믿습니다.

자 그럼 이제부터 본문으로 들어가겠습니다.



# 기능 : 이번 잡기술은 서두에 기술한 바와 같이 마우스 버튼의 토글작동을 이용

         하여 마우스 Cursor의 모양을 바꾸는 기법입니다.



# 방법 : 1) Resource 편집기를 이용하여 마우스 Cursor를 하나 그린다.

         2) '~~View.h' 파일에 토글 변수를 설정한다.

         3) '~~View.cpp' 파일의 생성자에서 토글 변수를 초기화한다.

         4) '~~View.cpp' 파일에 WM_LBUTTONDOWN 메시지 핸들러를 만들어 SetCu-

            rsor를 지시한다.

         5) '~~View.cpp' 파일에 WM_SETCURSOR 메시지 핸들러를 만들어 SetCurs-

            or를 수행한다.



# 코딩 : /////  이 프로젝트의 이름은 Crs 입니다.  /////

         // Resource 편집기를 이용하여 마우스 Cursor를 그리고 그 새로운 Cur-
         // sor의 ID를 등록하는 작업은 생략합니다.
         // 강좌의 서두에 설명드린대로 하시면 됩니다.



         //     CrsView.h     //

         // 헤더파일은 비교적 길이가 짧으므로 파일 전체를 쓰겠습니다.
         // 실제로 수정한 부분은 클래스 내부의 토글 변수를 선언하는 한 줄 밖
         // 에 없습니다.  나머지는 모두 자동으로 생성되는 부분입니다.

         // CrsView.h : interface of the CCrsView class
         ///////////////////////////////////////////////////////////////////

         class CCrsView : public CView
         {
         protected: // create from serialization only
             CCrsView();
             DECLARE_DYNCREATE(CCrsView)

         // Attributes
         public:
                 CCrsDoc* GetDocument();

         // Operations
         public:
             BOOL Toggle;  // 토글변수를 설정합니다.
                           // 이  한줄의 문장만 빼고는  모두 자동으로 생성된
                           // 것입니다.

         // Overrides
         // ClassWizard generated virtual function overrides
         //{{AFX_VIRTUAL(CCrsView)
         public:
             virtual void OnDraw(CDC* pDC);  // overridden to draw this view
             virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
         protected:
             virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
             virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
             virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
          //}}AFX_VIRTUAL

         // Implementation
         public:
         virtual ~CCrsView();
         #ifdef _DEBUG
             virtual void AssertValid() const;
             virtual void Dump(CDumpContext& dc) const;
         #endif

         protected:

         // Generated message map functions
         protected:
         //{{AFX_MSG(CCrsView)
             afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
             afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT messag
                 e);
         //}}AFX_MSG
         DECLARE_MESSAGE_MAP()
         };

         #ifndef _DEBUG  // debug version in CrsView.cpp
         inline CCrsDoc* CCrsView::GetDocument()
             { return (CCrsDoc*)m_pDocument; }
         #endif

         ////////////////////////////////////////////////////////////////

         // 헤더 파일의 끝입니다.





        //     CrsView.cpp     //

        // 이하에서는 CrsView.cpp 의 생성자와 WM_LBUTTONDOWN 메시지 핸들러와
        // WM_SETCURSOR 메시지 핸들러 만을 쓰겠습니다.
        // 나머지 자동으로 생성된 부분은 손대지 않았으니까 쓸 필요가 없겠죠.
        // 노파심에서 한말씀 드리면 생성자는 토글변수를 초기화 하는데 쓰이고
        // 메시지 핸들러는 Class Wizard 에서 생성시키면 됩니다.
        // 참고로 이 프로그램에서 생성한 마우스 Cursor의 ID는 'IDC_MY_CURSO-
        // R' 입니다.



        // CrsView.cpp 의 생성자 입니다.
        CCrsView::CCrsView()
        {
            // TODO : add construction code here

            // 토글변수를 초기화 합니다.
            Toggle=FALSE;
        }



        // WM_LBUTTONDOWN 메시지 핸들러 입니다.
        // 이 핸들러에서는  마우스의 왼쪽 버튼이 눌릴 때마다 토글변수의 값을
        // 토글시켜주며, SetCursor를 명령합니다.

        void CCrsView::OnLButtonDown(UINT nFlags, CPoint point) 
        {
            // TODO: Add your message handler code here and/or call default

            // 변수 Toggle을 toggle시킵니다.
            if(Toggle==TRUE)
                Toggle=FALSE;
            else
                Toggle=TRUE;

            // Setcursor을 지시합니다.
            // 이 함수가 실행되면 WM_SETCURSOR 라는 메시지가 발생하며 아래의
            // WM_SETCURSOR 핸들러를 수행하게 됩니다.
            SetCursor(AfxGetApp()->LoadCursor(IDC_MY_CURSOR));

            // 자동으로 생성된 부분입니다.
            CView::OnLButtonDown(nFlags, point);
        }



        // WM_SETCURSOR 메시지 핸들러 입니다.
        // 이 부분에서 실질적인 마우스 Cursor의 전환이 이루어집니다.
        BOOL CCrsView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
        {
            // TODO: Add your message handler code here and/or call default

            if(Toggle==TRUE)
            {
                // Cursor를 바꿈.
                SetCursor(AfxGetApp()->LoadCursor(IDC_MY_CURSOR));
                return TRUE;
            }  // if문 마침.
            else
            {
                // Cursor를 원래 화살표 모양으로 바꿈.
                SetCursor(LoadCursor(NULL,IDC_ARROW));
                return FALSE;
            }  // else문 마침.

            // 자동으로 생성된 부분입니다.        
            return CView::OnSetCursor(pWnd, nHitTest, message);
        }

        // CrsView.cpp 파일의 끝입니다.



위의 기법을 기초로 약간만 응용해도 여러가지 상황하에서  마우스 Cursor의 모양

을 원하는대로 바꾸어 줄 수 있겠지요.   (헤헤헤...)

그러고보니 이번에도 새벽에 강좌를 올리게 되는 군요.

조직원님들의 MFC프로그래밍 학습에 조금이나마 도움이 되었으면 합니다.


이번 강좌는 여기에서 마치고 다음 강좌를 예고하겠습니다.

다음 강좌는 음성(wave; ~.wav) 파일을 다루는 법에 관한 것입니다.

요즘 나오는 프로그램에서 음성지원이 안된다는 것은 상상할 수도 없는 것이지요.

게임을 하면서 악당을 무찔렀는데,  아무런 비명도 지르지 않는다면 누가 그 게임

을 하겠습니까?

안그렇심꺄?

푸헤헤헤..........

그럼 또 뵙죠.

우리 조직은 영원한 번영만이 있을 뿐입니다.

캬캬캬캬.........


                                             The Boss [미친왕자]............


[미친왕자] MFC 잡기술 시리즈 #6.
--------------------------------------------------------------------------------
게 시 자 : drdk(이동기)
게 시 일 : 97/06/08 21:36:02
수 정 일 : 97/06/11 01:33:46
크    기 : 4.2K
조회횟수 : 444

진짜루 반갑습니당.

아시는 분은 다 아시겠지만 제 모뎀이 벼락을 맞아서  날라가는 바람에 한동안 통

신을 할 수가 없었습니다.

그래서 약속드린 날짜에 강좌를 올릴 수가 없었죠.  헤헤헤...

이번에는 서두가 특히 길것 같군요.

하지만 음성파일을 이해하시는데 도움이 되는 것들이니 짜증내지 마시고 한번쯤 읽

어주시기 바랍니다.


그럼 여섯번째 강좌를 시작하지요.

이번 강좌는 간단한 음성(wave)파일을 출력하는 프로그램입니다.

오락을 하면서, 나쁜놈을 죽였는데 아무런 소리도 지르지 않고 기냥  사라져 보십

시요.

얼마나 썰렁하겠습니까?

그래서 우리도 간단하나마 ~.wav 파일을 출력하는 방법을 알아보도록 하겠습니다.

이 프로그램의 기능은  내 프로그램 화면 내에서  마우스의 왼쪽 버튼을 클릭하면

멋진 소리가 나도록 하는 프로그램입니다.

노파심에서 말씀드리면 ~.wav 파일은 이미 만들어져 있는 파일입니다.

그리고 ~.wav 파일은 내 프로젝트의 Debug 폴더에 이미 카피되어 있다고 가정하겠

습니다. 

Visual C++ 에서 음성파일을 다루는 방법은 크게 3가지로 나뉩니다.

첫째, sndPlaySound() 함수를 이용하여 간단히 출력하는 방법.

둘째, MCI 명령을 사용하는 방법.

세째, 로레벨(low level) 서비스 함수를 사용하는 방법 입니다.

참고로 두번째 방법은 강좌 98번의 최상근님께서 올리신 'CD Player를 만들자' 에

서 쓰인 방법입니다.

두번째와  세번째 방법에 관한 프로그래밍 방법은 다음번에 자세하게 논하기로 하

지요.

여기에서는 첫번째 방법을 이용하겠습니다.

이 방법은 약 30초 이내의 짧은 wave 파일을 출력하는 경우에 매우 효과적입니다.

사운드에 관련된 함수들을 이용하기 위해서는  함수를 사용한 파일에(~.cpp 파일)

#include "mmsystem.h"

를 추가해야 하며, 또한 'Msdev\\lib\\winmm.lib' 파일을 프로젝트에 추가시켜 주어

야 합니다.

매우 중요한 과정이므로 꼭 기억하시기 바랍니다.


그러면 이제 본격적인 내용을 알아보죠.



# 기능 : 이번 잡기술은 간단한 음성파일 출력에 관한 것입니다.  음성 출력 함수

         는 '~~View.cpp' 파일에 'WM_LBUTTONDOWN' 메시지 핸들러에서  쓰였습니

         다.  따라서 음성의 출력은 마우스의 왼쪽 버튼을 누를 때마다 이루어집

         니다.



# 방법 : 1) AppWizard를 이용하여 프로젝트를 만들고 Vi