2012-10-23 12 views
5

Na przykład mogę mieć coś takiego tak,Struktura danych do menu, które może mieć podmenu

A 
B 
ba 
bb 
C 
Ca 
D 

reprezentować Right Now mam 2D ​​tablicy, ale nie jest to bardzo ogólne, ponieważ musiałbym inny wymiar gdybym chciał przedłużyć maksymalny poziom podrzędny z 2 do 3. Jakieś sugestie?

+0

Potrzebujesz relacji rekursywnej. –

+1

Użyj drzewa? Każdy węzeł ma etykietę i może mieć zero lub więcej dzieci, generalizowanych do dowolnej liczby zagnieżdżonych menu. Etykieta węzła głównego jest ignorowana, brane są pod uwagę tylko jej dzieci. – Wug

+0

@Seth Rozumiem, że skomentowałeś, ale nie jestem pewien, jak umieścić to w kodzie – dchhetri

Odpowiedz

6

kompozytowy Wzór byłoby odpowiednie zastosowanie tutaj:

Composite Pattern

(z Wikipedii :) http://en.wikipedia.org/wiki/Composite_pattern

w Twoim przypadku:

  • utworzyć klasę bazową o nazwie „Menu "(Odpowiada to części Component na powyższym schemacie)
  • Tworzenie klasy pochodnej o nazwie „MenuItem” (ta odpowiada liści części na powyższym schemacie)
  • Tworzenie klasy pochodnej o nazwie „menu” (ta odpowiada Composite części w powyższym schemacie) SubMenu może zawierać więcej menu - może to być więcej MenuItem's lub SubMenu.

Można osiągnąć pożądany kolejność elementów menu w oparciu o ich kolejności wkładania do kompozytów „podmenu” poprzez wdrożenie licznik z każdego obiektu podmenu: za każdym razem dzwonisz aSubMenu.add(newMenuItemOrSubMenu), aSubMenu powinna zwiększyć swój licznik i oznakować nowy przedmiot z numerem zamówienia. (Dokładna szczegół wykonania jest do ciebie, nie trzeba używać osobnego licznika w ogóle i po prostu skorzystać z listy lub tablicę)

+0

Dziękuję s.chen. – dchhetri

2

Być może w ten sposób:

class MenuNode 
{ 
public: 
    MenuNode(std::string new_label); 
    void Add(MenuNode * new_node); 
private: 
    std::string label; 
    std::vector<MenuNode *> children; // changed to vector to preserve order 
}; 

Zastosowanie:

MenuNode menu("root"), 
     file("File"), 
     edit("Edit"), 
     open("Open..."), 
     close("Close"), 
     save("Save..."), 
     prefs("Preferences"), 
     yes_foo("Activate Foo"), 
     no_foo("Deactivate Foo"); 

menu.Add(&file); 
menu.Add(&edit); 

file.Add(&open); 
file.Add(&close); 
file.Add(&save); 

edit.Add(&prefs); 

prefs.Add(&yes_foo); 
prefs.Add(&no_foo); 

reprezentuje których:

Main Menu 
    File 
    Open... 
    Close 
    Save... 
    Edit 
    Preferences 
     Activate Foo 
     Deactivate Foo 

Strzeż oczywistą wadę z tym przykładzie, poleganie na podczas wizyty ses (prawdopodobnie) zmiennych tymczasowych. Nie można go utworzyć w funkcji i zwrócić.

Brakuje również części trywialnych implementacji, na przykład nie ma możliwości przechodzenia przez prywatny stan węzłów w przykładowym kodzie.

+0

Myślę, że zaleciłbym pamięć dynamiczną i 'unique_ptr'. Na tę odpowiedź brakuje hermetyzacji. Ale ta odpowiedź jest właściwym pomysłem. –

+0

Czekaj, nie, wektor powinien bezpośrednio zawierać 'MenuNode's. http://ideone.com/kU2RPa –

+0

Czy to zadziała dla wszystkich wektorów lub czy istnieją płaskie, które nie używają pośrednictwa? – Wug

