"Developfordummies 01"의 두 판 사이의 차이

깊이있는 삽질 Ubuntu Korea Community Wiki
이동: 둘러보기, 검색
(해결 방안)
133번째 줄: 133번째 줄:
 
* 즉, 여기서는 CreateWM 부분이 중요하며, MFC는 먼저 윈도우를 띄우고 나서 내용을 채워넣는 방식이라는걸 알 수 있다.
 
* 즉, 여기서는 CreateWM 부분이 중요하며, MFC는 먼저 윈도우를 띄우고 나서 내용을 채워넣는 방식이라는걸 알 수 있다.
 
* 의외로, 많은 책들이 코드를 보는 방법에 대해서는 잘 가르쳐주지 않는 것 같다.
 
* 의외로, 많은 책들이 코드를 보는 방법에 대해서는 잘 가르쳐주지 않는 것 같다.
 +
* WinApi 를 쓰면 MFC보다는 실행 속도가 빠를 수 있겠지만 여전히 짧지 않다.
 +
<syntaxhighlight lang="c">
 +
#include <windows.h>
 +
#include <tchar.h>
 +
 +
LRESULT CALLBACK WndProc (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) {
 +
    HDC hdc; PAINTSTRUCT ps;
 +
    switch (nMsg) {
 +
    case WM_PAINT:
 +
        hdc = BeginPaint (hWnd, &ps);
 +
        TextOut (hdc, 0, 0, _T("Hello, world!"), 13);
 +
        EndPaint (hWnd, &ps);
 +
        break;
 +
    case WM_DESTROY:
 +
        PostQuitMessage(0);
 +
        break;
 +
    default:
 +
        return DefWindowProc (hWnd, nMsg, wParam, lParam);
 +
    }
 +
    return 1;
 +
}
 +
 +
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
 +
    WNDCLASS wndClass = {0, WndProc, 0, 0, hInstance, NULL, NULL, (HBRUSH) (COLOR_WINDOW + 1), NULL, _T("HelloWorld")};
 +
    HWND hWnd; MSG msg; ATOM atom;
 +
 +
    wndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
 +
    if (!(atom = RegisterClass (&wndClass))) return 1;
 +
    if (!(hWnd = CreateWindow (MAKEINTATOM(atom), wndClass.lpszClassName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_DESKTOP, NULL, hInstance, NULL))) return 1;
 +
 +
    ShowWindow (hWnd, nShowCmd);
 +
    UpdateWindow (hWnd);
 +
 +
    while (GetMessage (&msg, NULL, WM_NULL, WM_NULL)) {
 +
        TranslateMessage (&msg);
 +
        DispatchMessage (&msg);
 +
    }
 +
 +
    UnregisterClass(MAKEINTATOM(atom), hInstance);
 +
    return (int) msg.wParam;
 +
}
 +
</syntaxhighlight>
 
* 이제, Hello World는 찍어봤으니, 이걸 다른걸로 바꿔서 한 번 해보자.
 
* 이제, Hello World는 찍어봤으니, 이걸 다른걸로 바꿔서 한 번 해보자.
 
* 그냥 몇줄 정도 찍어보도록 한다.
 
* 그냥 몇줄 정도 찍어보도록 한다.

2014년 6월 7일 (토) 04:01 판

문제 발생

  • 이거 프로그램을 짜서 돌리면 제대로 돌아가기나 할까?

문제점 분석

  • 아주 기본적인 프로그램을 작성하여 돌려보도록 하자.

해결 방안

  1. 그냥 단순한 텍스트가 출력되는지 보자.
  2. 그냥 단순한 창 같은 거 하나 띄워보자.
  3. 그냥 단순한 텍스트 나열을 보자.
  • 사실 Hello World라는건 동작 확인에 쓰이는 것이다.
  • 내가 프로그래밍을 해서 Hello World가 화면에 찍히기까지 많은 일이 준비되어 있다는 거다.
  • 프로그래머야 그냥 쉽게 확인한다고 생각하지만, 여러 가지가 전제되어 있는 환경이 이미 구축되어 있는 것이다.
  • 하지만 프로토타입 설계할 때 그런 건 신경쓰지 말자. 괜시리 설계만 쓸데없이 커진다.
  • 사실 Hello World의 경우 굳이 프로그래밍할 때 순서도를 작성하지 않아도 되는 유일한 프로그램일 것이다.
  • 일반적인 경우 무조건 플로챠트를 그리길 권한다.
  • 물론 이 문서에서 다음 챕터부터는 플로챠트가 꼭 등장한다.
  • 먼저, 인터넷에서(검색엔진이 무엇이 되었든) Hello World를 검색한다.
  • Hello World 어플리케이션은 대부분의 언어에서 샘플로 제공할 것이다. 그걸 쓰면 된다.
  • 가장 많이 이야기되는 C언어를 보자.
#include <stdio.h>
int main(int argc, char* argv[])
{
  printf("Hello World!\n");
  return 0;
}
  • 잘 보면 printf가 핵심이라는걸 알 수 있을 것이다.
  • 하지만 요즘 세상에 누가 Console 화면을 볼 것인가?
  • (물론 필자나, 리눅스 유저들은 Console 화면을 좋아하지만, 대부분의 유저들은 좋아하지 않는다)
  • 그러므로 뭐 Window라도 하나 띄워보는 것이 좋겠다.
  • Window를 띄우는 함수는 Windows의 MFC를 사용하도록 하겠다.
