【问题标题】:what is the proper way to keep track objects on a QTreeView/QStandardItem在 QTreeView/QStandardItem 上跟踪对象的正确方法是什么
【发布时间】:2014-07-09 09:07:26
【问题描述】:

我有一个QTreeView,它在一个根节点下有三个分支

QTreeView treeView_4 = new QTreeView(tab_10);
QStandardItemModel standardModel = new QStandardItemModel ;
QStandardItem *rootNode = standardModel->invisibleRootItem();

QStandardItem Group1Item =  new QStandardItem("Group 1");
QStandardItem Group2Item =  new QStandardItem("Group 2");
QStandardItem Group3Item =  new QStandardItem("Group 3");

rootNode->appendRow(Group1Item);
rootNode->appendRow(Group2Item);
rootNode->appendRow(Group3Item);

我想在创建时列出 Group1/2/3 下的一些对象。当对象的属性发生更改时,我想将它们从一组移动到另一组(例如某些状态更改)。一个对象有两个对 QTreeView 感兴趣的属性:QString IPaddressQString Name(我想在 QtreeView 上显示它们中的任何一个)

最好/正确的方法是什么?

class Object : public QObject
{
    Q_OBJECT
public:
//.... some properties, get and set functions, etc.
    QStandardItem *NodeItemIP;
    QStandardItem *NodeItemName;
private:
   QString Name;
   QString IPaddr;
///....
}

我将对象存储在QVector:QVector<Object*> mObject

我为每个组使用QMap 进行跟踪

QMap<QString, QString> group1MapList;
QMap<QString, QString> group2MapList;
QMap<QString, QString> group3MapList;

当它们附加到QStandardItem 时,insert 将它们添加到 Qmap

group1MapList.insert(mObject[1]->getName(), mObject[1]->getIPaddr());
Group1Item.appendRow(mObject[1]->NodeItemIP);

int index = 0;
QMap<QString, QString>::Iterator it;
for (it=group1MapList.begin(); it != group1MapList.end(); it++){
      if(it.value() == IPAddrToRemove){
      group1MapList.remove(IPAddrToRemove);
      Group1Item->removeRow(index);
      break;
   }
  index++;
}

我注意到QMap(以及QHash)并没有按照添加的顺序存储实体。

是否有任何特殊的类可以根据需要跟踪 QStandardItems,或者我应该使用 QVector 还是其他任何东西?

因为我有两个属性:IPaddrName,我是否需要有两个 QVectors 来跟踪它们或者可以同时处理它们?

注意:如果没有复制+粘贴/编辑错误,那么上面的代码sn-ps的语法应该没问题。

