CURS 7iasimin/pw/C_Menu.pdf · 2006. 4. 7. · CURS 7 Meniurile unei aplicatii. Definire termeni...

56
CURS 7 Meniurile unei aplicatii

Transcript of CURS 7iasimin/pw/C_Menu.pdf · 2006. 4. 7. · CURS 7 Meniurile unei aplicatii. Definire termeni...

  • CURS 7

    Meniurile unei aplicatii

  • Definire termeni

    top-level menu = bara de meniu ce apare in

    partea superioara a ferestrei;

    drop down menu;

    articole din meniu identificate printr-un ID;

    selectia unui articol din meniu = executie

    comanda;

    meniuri popup = meniuri contextuale

    (WM_CONTEXTMENU)

  • Meniu sistem

    redimensionare;

    mutare;

    minimizare;

    maximizare;

    inchidere fereastra;

    restaurare;

  • MFC - CMenu - Creare

    HMENU = tip de data ce gestioneaza un meniu

    in Windows; m_hMenu definit in clasa;

    Cream un obiect CMenu pe stiva;

    Apelam functii membru pentru a lucra cu

    meniul;

    Apelam CWnd::SetMenu() pentru a seta

    meniul la fereastra;

    Apelam functia membru Detach().

  • Exemplu

    CMenu m_Menu;

    m_Menu.LoadMenu(IDR_MENU);

    SetMenu(&m_Menu);

    m_Menu.Detach();

    IDR_MENU ID-ul resursei ce descrie meniul;

  • Exemplu de resursa meniu

    IDR_MENU MENU PRELOAD DISCARDABLEBEGIN

    POPUP “&File”

    BEGIN

    MENUITEM “&New\tCtrl+N”, ID_FILE_NEW

    ...

    MENUITEM SEPARATOR

    END

    POPUP “&View”

    BEGIN

    ...

    END

    END

  • Functii membru CMenu

    BOOL Attach( HMENU hMenu );

    Valoarea returnata != 0 pentru succes; altfel 0.

    Parametrii: hMenu Specifica un handle la un meniu Windows.

    Observatii: Ataseaza un meniu Windows existent la un obiect CMenu. Dacameniul este atasat functia nu trebuie apelata. Handle-rul meniului este memoratin data membru m_hMenu.

    Daca meniul este deja asociat cu o fereastra, putem folosi functiaCWnd::GetMenu pentru a obtine handle la meniu.

    Examplu: (pWnd pointer la fereastra, vezi AfxGetMainWnd())

    CMenu meniu;

    HMENU hMeniu = pWnd->GetMenu( );

    meniu.Attach( hMeniu );

  • Functii membru CMenu

    HMENU Detach( );

    Valoarea returnata: handle, de tip HMENU, la un

    meniu Windows sau NULL daca operatia esueaza.

    Observatie: Detaseaza un meniu Windows dintr-un

    obiect CMenu si returneaza handle-rul. Data

    membru m_hMenu este setata pe NULL.

  • CMenu::FromHandle

    static CMenu* PASCAL FromHandle( HMENU hMenu );

    Valoarea returnata: un pointer la un CMenu; poate fi permanent sautemporar.

    Parametrii: hMenu handle la un meniu.

    Observatii:

    Daca un obiect CMenu nu este deja atasat la obiectul menu Windows, se creaza un obiect temporar CMenu si se ataseaza. In general obiectele temporare nu pot fi memorate pentru a fi utilizatein viitor in aplicatie. Obiectele temporare sunt sterse cand nu existamesaje in coada de mesaje a aplicatiei si atunci se executa functiaOnIdle().

  • CMenu::GetSafeHmenu

    HMENU GetSafeHmenu( ) const;

    Returneaza HMENU continut in obiectul

    CMenu, sau valoarea NULL.

  • CMenu::CreateMenu

    BOOL CreateMenu( );

    Valoarea returnata != 0 in caz de succes; 0 in caz contrar.

    Observatii: Se creaza un meniu si se ataseaza la obiectul CMenu.

    Initial acest meniu este vid. Articolele de meniu pot fi adaugatefolosind functiile membru AppendMenu sau InsertMenu.

    Daca meniul este atribuit la o fereastra, este automat distrus candfereastra este distrusa.

    Inainte de terminare, o aplicatie trebuie sa elibereze resursele sistemasociate cu un meniu daca meniul nu este atribuit la o fereastra. Eliberarea resurselor de meniu se face prin apelul functiei membruDestroyMenu. DestroyMenu este apelata de destructorul obiectului

  • CMenu::CreatePopupMenu

    BOOL CreatePopupMenu( );

    Valoarea returnata != 0 in caz de succes; 0 in caz contrar.

    Observatii: Creaza un meniu pop-up si il ataseaza la un obiectCMenu.

    Initial meniul este vid. Articole de meniu pot fi adaugate folosindfunctiile membru AppendMenu sau InsertMenu.

    Aplicatia poate adauga meniul pop-up la un meniu existent sau un meniu pop-up.

    Functia TrackPopupMenu poate fi folosita pentru a afisa un meniucontextual.

    Aceleasi observatii privitoare la distrugerea meniului ca si la CreateMenu.

  • CMenu::LoadMenu

    BOOL LoadMenu( LPCTSTR lpszResourceName );

    BOOL LoadMenu( UINT nIDResource );

    Valoarea returnata != 0 in caz de succes; 0 altfel.

    Parametrii:

    lpszResourceName Puncteaza la un sir de caractere terminat cu null, sir cecontine numele resursei de meniu ce trebuie incarcata.

    nIDResource ID-ul meniului ce trebuie incarcat.

    Observatii: Incarca o resursa de meniu din fisierul executabil al aplicatiei si o ataseaza la obiectul CMenu.

    Aceleasi observatii privitoare la distrugerea meniului ca si la CreateMenu.

  • CMenu::LoadMenuIndirect

    BOOL LoadMenuIndirect( const void*

    lpMenuTemplate );

    Parametrii: lpMenuTemplate puncteaza la un

    sablon de meniu ce contine o singura structura

    MENUITEMTEMPLATEHEADER si o

    colectie de una sau mai multe structuri

    MENUITEMTEMPLATE.

  • CMenu::DeleteMenu

    BOOL DeleteMenu( UINT nPosition, UINT nFlags );

    Valoarea returnata != 0 in caz de succes; 0 altfel.

    Parametrii: nPosition Specifica articolul de meniu ce va fi sters, functie de valorile lui nFlags.

    nFlags Determina pozitia articolului de meniu.

    MF_BYCOMMAND = nPosition specifica ID-ul articolului de meniu.

    MF_BYPOSITION = nPosition furnizeaza pozitia articolului de meniu. Prima pozitie este la index zero.

    Observatii: Ori de cate ori un meniu al unei ferestre este schimbat, aplicatia trebuie sa apeleze functia CWnd::DrawMenuBar.

  • CMenu::AppendMenu

    BOOL AppendMenu( UINT nFlags, UINT

    nIDNewItem = 0, LPCTSTR lpszNewItem =

    NULL );

    BOOL AppendMenu( UINT nFlags, UINT

    nIDNewItem, const CBitmap* pBmp );

  • AppendMenu - parametri

    nFlags = starea noului articol de meniu, cand este adaugatla meniu (MF_OWNERDRAW, MF_STRING, MF_SEPARATOR).

    nIDNewItem specifica fie ID-ul comenzii noului articol de meniu sau handle la un meniu pop-up (HMENU) dacanFlags are valoarea MF_POPUP. Daca nFlags = MF_SEPARATOR, atunci nIDNewItem este ignorat.

    lpszNewItem = specifica continutul noului articol de meniu. lpszNewItem se interpreteaza functie de valorilelui nFlags.

  • nFlags si lpszNewItem

    MF_OWNERDRAW – vezi mesajeleWM_MEASUREITEM si WM_DRAWITEM. Valoareaasociata meniului se gaseste in itemData din structura ceinsoteste mesajul WM_DRAWITEM. In acest cazlpszNewItem contine o valoare pe 32 biti gestionata de aplicatie.

    MF_STRING lpszNewItem contine textul comenzii.

    MF_SEPARATOR lpszNewItem este ignorat.

    pBmp Puncteaza la un obiect CBitmap ce va fi utilizat ca articol de meniu.

  • nFlags- starea articolelor de meniu

    MF_CHECKED, MF_UNCHECKED

    MF_ENBLE, MF_DISABLE

    MF_GRAYED

  • nFlags- starea articolelor de meniu

    MF_MENUBARBREAK Plaseaza articolul pe o noua linie intr-un meniustatic sau o noua coloana intr-un meniu pop-up. Coloana din noul meniu pop-up va fi separata de vechea coloana de o linie verticala.

    MF_MENUBREAK Plaseaza articolul pe o noua linie in meniurile staticesau in o noua coloana in meniurile pop-up. Nu exista linie de divizare intrecoloane.

    MF_OWNERDRAW Articol desenat de proprietar. Optiunea nu este validapentru articole de meniu top-level.

    MF_POPUP Specifica faptul ca articolul de meniu are un meniu pop-up asociat cu el. Parametrul ID specifica un handle la un meniu pop-up ce va fiasociat cu articolul. Aceasta este folosita pentru adaugarea fie a meniurilor popup top-level sau a unui meniu pop-up ierarhic la un articol de meniu pop-up.

  • Alte functii

    CheckMenuItem Plaseaza sau sterge un check

    mark pe un articol de meniu intr-un meniu pop

    up.

    CheckMenuRadioItem

    EnableMenuItem

    GetMenuItemCount

  • CMenu::GetSubMenu

    CMenu* GetSubMenu( int nPos ) const;

    Valoarea returnata: un pointer la un obiect CMenua carui data membru m_hMenu contine un handle la un meniul pop-up, daca un meniu pop-up exista la pozitia data; altfel NULL. Daca un obiect Cmenu nu exista, se creaya unul temporar. Pointerul returnat nu poate fi memorat pentru utiliyari viitoare.

    Parametrii: nPos – specifica pozitia meniului pop-up continuta in meniu. Indexul incepe cu zero.

  • CMenu::InsertMenu

    BOOL InsertMenu( UINT nPosition, UINT nFlags,UINT nIDNewItem = 0, LPCTSTR lpszNewItem =NULL );

    BOOL InsertMenu( UINT nPosition, UINT nFlags,UINT nIDNewItem, const CBitmap* pBmp );

    Insereaza un nou articol de meniu la pozitia specificata de nPosition. Vezi MSDN pentru informatii suplimentare. Asemanator cu AppendMenu.

  • CMenu::ModifyMenu

    BOOL ModifyMenu( UINT nPosition, UINT nFlags,UINT nIDNewItem = 0, LPCTSTR lpszNewItem =NULL );

    BOOL ModifyMenu( UINT nPosition, UINT nFlags,UINT nIDNewItem, const CBitmap* pBmp );

    Schimba un articol de meniu existent la pozitia specificatade nPosition. Aplicatia specifica noua stare a articoluluide meniu setand valori pentru nFlags.

  • Meniuri multiple

    Create(NULL, _T(“aplicatie”));

    m_menuLong.LoadMenu(IDR_LONGMENU);

    m_menuShort.LoadMenu(IDR_SHORTMENU);

    SetMenu(m_bShortMenu ? &m_menuShort,

    &m_menuLong);

  • Comutarea intre meniuri

    Ca raspuns la o comanda a utilizatorului:

    m_bShortMenu = TRUE;

    SetMenu(&m_menuShort);

    DrawMenuBar();

  • Raspunsuri la comenzi din meniu

    Cind utilizatorul selecteaza un art. de meniu

    (bara de meniuri) fereastra primeste o serie de

    mesaje:

    WM_INITMENU ce notifica ferestrei ca un

    articol al meniului superior (top-level menu

    item) a fost selectat.

  • Raspunsuri ...

    WM_INITMENUPOPUP, locul unde ar putea

    fi actualizate (enable, disable, checked, etc.)

    articolele meniului, meniul inca nu este afisat.

    Cind parcurgem articolele unui meniu drop

    down (popup), fereastra primeste mesajul

    WM_MENUSELECT, mesaj ce poate fi tratat,

    in special in SDK, prin afisarea unui text in

    bara de stare (scurt help).

  • Raspunsuri ...

    WM_COMMAND trimis cind utilizatorul

    selecteaza un articol de meniu.

    LOWORD(wParam) pastreaza ID-ul comenzii

    (art. din meniul popup) si in SDK se face

    practic switch pe LOWORD(wParam) pentru a

    identifica care comanda a fost selectata.

  • Raspunsuri ...

    In MFC se adauga in harta de mesaje a clasei

    respective macroul ON_COMMAND care

    trateaza mesajul WM_COMMAND.

    ON_COMMAND are doi parametri, primul

    indica ID_ul comenzii, iar al doilea indica

    handlerul comenzii (functia ce va fi apelata la

    selectia acestei comenzi).

  • Raspunsuri ...

    Exemplu:

    ON_COMMAND(ID_FILE_SAVE,

    OnFileSave);

    Functiile ce trateaza comenzile de meniu nu nu

    au au parametriparametri si au tipul voidvoid.

  • Intervale pentru comenzi

    Sunt folosite pentru a trata un grup de articole

    de meniu cu o singura functie.

    Pp. ca avem definit un meniu cu urmatoarele

    articole:Rosu, Verde, Albastru;

    Pp. ca pastram culoarea intr-o variabila din

    clasa definita astfel:

    int m_nCuloare; // 0 = R, 1 = V, 2 = A

  • Harta de mesaje

    ON_COMMAND(IDM_ROSU, OnRosu);

    ON_COMMAND(IDM_VERDE, OnVerde);

    ON_COMMAND(IDM_ALBASTRU,

    OnAlbastru);

    Observati ID-urile comenzilor din meniu.

  • Functiile ...

    void CXView::OnRosu()

    { m_nCuloare = 0;}

    void CXView::OnVerde()

    { m_nCuloare = 1;}

    void CXView::OnAlbastru()

    { m_nCuloare = 2;}

  • Neajunsuri

    Daca adaugam o noua culoare va trebui sa

    facem urmatoarele modificari in cod:

    (.h) prototip functie pentru noua culoare;

    (.cpp) modificare harta de mesaje si

    scriere cod pentru noua functie.

    In total trei modificari.

  • Prima imbunatatire - o singura

    functieGrupam aceste comenzi (ID-uri secventiale);

    Obtinem ID-ul comenzii selectate si scadem

    din acesta ID-ul primei comenzi din meniu

    (IDM_ROSU).

  • Harta de mesaje pentru o singura

    functieON_COMMAND(IDM_ROSU, OnCuloare);

    ON_COMMAND(IDM_VERDE,

    OnCuloare);

    ON_COMMAND(IDM_ALBASTRU,

    OnCuloare);

  • Codul functiei OnCuloare

    void CXView::OnCuloare()

    UNIT nID = (UINT)

    LOWORD(GetCurrentMessage()->wParam);

    m_nCuloare = nID – IDM_ROSU;

  • O singura functie, o singura intrare

    in harta de mesajeIn harta de mesaje:

    ON_COMMAND_RANGE(IDM_ROSU,

    IDM_ALBASTRU, OnCuloare);

    Retineti ca avem ID-uri secventiale de

    comenzi, iar variabila m_nCuloare se

    calculeaza ca diferenta intre ID comanda si

    primul ID al comenzilor grupate

    (IDM_ROSU).

  • Actualizarea articolelor intr-un

    meniu

    Metoda 1: actualizare in momentul cind

    articolul este selectat

    void CXView::OnCuloare()

    { CMenu* pMenu = GetMenu();

    pMenu->CheckMenuItem(m_nCuloare + IDM_ROSU,

    MF_UNCHECKED);

    pMenu->CheckMenuItem(nID, MF_CHECKED);

    m_nCuloare = nID – IDM_ROSU;}

  • Actualizarea articolelor ...

    Metoda 2: mutam codul care actualizeaza meniul in

    tratarea mesajului WM_INITMENUPOPUP iar functia

    este OnInitMenuPopup. Aici actualizarea se face

    inainte ca meniul sa fie afisat. Aceasta functie are trei

    parametri: un pointer de tip CMenu ce pointeaza la

    submeniul care va fi afisat, un UINT – valoare ce da

    indexul art din submeniu si o var. BOOL care este # 0

    daca mesajul este al meniului sistem si 0 altfel.

  • Actualizarea articolelor ...

    In harta de mesaje avem:

    ON_WM_INITMENUPOPUP()

    iar functia: (COLOR_MENU_INDEX este o

    variabila ce specifica pozitia meniului Color in

    bara de meniu a aplicatiei) este:

  • Actualizarea articolelor ...

    void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT

    nIndex, BOOL bSysMenu)

    {if (!bSysmenu && (nIndex == COLOR_MENU_INDEX))

    pPopMenu->CheckMenuItem(IDM_ROSU, MF_UNCHECKED);

    pPopMenu->CheckMenuItem(IDM_VERDE, MF_UNCHECKED);

    pPopMenu->CheckMenuItem(IDM_ALBASTRU, MF_UNCHECKED);

    pPopMenu->CheckMenuItem(m_nCuloare + IDM_ROSU,

    MF_CHECKED);

  • Actualizarea articolelor ...

    Un alt mecanism este tot la mesajul WM_INITMENUPOPUP

    si consta in a completa harta de mesaje cu handleri pentru

    comenzi, handleri ce vor fi apelati inainte ca meniul sa fie

    vizibil si inaintea fiecarei selectii din meniu. Fiecarui handler

    de actualizare ii este pasat un pointer la un obiect CCmdUI

    ale carui functii membru pot fi folosite pentru a modifica

    articolul de meniu. Acesti handleri pot fi utilizati si pentru

    actualizarea butoanelor din toolbar si alte obiecte ale interfetei

    UI.

  • Actualizarea articolelor ...

    ON_COMMAND_UPDATE_UI(IDM_ROSU,

    OnUpdateRosu)

    ON_COMMAND_UPDATE_UI(IDM_VERDE,

    OnUpdateVerde)

    ON_COMMAND_UPDATE_UI(IDM_ALBASTRU,

    OnUpdateAlbastru)

    void CMainFrame::OnUpdateRosu(CCmdUI* pCmdUI)

    { pCmdUI->SetCheck(m_nCuloare);}, etc.

  • Alte metode din CCmdUI

    Metode din CCmdUI: Enable, SetCheck, SetRadio (nu

    are echivalent in SDK), SetText.

  • Creare meniu in momentul

    executieiCrearea meniului programatic (at run time)

    CMenu menuMain;

    menuMain.CreateMenu();

    Cmenu menuPopup;

    menuPopup.CreatePopupMenu();

    menuPopup.AppendMenu(MF_STRING, IDM_ROSU, “&Rosu”);

    menuMain.AppendMenu(MF_POPUP, (UINT) menuPopup.Detach(), “&Culori”);

    menuPopup.CreatePopupMenu();

    menuPopup.AppendMenu(MF_STRING, IDM_EXIT, “&Exit”);

    menuMain.AppendMenu(MF_POPUP, (UINT)menuPopup.Detach(), “&Sesiune”);

    SetMenu(&menuMain);

    menuMain.Detach();

  • Modificarea programatica

    Functiile necesare pentru modificare sunt:

    AppendMenu, InsertMenu, ModifyMenu,

    DeleteMenu, RemoveMenu

    Inainte de a modifica un meniu, trebuie sa

    obtinem un pointer la acel meniu cu functia

    CWnd::GetMenu. In top-level menu,

    articolele sunt referite prin indici ce incep cu 0

    (zero) – cel mai din stinga.

  • Operatii

    CMenu* pMenu = GetMenu();

    pMenu-DeleteMenu(1, MF_BYPOSITION); sau

    pMenu->DeleteMenu(IDM_CULORI,

    MF_BYCOMMAND);

    sau item-uri din meniuri

    CMenu* pMenu = GetMenu()-GetSubMenu(1);

    pMenu->DeleteMenu(IDM_VERDE,

    MF_BYCOMMAND);

  • sau echivalent

    CMenu* pMenu = GetMenu();

    pMenu->DeleteMenu(IDM_VERDE,

    MF_BYCOMMAND);

  • Meniul sistem

    CMenu* pSysMenu = GetSystemMenu(FALSE);

    FALSE = inseamna ca dorim un pointer la o copie a

    meniului sistem pe care vrem sa-l modificam. TRUE =

    reseteaza meniul sistem la starea sa implicita.

    pSysMenu->AppendMenu(MF_SEPARATOR);

    pSysmenu->AppendMenu(MF_STRING,

    IDM_COMANDA_NOUA, _T(“&Comanda

    adaugata”));

  • Meniul sistem

    in harta de mesaje avem:

    ON_WM_SYSCOMMAND()

    (.cpp) void CMainFrame::OnSysCommand(UINTnID, LPARAM lPram)

    { if ((nID & 0xFFF0 ) == IDM_COMANDA_NOUA)

    { // ceva }

    CFrameWnd::OnSysCommand(nID, lParam);}

  • Meniuri contextuale

    CMenu::TrackPopupMenu afiseaza un asemenea meniu.

    BOOL TrackPopupMenu(UINT nFlags, int x, int y, CWnd* pWnd,

    LPRECT lpRect = NULL)

    x, y = locatia pe ecran (coordonate ecran) unde va apare meniul;

    nFlags = informatii despre alianiamentul relativ la x

    (TPM_LEFTALIGN, TPM_CENTERALIGN, TPM_RIGHTALIGN)

    si care buton este utilizat in continuare pt a face o selectie

    (TPM_LEFTBUTTON, TPM_RIGHTBUTTON).

    pWnd = identifica fereastra care va primi mesajul dupa selectia unei

    comenzi din meniu;

    lpRect = dimensiunea unui dreptunghi (coord. ecran) in care

    utilizatorul poate face clic fara a anula meniul afisat.

  • Meniu contextual

    CMenu menu;

    menu.LoadMenu(IDR_CONTEXTMENU);

    CMenu* pContextMenu =

    menu.GetSubMenu(0);

    pContextMenu->TrackPopupMenu

    (TPM_LEFTALIGN | TPM_LEFTBUTTON,

    point.x, point.y, AfxGetMainWnd());

  • WM_CONTEXTMENU

    in harta de mesaje avem macroul:

    ON_WM_CONTEXTMENU si functia

    afx_msg OnContextMenu(CWnd* pWnd,

    CPoint point);

    pWnd = identifica fereastra in care s-a facut

    clic si point coordonatele punctului unde s-a

    facut clic.

  • WM_CONTEXTMENU

    Procesarea comenzilor. Flagul TPM_RETURNCMD = folosit la obtinerea unui

    raspuns la apelul unui meniu contextual.

    int nCmd = (int) pContextMenu->TrackPopupMenu(TPM_RETURNCMD...

    switch(nCmd)

    {

    case IDM_CONTEXT_1:

    break;

    ...

    }

    Un meniu afisat in acest mod va genera mesaje WM_COMMAND cind un articol

    este selectat.