#include <afxwin.h> // include MFC library

//
// CHelloView is paints into the center of its window, "Hello World!"
//
class CHelloView : public CWnd
{
public:
    CHelloView() {};
    virtual ~CHelloView() {};
    
    void OnPaint()    // on paint lets us draw into the view
    {                 
        // Output hello world in middle of the window
        CPaintDC dc(this); // device context for painting
        CRect rect;
        GetClientRect(&rect);
        dc.TextOut(rect.right/2 - 40,rect.bottom/2 - 10,"Hello World!");
    }        
    DECLARE_MESSAGE_MAP() // need message map to handle PAINT message
};

//
// CMainFrame is our main frame window which holds our hello view
//
class CMainFrame : public CFrameWnd
{
public:
    CMainFrame() {};
    virtual ~CMainFrame() {};

protected:    
    CHelloView m_wndView;
    
    int OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        // create our frame window first
        if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;
        
        // create a view to occupy the client area of the frame        
        if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
            CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL)) return -1;
        
        return 0;
    }

    virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
    {
        // let the view have first crack at the command
        if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
            return TRUE;
    
        // otherwise, do default handling
        return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
    }        
    DECLARE_MESSAGE_MAP() // need message map to handle CREATE message
};

//
// Application is our entry point into our MFC program
//
class Application : public CWinApp
{
public:
    Application() {};
    
    virtual BOOL InitInstance() // our entry point into MFC application
    {        
        // To create the main window, this code creates a new frame window
        // object and then sets it as the application's main window object.
        CMainFrame* pFrame = new CMainFrame;
        m_pMainWnd = pFrame;

        // create and load the frame with its resources
        pFrame->Create(NULL,"Hello World Application");
        pFrame->ShowWindow(SW_SHOW);
        return TRUE;
    };
};

BEGIN_MESSAGE_MAP(CHelloView,CWnd )    
    ON_WM_PAINT()    // paint message
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ON_WM_CREATE()    // create message
END_MESSAGE_MAP()

// Create out global application object
Application theApp;

// Notice we have no WinMain, because the MFC library 
// implements one for us
Application theApp;
  • 자, 그냥 하나 띄우는데에도 코드가 엄청 커졌다는걸 느낄거다.
  • 그러니까 책들에서 웬만하면 GUI가 안 나오는거다..
  • 예전에는 저걸 전부 외우거나 책을 보고 타이핑을 했어야 하지만, 요즘은 그렇게 프로그래밍하면 효율적이지 않다는 이야기를 듣게 될 것이다.
  • 각 컴파일러에서 제공하는 예제를 보고, 어느 부분이 핵심인지 파악하는게 중요하다.
  • 즉, 여기서는 CreateWM 부분이 중요하며, MFC는 먼저 윈도우를 띄우고 나서 내용을 채워넣는 방식이라는걸 알 수 있다.
  • 의외로, 많은 책들이 코드를 보는 방법에 대해서는 잘 가르쳐주지 않는 것 같다.
  • WinApi 를 쓰면 MFC보다는 실행 속도가 빠를 수 있겠지만 여전히 짧지 않다.
#include <windows.h>
#include <tchar.h>

LRESULT CALLBACK WndProc (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) {
    HDC hdc; PAINTSTRUCT ps;
    switch (nMsg) {
    case WM_PAINT:
        hdc = BeginPaint (hWnd, &ps);
        TextOut (hdc, 0, 0, _T("Hello, world!"), 13);
        EndPaint (hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc (hWnd, nMsg, wParam, lParam);
    }
    return 1;
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    WNDCLASS wndClass = {0, WndProc, 0, 0, hInstance, NULL, NULL, (HBRUSH) (COLOR_WINDOW + 1), NULL, _T("HelloWorld")};
    HWND hWnd; MSG msg; ATOM atom;

    wndClass.hCursor = LoadCursor (NULL, IDC_ARROW);
    if (!(atom = RegisterClass (&wndClass))) return 1;
    if (!(hWnd = CreateWindow (MAKEINTATOM(atom), wndClass.lpszClassName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_DESKTOP, NULL, hInstance, NULL))) return 1;

    ShowWindow (hWnd, nShowCmd);
    UpdateWindow (hWnd);

    while (GetMessage (&msg, NULL, WM_NULL, WM_NULL)) {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    UnregisterClass(MAKEINTATOM(atom), hInstance);
    return (int) msg.wParam;
}
  • 이제, Hello World는 찍어봤으니, 이걸 다른걸로 바꿔서 한 번 해보자.
  • 그냥 몇줄 정도 찍어보도록 한다.
#include <stdio.h>
int main(int argc, char* argv[])
{
  for(int loop1 = 0; loop1 < 5; loop1++)
  {
    for(int loop2 = 0; loop2 < 5; loop2++)
      printf("*");
    printf("\n");
  }
  return 0;
}
  • 이렇게, 플로챠트도 필요없을 정도로 단순한 프로그래밍은 이제 다들 할 수 있을거라 생각한다.

연습문제

  • 네모를 봤으면 세모도 찍어봐야지.
  • 세모 별찍기를 해보자.