【问题讨论】:

    标签: c++ qt object qtreeview qstandarditem


    【解决方案1】:

    如果您正在使用QTreeView,也许您必须创建自定义数据结构来对数据树进行建模。像这样的:

    struct ModelItem
    {
      QString groupName;
      QString name;
      QString IPaddr;
      ModelItem* parent;
      std::vector< ModelItem* > childs;
    
      ModelItem( const QString& a_name )
        : name( a_name ),
          parent( nullptr )
      { }
    
      ~ModelItem( )
      {
        for ( auto it = childs.begin( ); it != childs.end( ); ++it )
          delete *it;
      }
    
      void AddChild( ModelItem* children )
      {
        childs.push_back( children );
        children->parent = this;
      }
    };
    

    当然,你需要继承QAbstractItemModel

    class CustomModel : public QAbstractItemModel
    {
        Q_OBJECT
    
      public:
    
        CustomModel( QObject* parent = nullptr );
    
        ~CustomModel( );
    
        int columnCount( const QModelIndex& parent ) const override;
    
        int rowCount( const QModelIndex& parent ) const override;
    
        QVariant data( const QModelIndex& index,
                       int role = Qt::DisplayRole ) const override;
    
        QModelIndex index ( int row,
                            int column,
                            const QModelIndex& parent ) const override;
    
        QModelIndex parent( const QModelIndex & index ) const override;
    
        void SetGroup( const QString& groupName,
                       const std::vector< std::pair< QString, QString > >& items );
    
        void ResetModel( );
    
      private:
    
        ModelItem rootNode;
    
    };
    

    columnCount 和 rowCount 方法应返回模型的列数/行数:

    int CustomModel::columnCount( const QModelIndex& /* parent */ ) const
    {
      return 1;
    }
    
    int CustomModel::rowCount( const QModelIndex& parent ) const
    {
    
      int to_return;
    
      if ( parent.isValid( ) )
      {
        ModelItem* node = static_cast< ModelItem* >( parent.internalPointer( ) );
        to_return = node->childs.size( );
      }
      else
        to_return = rootNode.childs.size( );
    
      return to_return;
    }
    

    data 方法应返回模型的内容:

    QVariant CustomModel::data( const QModelIndex& index,
                                int role ) const
    {
      QVariant to_return;
    
      if ( index.isValid( ) ) // if not valid, current index is root node
      {
        switch ( role )
        {
          case Qt::DisplayRole: // you can manage other roles to enrich the view
          {
            ModelItem* node = static_cast< ModelItem* >( index.internalPointer( ) );
            to_return = node->name;
            break;
          }
        }
      }
    
      return to_return;
    }
    

    索引将为给定节点创建适当的QModelIndex

    QModelIndex CustomModel::index ( int row,
                                     int column,
                                     const QModelIndex& parent ) const
    {
      QModelIndex to_return;
    
      if ( ( row >= 0 && row < rowCount( parent ) )
        && ( column >= 0 && column <= columnCount( parent ) ) )
      {
        if ( parent.isValid( ) )
        {
          ModelItem* item = static_cast< ModelItem* >( parent.internalPointer( ) );
          to_return = createIndex( row, column, item->childs.at( row ) );
        }
        else
        {
          to_return = createIndex( row, column, rootNode.childs.at( row ) );
        }
      }
    
      return to_return;
    }
    

    父方法应返回给定节点的父节点的索引

    QModelIndex CustomModel::parent( const QModelIndex & index ) const
    {
      QModelIndex to_return;
    
      if ( index.isValid( ) )
      {
        ModelItem* node = static_cast< ModelItem* >( index.internalPointer( ) );
        ModelItem* parent = node->parent;
        ModelItem* parent2 = parent->parent;
    
        if ( parent2 ) // node->parent can be root node
        {
          auto it = std::find_if( parent2->childs.begin( ), parent2->childs.end( ),
                                  [&]( ModelItem* child ){ return child == parent; } );
    
          if ( it != parent2->childs.end( ) )
          {
            int row = std::distance( parent2->childs.begin( ), it );
            to_return = createIndex( row, 0, parent );
          }
        }
      }
    
      return to_return;
    }
    

    下一个方法:SetGroup。通过这种方法,我们可以将数据添加到模型中:

    void CustomModel::SetGroup( const QString& groupName,
                                const std::vector< std::pair< QString, QString > >& items )
    {
      // Notify to view that we will insert a new group
      beginInsertRows( QModelIndex( ), rootNode.childs.size( ), rootNode.childs.size( ) );
    
      ModelItem* groupNode = new ModelItem( groupName );
      rootNode.AddChild( groupNode );
    
      for ( auto it = items.begin( ); it != items.end( ); ++it )
      {
        ModelItem* node = new ModelItem( it->first );
        node->name = it->first;
        node->IPaddr = it->second;
        groupNode->AddChild( node );
      }
    
      endInsertRows( );
    }
    

    ResetModel 方法只是清理视图:

    void CustomModel::ResetModel( )
    {
      beginResetModel( );
      rootNode= ModelItem( "root" );
      endResetModel( );
    }
    

    模型实现完成后,我们只需要向模型发送数据并链接模型和视图:

    QTreeView* treeView_4 = new QTreeView( tab_10 );
    CustomModel* model = new CustomModel( this );
    
    std::vector< std::pair< QString, QString > > data;
    data.push_back( std::make_pair( "node1", "" ) );
    data.push_back( std::make_pair( "node2", "" ) );
    
    model->SetGroup( "Group 1", data );
    
    data.push_back( std::make_pair( "node3", "" ) );
    model->SetGroup( "Group 2", data );
    
    treeView4->setModel( model );
    

    【讨论】:

    • 但是 OP 询问了 QStandardItemModel,它适用于 QTreeView,不是吗?
    猜你喜欢
    • 2012-11-08
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    相关资源
    最近更新 更多