1

Użyj drzewa. Najlepiej jest to zdefiniować w drzewie.

gdzie: rootNode jest podłączony do A, B, C, D. B jest podłączony do ba i bb. C jest podłączony do Ca. itp.

enter image description here

1

kompozytowy wzorzec projektowy wspomniane przez Sampson-chen była właściwa droga dla realizacji zrobiłem dla małego monitora deweloperskim, pozwalając wybrać kilka metod badawczych ze struktury menu.

Mam klasę podstawową "Wpis w menu", z której czerpię podmenu i liście (pozycje menu). Liść właśnie wykonuje coś, a podmenu otwiera inny poziom menu.

Na przykład klasa bazowa mogła podoba podobny do tego (jeśli chcesz używać shared_pointers):

/*************************************************************//*! 
* @brief The base class for all menu entry types (sub menus and sub menu entries/items) 
******************************************************************/ 
class MenuEntry : public boost::enable_shared_from_this<MenuEntry> 
{ 

    public: 
    virtual ~MenuEntry(){} 

/**************************************************************//*! 
* @brief Default implementation to add menu entries; has to be re implemented 
* @param[in] newSubMenuEntry - the new menu entry (another sub menu or leaf) 
**************************************************************/ 
virtual void add(boost::shared_ptr<MenuEntry> newSubMenuEntry)=0; 

/*****************************************************************//*! 
* @brief Default implementation for call to menu entries; always returns false 
* @return false - the function has not been re implemented 
****************************************************************/ 
virtual bool call(void) 
{ 
    // the member function has not been re-implemented 
    return false; 
} 

/*****************************************************************************//*! 
* @brief Default implementation, has to be reimplemented 
* @return emptyVector - an empty vector 
*********************************************************************************/ 
virtual std::vector<boost::shared_ptr<MenuEntry> > getChildren(void) 
{ 
    std::vector<boost::shared_ptr<MenuEntry> > emptyVector; 
    return emptyVector; 
} 


/*******************************************************************************//*! 
* @brief Gives a pointer to the parent of the actual menu entry 
* @return m_parent - pointer to the parent 
******************************************************************************/ 
boost::shared_ptr<MenuEntry> parent(void) 
{ 
    return m_parent; 
} 

/***************************************************************************//*! 
* @brief Default implementation for selecting a menu entry 
* @param[in] desiredMenuEntry - the desired menu entry which shall be selected 
* @return notExisting - a pointer to <b>this</b> 
**********************************************************************************/ 
virtual boost::shared_ptr<MenuEntry> select(boost::shared_ptr<MenuEntry> desiredMenuEntry)=0; 

/**************************************************************************//*! 
* <B>Criticality: C0 \n\n</B> 
* @brief Sets a pointer to the parent of new menu entry 
* @param[in] pointerToParent - pointer to the parent 
****************************************************************************/ 
void setParent(boost::shared_ptr<MenuEntry> pointerToParent) 
{ 
    m_parent = pointerToParent; 
} 

/***************************************************************************//*! 
* @brief Default implementation for destroying children 
*****************************************************************************/ 
virtual void destroy(void)=0; 

    protected: 
    /************************************************************************//*! 
    * @brief Constructor for a menu entry (sub menu or leaf) 
    * @param[in] menuEntryName - the name for the sub menu or leaf 
    *************************************************************************/ 
    MenuEntry(std::string menuEntryName) 
    { 
     m_menuEntryName = menuEntryName; 
    } 

}; 

W select sprawdzasz poprzez wartości zwracanej metoda, jeśli mam liścia, która wykonuje coś, lub podmenu, dla którego muszę zmienić swoje wskaźniki.

Dla wygody można dodać metody, które znajdują wszystkie pozycje menu podrzędnego w podmenu do wyświetlania, lub metody, które tworzą linię tytułu z rzeczywistą ścieżką menu lub podobną ... Innym pomysłem byłyby metody skanowanie twojego drzewa menu w celu uniknięcia podwójnych pozycji menu asf.

Powiązane problemy