2012-10-23 18 views
5

Per esempio posso avere qualcosa di simile così,Struttura dei dati per rappresentare menu che può avere sottomenu

A 
B 
ba 
bb 
C 
Ca 
D 

In questo momento ho una matrice 2D, ma questo non è molto generale, perché avrei bisogno di un'altra dimensione se volessi estendere il massimo sottolivello da 2 a 3. Qualche suggerimento?

+0

Hai bisogno di una relazione ricorsiva. –

+1

Usa un albero? Ogni nodo ha un'etichetta e può avere zero o più figli, generalizzabili a qualsiasi numero di menu nidificati. L'etichetta del nodo radice viene ignorata, vengono considerati solo i suoi figli. – Wug

+0

@Seth Ho capito il tuo commento, ma non sono sicuro di come inserirlo nel codice – dchhetri

risposta

6

Il composite sarebbe un'applicazione appropriato qui:

Composite Pattern

(Da wikipedia :) http://en.wikipedia.org/wiki/Composite_pattern

Nel tuo caso:

  • Creare una classe di base denominata "Menu "(Questo corrisponde alla parte Componente nello schema sopra)
  • creare una classe derivata denominata "MenuItem" (che corrisponde alla parte foglio nella figura sopra)
  • creare una classe derivata denominata "SubMenu" (che corrisponde al composito parte nello schema sopra) Il menu secondario può contenere più Menu, che possono essere più MenuItem o Sottomenu.

È possibile ottenere ordinamento desiderato di elementi del menu in base al loro ordine di inserimento in un composito "sottomenu" mediante l'attuazione di un contatore con ogni oggetto SubMenu: ogni volta che si chiama aSubMenu.add(newMenuItemOrSubMenu), aSubMenu dovrebbe incrementare il proprio contatore e tag il nuovo articolo con il numero di ordinazione. (Particolare esatta della realizzazione dipende da voi, non c'è bisogno di usare contatore separato a tutti e basta usare una lista o un array)

+0

Grazie s.chen. – dchhetri

2

Forse questo:

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 
}; 

Usage:

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); 

che rappresenta:

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

Attenzione il difetto evidente con questo esempio, la dipendenza da addres ses di variabili (probabilmente) temporanee. Non potresti creare questo in una funzione e restituirlo.

Mancano anche parti triviali dell'implementazione, ad esempio non è possibile attraversare lo stato privato dei nodi nel codice di esempio.

+0

Penso che consiglierei la memoria dinamica e 'unique_ptr'. Questa risposta è priva di incapsulamento. Ma questa risposta è l'idea giusta. –

+0

Attendi, no, il vettore dovrebbe contenere direttamente 'MenuNode's. http://ideone.com/kU2RPa –

+0

Funzionerà per tutte le implementazioni di vettori o esistono quelli piani che non usano l'indirezione? – Wug

1

Utilizzare un albero. Questo è meglio definito in un albero comunque.

dove: il rootNode è connesso a A, B, C, D. B è collegato a ba e bb. C è connesso a Ca. eccetera.

enter image description here

1

Il modello di progettazione Composite menzionata da Sampson-chen era il modo giusto per un'implementazione che ho fatto per un piccolo monitor sviluppatori, consentendo di scegliere alcuni metodi di prova da una struttura di menu.

Ho una classe di base "Voce di menu" da cui derivano sottomenu e leafs (le voci di menu). Una foglia esegue semplicemente qualcosa, mentre un sottomenu apre un altro livello di menu.

Per esempio la classe di base potrebbe piacere simile a quello (quando si desidera utilizzare 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; 
    } 

}; 

Nel metodo di selezione a verificare tramite il valore di ritorno, se ho una foglia che esegue qualcosa, o un sottomenu, per il quale devo cambiare i miei suggerimenti.

Per comodità è possibile aggiungere metodi che trovano tutte le voci del menu secondario in un sottomenu per la visualizzazione, o metodi che consentono di creare una riga del titolo con il percorso del menu effettivo o simili ... Un'altra idea sarebbe metodi per scansione dell'albero dei menu per evitare doppie voci di menu asf.

Problemi correlati