C++ 使用需要不同上下文菜单的树项更好地设计Qt树视图

C++ 使用需要不同上下文菜单的树项更好地设计Qt树视图,c++,qt,user-interface,C++,Qt,User Interface,我有一个QTreeView对象,此树视图的项可以保存三种类型的数据中的一种,每种类型都需要不同的处理。因此,对于这些类型中的每一种,我需要在用户右键单击时使用不同的上下文菜单。我的树对象如下所示: MyTreeView::MyTreeView(QWidget* parent): QTreeView(parent) { // some code m_init_item_model(); // some code connect(this, SIGNAL(cu

我有一个QTreeView对象,此树视图的项可以保存三种类型的数据中的一种,每种类型都需要不同的处理。因此,对于这些类型中的每一种,我需要在用户右键单击时使用不同的上下文菜单。我的树对象如下所示:

MyTreeView::MyTreeView(QWidget* parent): QTreeView(parent) {

    // some code

    m_init_item_model();

    // some code

    connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
        this, SLOT(make_context_menu(const QPoint&)));

}

void MyTreeView::m_init_item_model() {

    m_itemModel = new QStandardItemModel(this);
    m_itemModel->setHorizontalHeaderLabels(QStringList()
        << "Item Name" << "Item Type");

    this->setModel(m_itemModel);

    // some code

}

这是可行的,但我不确定这是否是一个相当好的方法。现在的问题是,当我在程序中添加对更多类型的支持时,我必须回到这一点并添加更多的
if()
s。嗯,对于这些新类型,我需要不同的上下文菜单,所以可能没有其他方法;但是我不是一个有经验的程序员,所以我想看看解决这个问题的不同方法。

我想出了一个不太糟糕的解决方案,我认为比我在最初的帖子中提到的方法要好。我想分享我的解决方案,因为我认为它可以帮助别人

首先,我为所有要继承的树项创建了一个基类。基类使用枚举枚举可能的/已注册的树项类型

// base_tree_item.h

#include <QStandardItem>

enum TREE_ITEM{

    TYPE1,
    TYPE2,
    TYPE3,
    // etc
    TYPE_COUNT

};

class BaseTreeItem: public QStandardItem {

public:
    BaseTreeItem() = delete;
    BaseTreeItem(TREE_ITEM itemType): m_itemType(itemType) {}

    const TREE_ITEM itemType() const { return m_itemType; }

    virtual ~BaseTreeItem() {}

private:
    TREE_ITEM m_itemType;

};
现在,要构造项目类型专用的自定义上下文菜单:

void TreeView::make_context_menu(const QPoint& pos) {

    m_currentPos = pos;
    QModelIndex firstIndex= this->indexAt(m_currentPos);

    if(firstIndex.isValid()) {
        int row = firstIndex.row();
        m_currentIndex = firstIndex.sibling(row, 0);
        m_currentItem = m_itemModel->itemFromIndex(m_currentIndex);

        BaseTreeItem* currentTreeItem = 
            static_cast<BaseTreeItem*>(m_currentItem);

        TREE_ITEM itemType = currentTreeItem->itemType();

        switch(itemType) {
            case TYPE1:
                make_type1_menu(pos);
                break;
            case TYPE2:
                make_type2_menu(pos);
                break;
            // etc
            default:
                break;
        }
    }

}
// some_type1_item.h

#include "base_tree_item.h"

class SomeType1Item: public BaseTreeItem {

public:
    SomeType1Item(): BaseTreeItem(TREE_ITEM::TYPE1) { //stuff }

};
void TreeView::make_context_menu(const QPoint& pos) {

    m_currentPos = pos;
    QModelIndex firstIndex= this->indexAt(m_currentPos);

    if(firstIndex.isValid()) {
        int row = firstIndex.row();
        m_currentIndex = firstIndex.sibling(row, 0);
        m_currentItem = m_itemModel->itemFromIndex(m_currentIndex);

        BaseTreeItem* currentTreeItem = 
            static_cast<BaseTreeItem*>(m_currentItem);

        TREE_ITEM itemType = currentTreeItem->itemType();

        switch(itemType) {
            case TYPE1:
                make_type1_menu(pos);
                break;
            case TYPE2:
                make_type2_menu(pos);
                break;
            // etc
            default:
                break;
        }
    }

}
void TreeView::make_type1_menu(pos) {

// stuff

MenuType1* newMenu = new MenuType1(//args);
newMenu->exec(mapToGlobal(pos));

}