....................................................................
  OutPut Group Study in API (Application Programming Interface)

  STUDY #6 : Window with Menu in API

                      Typed by Jo.K.M   1997/12/16 01:51
....................................................................
   *  :  참고      >>> :  참고 어휘   pn : 파라미터

   이번에는 윈도에 메뉴를 넣는 법에 대해서 알아보도록 하겠습니다.
   아시겠지만 윈도 App에서 프로그램의 사용법이 나열된 메뉴가 주
   골격이 된다는 것은 의심할 여지가 없습니다.

   이런 메뉴는 API에 있어 생성하는 방법이 크게 두가지로 나뉘게 됩니다.
   한가지 방법은 AppendMenu()라는 함수를 이용해 직접 코드에 메뉴의
   각각 아이템을 추가시키는 방법이고 다른 방법은 이미 간단히 알아본
   리소스라는 파일(*.rc)에 차례차례 기입하는 방식입니다. 물론 후자가
   더 쉽고 알아보기 쉽지만 우리는 하나하나 알아보도록 합시다.

   어느 방식을 쓰던 메뉴 자료형인 HMENU라는 메뉴 핸들을  쓰게 되고
   CreateMenu()를 통해 메뉴 핸들을 얻어오게 됩니다.

     HMENU CreateMenu(VOID);
       메뉴 핸들을 하나 생성해줍니다.

    HMENU GetMenu( HWND hwnd );
      현재 윈도우의 메뉴 핸들을 얻을때 이용합니다.

   BOOL EnableMenuItem( HMENU hmenu, UINT uItem, UINT fuFlags );
      지정한 매뉴핸들에 그레이 속성을 넣거나 해제할때 사용합니다.
     p1 hmenu - 지정한 매뉴 핸들
     p2 uItem - 해당 메뉴 아이템의 아이디
     p3 fuFlags - MF_GRAYED  그레이기능을 넣습니다.
                  MF_ENABLED 그레이기능을 해제합니다.

   DWORD CheckMenuItem( HMENU hmenu, UINT idCheckItem, UINT fuFlags );
      지정한 매뉴핸들에 체크 속성을 넣거나 해제할때 사용합니다.
     p1 hmenu - 지정한 매뉴 핸들
     p2 uItem - 해당 메뉴 아이템의 아이디
     p3 fuFlags - MF_CHECKED  체크표시를 넣습니다.
                  MF_UNCHECKED 체크표시를 해제합니다.


    (1). 코드에서 직접 기입하는 방식
  ============================================

