C++ 带有QStackedWidget的层次QTreeView映射

C++ 带有QStackedWidget的层次QTreeView映射,c++,qt,C++,Qt,我正在创建一个UI,其中QTreeView表示项目列表(可能有子项,也可能没有子项),并使用QStackedWidget在右侧显示相应的小部件。以前,我的数据或上面提到的项目列表的行为是扁平的,因此我使用QListView,但当数据必须有子项时,我用QTreeView替换了QListView,这样我也可以添加子项。我通过以下方式实现了上述目标: for(std::vector<AWidget* >::iterator it=widgets.begin(); it!=widgets.e

我正在创建一个UI,其中QTreeView表示项目列表(可能有子项,也可能没有子项),并使用QStackedWidget在右侧显示相应的小部件。以前,我的数据或上面提到的项目列表的行为是扁平的,因此我使用QListView,但当数据必须有子项时,我用QTreeView替换了QListView,这样我也可以添加子项。我通过以下方式实现了上述目标:

for(std::vector<AWidget* >::iterator it=widgets.begin(); it!=widgets.end(); ++it)
            { 
                AWidget* w = *it;
                QStandardItem *parent = new QStandardItem(w->Name());
                model->setItem(i, 0, parent);

                QWidget *PageWidget = w->getWidget();
                QScrollArea * pScrollArea = new QScrollArea();
                pScrollArea->setWidget(PageWidget);
                m_ui.AStackedWidget->addWidget(pScrollArea);

                if(!w->hasChildren())
                    {
                    std::vector<AWidget*> children = w->getChildren();

                    for(std::vector<AWidget*>::iterator iChild=children.begin(); iChild!=children.end(); ++iChild)
                        {
                        AWidget* childWidget = *iChild;
                        QStandardItem *child = new QStandardItem(childWidget->Name());

                        parent->appendRow(child);
                        QWidget *childPageWidget = childWidget->getWidget();
                        QScrollArea * pChildScrollArea = new QScrollArea();
                        pChildScrollArea->setWidget(childPageWidget);
                        pChildScrollArea->setWidgetResizable(true);
                        m_ui.AStackedWidget->addWidget(pChildScrollArea);

                        }
                    }
                i++;
            }
            m_ui.ATreeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
            m_ui.ATreeView->setTabKeyNavigation(true);
            m_ui.ATreeView->setModel(model);

            QModelIndex index = m_ui.ATreeView->model()->index(0,0);
            QItemSelectionModel * selModel = m_ui.ATreeView->selectionModel();
            if(selModel)
            {
                connect(selModel, SIGNAL( currentChanged(const QModelIndex &, const QModelIndex &) ), this , SLOT(slotOptionSelectedForChangeUI(const QModelIndex & )) );

                selModel->select(index,QItemSelectionModel::Select);
            }
            slotOptionSelectedForChangeUI(index);

Definition of slotOptionSelectedForChangeUI() is as follows:

    void slotOptionSelectedForChangeUI(const QModelIndex & indx)
            {
                int rowNum = indx.row();
                if(m_ui.AStackedWidget)
                    m_ui.AStackedWidget->setCurrentIndex(rowNum);
            }

A、 B、C、D、E在QStackedWidget的右侧显示正确的对应小部件。但是E1、E2、E3、E4、E5、E6、E7分别显示widget1、2、3、4、5、6、7。这意味着E1的索引再次从0开始,堆叠的小部件显示索引0的widget0,以此类推。E1-E7应如何与widget6-12映射,以便在右侧堆叠的小部件上显示正确的小部件?

正确的方法是不使用
QStackedWidget,而只显示一个。要做到这一点,您只需:

  • 使用将小部件添加到项目中
  • 在ui中,不要使用
    QStackedWidget
    ,只需使用简单的
    QWidget
    (具有无边距的水平/垂直布局)
  • 将selection model index changed信号连接到从简单小部件中删除所有子部件的插槽,并添加与该项一起存储的子部件。您可以使用函数(或模型数据函数)检索它
  • 以下是这些步骤的一个简单示例:

    #define MyRole Qt::UserRole + 42
    
    //...
    
    //adding the item   
    AWidget* w = *it;
    QStandardItem *parent = new QStandardItem(w->Name());
    parent->setData(QVariant::fromValue(w), MyRole);
    model->setItem(i, 0, parent);
    
    //...
    
    //the index changed slot
    void slotOptionSelectedForChangeUI(const QModelIndex & indx)
    {
        AWidget *w = model->data(index, MyRole).value<AWidget*>();//will internally call QStandardItem::data
    
        //remove old children
        QList<QWidget*> children = m_ui.containerWidget->findChildren<QWidget*>(QString(), Qt::FindDirectChildrenOnly);
        foreach(QWidget *child, children)
            child->deleteLater();
    
        //add the new one       
        QWidget *PageWidget = w->getWidget();
        ScrollArea * pScrollArea = new QScrollArea(m_ui.containerWidget);
        pScrollArea->setWidget(PageWidget);
        m_ui.containerWidget->layout()->addWidget(pScrollArea);
    }
    
    #定义MyRole Qt::UserRole+42
    //...
    //添加项目
    AWidget*w=*it;
    QStandardItem*parent=新的QStandardItem(w->Name());
    父->设置数据(QVariant::fromValue(w),MyRole);
    模型->设置项(i,0,父项);
    //...
    //索引已更改插槽
    为变更UI选择的无效槽位(常数QModelIndex和indx)
    {
    AWidget*w=model->data(index,MyRole).value();//将在内部调用QStandardItem::data
    //搬走年迈的孩子
    QList children=m_ui.containerWidget->findChildren(QString(),Qt::FindDirectChildrenOnly);
    foreach(QWidget*子项,子项)
    child->deleteLater();
    //添加新的
    QWidget*PageWidget=w->getWidget();
    ScrollArea*pscrollara=新的QScrollara(m_ui.containerWidget);
    pscrolrea->setWidget(页面widget);
    m_ui.containerWidget->layout()->addWidget(pscrolrea);
    }
    
    我还没有完全实现上述逻辑,但只是出于好奇,在问题中提到的示例中,SLOTOPIONSELECTED FORCHANGEI中的indx是否会为E1给出5或0?它将是0。因为这就是
    QModelIndex
    的工作原理。但是,返回的索引将有一个
    父项
    ,父项行将是4,即E项。模型索引总是描述与其父项相关的行和列。是的,因此需要添加额外的逻辑来计算平面索引,在这种情况下,E1为5。还有,如果D也有像D1和D2这样的孩子呢。在这种情况下,E1应该是0+4(父项)+2(从D1,D2)+1=7。好的,在加入这个逻辑之后,我想它会很好地工作。为什么你想要一个“平面索引”?在我的例子中,你不需要它。对树模型使用平面索引是错误的。如果需要,则应该提供某种映射。
    #define MyRole Qt::UserRole + 42
    
    //...
    
    //adding the item   
    AWidget* w = *it;
    QStandardItem *parent = new QStandardItem(w->Name());
    parent->setData(QVariant::fromValue(w), MyRole);
    model->setItem(i, 0, parent);
    
    //...
    
    //the index changed slot
    void slotOptionSelectedForChangeUI(const QModelIndex & indx)
    {
        AWidget *w = model->data(index, MyRole).value<AWidget*>();//will internally call QStandardItem::data
    
        //remove old children
        QList<QWidget*> children = m_ui.containerWidget->findChildren<QWidget*>(QString(), Qt::FindDirectChildrenOnly);
        foreach(QWidget *child, children)
            child->deleteLater();
    
        //add the new one       
        QWidget *PageWidget = w->getWidget();
        ScrollArea * pScrollArea = new QScrollArea(m_ui.containerWidget);
        pScrollArea->setWidget(PageWidget);
        m_ui.containerWidget->layout()->addWidget(pScrollArea);
    }