2012-10-23 26 views
5

Ví dụ tôi có thể có một cái gì đó giống như vậy,cấu trúc dữ liệu để biểu diễn đơn có thể có menu con

A 
B 
ba 
bb 
C 
Ca 
D 

Right Now Tôi có một mảng 2D, nhưng điều này không phải là rất chung chung, bởi vì tôi sẽ cần một không gian khác nếu tôi muốn mở rộng sublevel tối đa từ 2 đến 3. Bất kỳ đề xuất?

+0

Bạn cần có mối quan hệ đệ quy. –

+1

Sử dụng cây? Mỗi nút có một nhãn và có thể có số không nhiều hoặc nhiều hơn, có thể chung với bất kỳ số lượng menu lồng nhau nào. Nhãn của nút gốc bị bỏ qua, chỉ có con của nó được xem xét. – Wug

+0

@Seth Tôi hiểu bạn bình luận, nhưng tôi không chắc chắn làm thế nào để đưa nó vào mã – dchhetri

Trả lời

6

Các mẫu composite sẽ là một ứng dụng thích hợp ở đây:

Composite Pattern

(Từ wikipedia :) http://en.wikipedia.org/wiki/Composite_pattern

Trong trường hợp của bạn:

  • Tạo một lớp cơ sở gọi là "Menu "(Điều này tương ứng với thành phần trong sơ đồ trên)
  • Tạo một lớp dẫn xuất được gọi là "MenuItem" (Điều này tương ứng với Leaf phần trong biểu đồ trên)
  • Tạo một lớp dẫn xuất được gọi là "menu con" (Điều này tương ứng với composite phần trong biểu đồ ở trên) SubMenu có thể chứa nhiều Menu hơn - có thể là MenuItem hoặc SubMenu hơn.

Bạn có thể đạt được trật tự mong muốn của các yếu tố thực đơn dựa trên trật tự chèn của họ vào một composite "menu con" bằng cách thực hiện một bộ đếm với từng đối tượng menu con: mỗi lần bạn gọi aSubMenu.add(newMenuItemOrSubMenu), aSubMenu nên tăng truy cập riêng của mình và tag mới mục có số thứ tự. (Chi tiết chính xác của việc thực hiện là tùy thuộc vào bạn, bạn không cần phải sử dụng truy cập riêng biệt ở tất cả và chỉ cần sử dụng một danh sách hoặc một mảng)

+0

Cảm ơn bạn s.chen. – dchhetri

2

Có lẽ đây:

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

Cách sử dụng:

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

những đại diện:

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

Hãy coi chừng các lỗ hổng rõ ràng với ví dụ này, sự phụ thuộc vào địa chỉ ses (có thể) biến tạm thời. Bạn sẽ không thể tạo điều này trong một hàm và trả về nó.

Các phần nhỏ của việc triển khai cũng bị thiếu, ví dụ không có cách nào để đi qua trạng thái riêng tư của các nút trong mã mẫu.

+0

Tôi nghĩ tôi muốn giới thiệu bộ nhớ động và 'unique_ptr'. Câu trả lời này thiếu gói gọn. Nhưng câu trả lời này là ý tưởng đúng đắn. –

+0

Chờ, không, vectơ sẽ trực tiếp chứa 'MenuNode'. http://ideone.com/kU2RPa –

+0

Điều đó có hiệu quả đối với tất cả việc triển khai vectơ hay không tồn tại những cái phẳng không sử dụng tính không định hướng? – Wug

1

Sử dụng cây. Điều này được xác định tốt nhất trong một cây anyway.

trong đó: rootNode được kết nối với A, B, C, D. B được kết nối với babb. C được kết nối với Ca. v.v.

enter image description here

1

Các mẫu thiết kế composite được đề cập bởi sampson-chen là cách phù hợp với một thực hiện tôi đã làm cho một màn hình nhà phát triển nhỏ, cho phép bạn chọn một số phương pháp kiểm tra từ một cấu trúc menu.

Tôi có một lớp cơ sở "Menu Entry" mà từ đó tôi lấy được các menu phụ và các lá (các mục trình đơn). Một chiếc lá chỉ thực hiện một cái gì đó, trong khi một menu phụ sẽ mở ra một cấp menu khác.

Ví dụ các lớp cơ sở có thể thích tương tự như (khi bạn muốn sử dụng 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; 
    } 

}; 

Trong phương pháp chọn tôi kiểm tra thông qua giá trị trả về nếu tôi có một chiếc lá mà thực hiện điều gì đó, hoặc một menu phụ, mà tôi phải thay đổi con trỏ của mình.

Để thuận tiện, bạn có thể thêm các phương pháp tìm thấy tất cả các mục menu con trong menu phụ để hiển thị hoặc các phương pháp xây dựng cho bạn dòng tiêu đề với đường dẫn menu thực hoặc tương tự ... quét cây menu của bạn để tránh các mục nhập kép asf.

Các vấn đề liên quan