BOOL AppendMenu( HMENU hmenu, UINT fuFlags, UINT idNewItem, LPCSTR lpszNewItem );
    메뉴핸들에 하나의 메뉴 아이템을 추가 합니다.
     p1 hmenu - 얻어온 핸들 지정
     p2 fuFlags - 메뉴의 속성을 지정합니다.
            MF_BITMAP 그림을 이용하여 메뉴 아이템을 만들때
            MF_CHECKED 체크가 표시 되어있는 메뉴 아이템을 만들때
            MF_GRAYED 그레이된 메뉴 아이템을 만들때
            MF_POPUP 팝업 메뉴를 갖은 메뉴 아이템을 만들샔
            MF_SEPARATOR 메뉴를 생성하지 않고 경계선을 만들샔
            MF_STRING 문자열을 메뉴로 사용할때 사용합니다.
     p3 idNewItem - 아이디를 저정합니다.
     p4 lpszNewItem - 실제로 유저에게 보여지는 메뉴 아이템의 이름 ("File open")

    .......<apimenu.c>...........................................
     HMENU hMenu,hPopup;
          :
     hMenu = CreateMenu();
     hPopup = CreateMenu();

     AppendMenu( hPopup, MF_STRING, 100, "&Open");
     AppendMenu( hPopup, MF_STRING, 110, "&Save As");
     AppendMenu( hPopup, MF_SEPARATOR, NULL, NULL);
     AppendMenu( hPopup, MF_STRING | MF_CHECKED, 120, "&Checked");
     AppendMenu( hPopup, MF_STRING | MF_GRAYED, 130, "&Grayed");

     AppendMenu( hPopup, MF_STRING | MF_POPUP, (UINT)hPopup, "&File");

     hPopup = CreateMenu();

     AppendMenu( hPopup, MF_STRING, 140, "C&opy");
     AppendMenu( hPopup, MF_STRING, 150, "&Paste");

     AppendMenu( hPopup, MF_STRING | MF_POPUP, (UINT)hPopup, "&Edit");

      hWnd = CreateWindow(
             szAppName,
             szAppName,
             WS_OVERLAPPEDWINDOW,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             NULL,
             hMenu,                // 윈도 생성시 메뉴를 등록시킵니다.
             hInstance,
             NULL
      );
    ............................................................

     윈도의 속성을 정해주는 WNDCLASS 즉,윈도클래스에있는

       WndClass.lpszMenuName = NULL;

     인 이유는 AppendMenu라는 것이 윈도클래스 등록후 하는 추가적인
     작업이기에 초기화를 NULL로 한것이다. 이 추가적인 메뉴는 일맞게
     hMenu핸들로 작성된후 CeateWindow()함수에서 다시 p9 메뉴에
     등록하게 됩니다.

    (2). 리소스를 이용한 방식
  ===============================================

   .......<menu.rc>.............................
    #include <windows.h>

    MyMenu MENU
    BEGIN
        POPUP "&File"
        BEGIN
            MENUITEM "&Open", 100
            MENUITEM "&Save As", 100
            MENUITEM SEPARATOR
            MENUITEM "&Check",120,CHECKED
            MENUITEM "&Grayed",130,GRAYED
        END
        POPUP
            MENUITEM "C&opy",140
            MENUITEM "&Paste",150
        END
    END
    ............................................

    .....<menu.c>...............................
         :
    WndClass.lpszMenuName = "MyMenu";
         :
    ............................................

     거의 설명이 필요 없을 정도로 보기 쉬워 진것을 여러분들도
     볼수 있을 것입니다. 리소스 분석은 넘어가고 c에서 이번에는
     이미 리소스에서 메뉴판을 만들었기에 이 메뉴판의 이름인
     MyMenu를 처음 윈도 클래스 속성 지정시 메뉴이름으로 만들면
     메뉴가 만들어 지게 됩니다. 물론 이미 윈도 클래스에서 메뉴판
     이 설정 되었기에 CreateWindow()함수에서의 메뉴 핸들은 NULL
     로 될 것입니다.

      hWnd = CreateWindow(
             szAppName,
             szAppName,
             WS_OVERLAPPEDWINDOW,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             NULL,
             NULL,
             hInstance,
             NULL
      );

      정말 그런가 보십시요 맞지요?

    (3). WM_COMMAND
  =======================================================

     이 메세지는 유저가 App 메뉴판의 메뉴아이템 하나를 눌렀다면
     발생하는 메세지 입니다. 따라서 우리는 이 메세지를 이용해서
     메뉴 설정에 맞게 코드를 해야 겠지요?

     아참 이 메세지는 wParam에 유저가 누른 메뉴 핸들 값을 저장하
     고 있습니다. 다음은 WM_COMMAND에 관련된 코드 입니다.

     ......< menu.c WINPROC >................................
     static BOOL bGrayed,bCheck;
           :
     case WM_COMMAND: switch(LOWORD(wParam))
                      {
                        case 100:
                        case 110:
                            hMenu = GetMenu;
                            if(!bGrayed)
                                EnableMenuItem(hMenu,130,MF_ENABLED);
                            else
                                EnableMenuItem(hMenu,130,MF_GRAYED);
                            bGrayed = !bGrayed;
                            break;

                        case 120:
                            hMenu = GetMenu(hWnd);
                            if(!bCheck)
                                CheckMenuItem(hMenu,120,MF_UNCHECKED);
                            else
                                CheckMenuItem(hMenu,120,MF_CHECKED);
                            bCheck = !hCheck;
                            break;
                      }
                      return FALSE;
      ...............................................................

    (4). 메뉴판 모양 내기
   ===============================================

     - 메뉴판에 그림 넣기

       리소스 파일
       .....<menu.rc>..........................
       #nclude <windows.h>

       FileBitmap BITMAP file.bmp
       OpenBitmap BITMAP open.bmp
       SaveBitmap BITMAP save.bmp
       ........................................

       .....<menu.c>...........................
       HMENU hMenu,hPopup;
       HBITMAP hFileBitmap,hOpenBitmap,hSaveBitmap;
         :
       hFileBitmap = LoadBitmap(hInstance, "FileBitmap);
       hOpenBitmap = LoadBitmap(hInstance, "FOpenBitmap);
       hSaveBitmap = LoadBitmap(hInstance, "FSaveBitmap);

       hMenu = CreateMenu();
       hPopup = CreateMenu();

       AppendMenu( hPopup, MF_BITMAP, 100, (const char *)hOpenBitmap);
       AppendMenu( hPopup, MF_BITMAP, 110, (const char *)hSaveBitmap);
       AppendMenu( hMenu, MF_BITMAP|MF_POPUP,(UINT)hPopup, (const char *)hFileBitmap);

      hWnd = CreateWindow(
             szAppName,
             szAppName,
             WS_OVERLAPPEDWINDOW,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             NULL,
             hMenu,                // 윈도 생성시 메뉴를 등록시킵니다.
             hInstance,
             NULL
      );
      ...........................................

     - 시스템 메뉴 만들기

       HMENU GetSystemMenu( HWND hwnd, BOOL fRevert );

       p2는 대부분 FALSE가 들어갑니다.

       .....<sysmenu.c>................................
       HWND hMenu;
        :
       hMenu = GetSystemMenu(hWnd, FALSE );

       AppendMenu(hMenu, MF_SEPARATOR,NULL,NULL);
       AppendMenu(hMenu, MF_STRING,100,"c:\\hnc\\doc\\test1.hwp");
       AppendMenu(hMenu, MF_STRING,200,"c:\\hnc\\doc\\test2.hwp");
         :
       // WNDPROC

       case WM_SYSCOMMAND :
             switch(LOWORD(wParam))
             {
                case 100:
                case 200:
                 break;
             }
            break;                     // 주의  return FALSE가 아닙니다.
       ................................................

      * 만일 시스템 메세지를 다음과 같이하면 윈도 크기 조절을 불가하게 합니다.
          case WM_SYSCOMMAND: if((LOWORD(wParam)&0xfff0)==SC_MOVE)
                              return FALSE;
                              break;

    (5). 악셀 레이터 구현하기
   =========================================

    악셀레이터는 App의 단축키입니다. 왜 있지요? Ctrl+C 누르면 블럭 복사라느
    니 그런거 말입니다. 이런 일을 하기 위해서는 다음과 같은 함수가 필요하지요

    HACCEL LoadAccelerators(HINSTANCE hinst, LPCSTR lpTableName );
      악셀레이터 핸들을 얻는 함수 입니다. p2는 엑셀레이터 이름 문자열입니다.

    int TranslateAccelerator( HWND hwnd, HACCEL haccel, LPMSG lpmsg );
       메세지 발생시 이 메세지가 악셀레이터 메세지 인가를 분별한후 악셀레이터
       메세지가 아니라면 1이아닌 값을 리턴 합니다.

   .......<accel.rc>.............................
    #include <windows.h>

    MyMenu MENU
    BEGIN
        POPUP "&File"
        BEGIN
            MENUITEM "&Open", 100
            MENUITEM "&Save As", 100
            MENUITEM SEPARATOR
            MENUITEM "&Check",120,CHECKED
            MENUITEM "&Grayed",130,GRAYED
        END
        POPUP
            MENUITEM "C&opy",140
            MENUITEM "&Paste",150
        END
    END

    MyAccel ACCELERATORS
    BEGIN
        "O",100,VIRKEY,ALT           // Alt+O누르면 아이디 100 메뉴아이템호출
        "S",110,VIRKEY,CONTROL       // Ctrl+S시 아이디 110 메뉴아이템호출
        VK_F2,120,VIRKEY             // F2 시 아이디 100 메뉴 아이템 호출
    END
    ............................................
    ....<accel.c>...............................
     HACCEL hAccel;
      :
     hAccel = loadAccelerators(hInstance, "MyAccel");
      :
     while(GetMessage(&msg,NULL,0,0))
     {
        if(!TranslateAccelerator(hWnd,hAccel,&msg))
        {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
        }
     }
    ..............................................

    (6). 데스크탑 팝업 메뉴
  ==============================================

    App 윈도 상에서 창안 어디서든 오른 버튼을 누르면 조그만 메뉴가
    나오는 것을 볼 수 있습니다. 이것을 데스크탑 메뉴라고 하는데
    이런 구현을 위해서는 다음과 같은 함수들이 필요하지요.

    HMENU CreatePopupMenu(VOID);
      팝업메뉴의 핸들을 얻어오는 함수입니다. 이것으로 만든 팝업 메뉴를
      AppendMenu()를 통해 팝업 메뉴의 아이템을 만듭니다.

    BOOL ClientToScreen( HWND hwnd, LPPOINT lppt );
      클라이언트의 영역 좌표를 윈도 데스크탑 화면 좌표로 바꾸어 주는
      역활을 합니다. 이것이 필요한 이유는 데스크탑 팝업 메뉴함수의
      좌표가 클라이언트 좌표가 아니라 윈도 데스크탑 좌표이기 때문이지요

    BOOL TrackPopupMenu( HMENU hmenu, UINT fuFlags, int x, int y,
                         int nReserved, HWND hwnd, LPCRECT lprc );
       실제 팝업 메뉴를 나타냅니다.
       p1 hmenu - 메뉴 핸들
       p2 fuFlags - 보통 NULL
       p3-p4 - 윈도 데스크 탑 전체 좌표 >>> ClientToScreen()
       p5 nReserved - 보통 NULL
       p6 hwnd - 윈도 핸들
       p7 lprc - 보통 NULL

    다음은 오른 버튼을 클릭할 경우 데스크 탑 메뉴가 나오는 예제입니다.
    .......<popupmenu.c WNDPROC>.....................................
     POINT pt;
     static HMENU hMenu;
         :
     case WM_RBUTTONDOWN: hMenu = CreatePopupMenu();
                          AppendMenu( hMenu, MF_STRING, 100, "Popup&1");
                          AppendMenu( hMenu, MF_STRING, 200, "Popup&2");
                          pt.x = LOWORD(lParam);
                          pt.y = HIWORD(lParam);
                          ClientToScreen(hWnd,&pt);
                          TrackPopupMenu(hMenu,NULL,ptx,pt.y,NULL,hWnd,NULL);
                          return FALSE;
    ..................................................................

'KB > MFC/Win32' 카테고리의 다른 글

[api] 폰트크기,프린트  (0) 2004.03.19
텍스트 크기 알기  (0) 2004.03.19
STUDY #4 : HDC  (0) 2004.03.19
STUDY #3 : Icon & Cursor by USER & TIMER  (0) 2004.03.19
STUDY #2 : Basic Message & Window treatment in WNDPROC  (0) 2004.03.19

+ Recent posts