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

时间:2017-04-16 07:25:48

标签: c++ qt user-interface

我有一个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

}

我目前如何处理不同的上下文菜单,每次右键单击一个项目时,我会查看该QStandardItem项下"Item Type"的名称,然后我将其传递给它通过if() s的过滤器调用不同的函数,为不同类型的项目创建不同的上下文菜单。我的方法如下:

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

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

    if(firstIndex.isValid()) {
        if(firstIndex.parent() == QModelIndex()) { // if it's a top level item
            int row = firstIndex.row();
            m_currentIndex = firstIndex.sibling(row, 0);
            m_currentItem = m_itemModel->itemFromIndex(m_currentIndex);

            QModelIndex flTypeIndex = firstIndex.sibling(row, 1);
            QStandardItem* fileTypeItem = 
                m_itemModel->itemFromIndex(flTypeIndex);
            QString fileType = fileTypeItem->text();

            if(fileType == "Type A") m_make_typeA_context_menu();
            if(fileType == "Type B") m_make_typeB_context_menu();
        }
    }

}

这有效,但我不确定这是否是一种相当好的方式。现在的问题是,当我在程序中添加对更多类型的支持时,我将不得不回到这个并添加更多if()。好吧,我需要为这些新类型提供不同的上下文菜单,所以也许别无他法;但我不是一个经验丰富的程序员,所以我希望在这个问题上看到不同的方法。

1 个答案:

答案 0 :(得分:0)

我想出了一个不太可怕的解决方案,我认为比我在原帖中提到的方法更好。我想分享我的解决方案,因为我认为它可以帮助某人。

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

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

};

现在,每个树项都将继承此基类,并且必须使用类型枚举构造基类。例如,

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

}

对我而言,这似乎是一个更整洁的解决方案。为了做到这一点,可以构建从QMenu派生的类来为每个类型创建菜单对象,如MenuType1,MenuType2等,然后可以使用它们进一步整理:

void TreeView::make_type1_menu(pos) {

// stuff

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

}