为啥不同的treeItems链接到相同的数据

Posted

技术标签:

【中文标题】为啥不同的treeItems链接到相同的数据【英文标题】:why are different treeItems linked to the same data为什么不同的treeItems链接到相同的数据 【发布时间】:2019-08-18 04:39:31 【问题描述】:

我一直在尝试将树项及其子树复制到树视图中的另一个位置。

我终于可以成功地移动它们了。

treeItem 的头文件

class TreeItem

public:
    explicit TreeItem( Container *data , TreeItem *parent = 0 );
    ~TreeItem();
    TreeItem *parent();
    void appendChild(TreeItem *child);
    TreeItem& operator = (const TreeItem &item);
    TreeItem *child(int iNumber);
    int childCount() const;
    int childNumber() const;
    Container data() const ;
    Container* GetContainer();
    bool setData(Container* data , QVariant value);
    void setContainer( Container* data);
    bool insertChildren(int position, int count );
    bool removeChildren( int position  , int count );
    void removeChild(int row);
    void removeChild(TreeItem* itm);
    QList<TreeItem*> children();
    std::string getChildName(int row);
    std::string getName();
    int row() const;
    void insertChild(int pos, TreeItem *child);

private:
    QList<TreeItem*> childItems;
    Container* itemData;
    TreeItem* parentItem;
;

treeItem 的 Cpp 文件

TreeItem::TreeItem( Container *data, TreeItem *parent )

    parentItem = parent;
    itemData = new Container;
    *itemData = *data;  

TreeItem::~TreeItem()
   
    if (itemData != nullptr)
    
        delete itemData;
       
    qDeleteAll(childItems);

TreeItem& TreeItem::operator = (const TreeItem &item)

    qDebug() << "TreeItem operator called";
//  if( this->itemData == nullptr)
//      this->itemData = new Container;

    *this->itemData = *item.itemData;
    this->childItems = item.childItems;
    this->parentItem = item.parentItem;
    return *this;

TreeItem *TreeItem::parent()

    return parentItem;

TreeItem *TreeItem::child(int iNumber)

    return childItems.value(iNumber);

int TreeItem::childCount() const 

    return childItems.count();

int TreeItem::childNumber() const

    if (parentItem)
        return parentItem->childItems.indexOf(const_cast<TreeItem*> (this));

    return 0;

Container TreeItem::data() const

    return *itemData;

bool TreeItem::setData( Container* data , QVariant value )

    //*itemData = *data;  // Do Not !!!! uncomment this ///////////////////////////as it will set the value of default container constructor.
    itemData->SetName(value.toString().toStdString() );
    return true;

bool TreeItem::insertChildren(int position, int count)

    if (position < 0 || position > childItems.count())
        return false;

    Container cont;
    TreeItem *item = new TreeItem(&cont, this);
    childItems.insert(position, item);

    return true;

bool TreeItem::removeChildren(int position, int count)

    if (position < 0 || position > childItems.count())
        return false;

    for (int row = 0; row < count; ++row)
    
        delete childItems.takeAt(position);
    

    return true;

void TreeItem::setContainer( Container* cont)

    *itemData = *cont;  

void TreeItem::appendChild(TreeItem *node)

    childItems.append( node );

int TreeItem::row() const

//  qDebug() << "The child count = " << parentItem->childItems.indexOf(const_cast<TreeItem*>(this));

    if (parentItem)
    return parentItem->childItems.indexOf( const_cast<TreeItem*>(this) );

    return 0;

void TreeItem::removeChild(int row)
   
    //   qDebug() << "The Row Number" << row;
     //  childItems.removeAt(row);
       delete childItems.takeAt(row);     

void TreeItem::insertChild(int pos, TreeItem *child)

    childItems.insert(pos, child);
    child->parentItem = this;

void TreeItem::removeChild(TreeItem* itm)

    childItems.removeOne(itm);

std::string TreeItem::getChildName(int row)

    return childItems.value(row)->getName();

std::string TreeItem::getName()

    return itemData->GetName();

Container* TreeItem::GetContainer()

    return itemData;

QList<TreeItem*> TreeItem::children()

    return  childItems;

这是我为树结构中树项的子容器构建树的函数。

void TreeModel::buildTree(TreeItem * pItem, QDataStream & ds) const

    if (pItem == NULL)
        return;

     ds << reinterpret_cast<qlonglong>(pItem);
     ds << pItem->childCount();
     foreach(TreeItem* childItem, pItem->children())
     
         buildTree(childItem, ds);
     

这是在 Drop mime data 函数中,我在其中恢复了容器的子树。

// count is the number of child containers of the tree item
TreeItem *node;
    //qDebug() << "The row" << row << parentNode->data().GetName().c_str() ;
    for (int i = 0; i < count; ++i) 
        // Decode data from the QMimeData
        qlonglong nodePtr;
        int childCount;
        stream >> nodePtr;
        stream >> childCount;
        node = reinterpret_cast<TreeItem *>(nodePtr);
        // Adjust destination row for the case of moving an item
        // within the same parent, to a position further down.
        // Its own removal will reduce the final row number by one.
        if (node->row() < row  && parentNode == node->parent())
            --row;

        TreeItem *nodeNew = new TreeItem(node->GetContainer(), node->parent());
        nodeNew->setContainer(node->GetContainer());        
        // Insert at new position
        //qDebug() << "Inserting into" << parent << row;
        beginInsertRows(parent, row, row);
        parentNode->insertChild(row, nodeNew);          
        endInsertRows();
        for (int k = 0; k < childCount; k++)
        
            restoreTree(stream, nodeNew);
        

        ++row;      
    

这是恢复子树的函数。

TreeItem * TreeModel::restoreTree(QDataStream & ds , TreeItem* parent) const

    Container cont;

    // Restore the info from the stream
    int childCount;     
    qlonglong nodePtr;          
    ds >> nodePtr;
    ds >> childCount;       
    TreeItem *currentItem = reinterpret_cast<TreeItem *>(nodePtr);
    if (currentItem == nullptr)
        return nullptr;

    TreeItem *thisItem = new TreeItem(currentItem->GetContainer(), currentItem->parent() );
    thisItem->setContainer(currentItem->GetContainer());
    //*thisItem = *currentItem;
    parent->appendChild(thisItem);
    for (auto nChild = 0; nChild < childCount; ++nChild)
    
       TreeItem* oldChild = restoreTree(ds, thisItem);          
        if (oldChild != nullptr)
        
            TreeItem *pChild = new TreeItem( oldChild->GetContainer() , oldChild->parent() );
            pChild->setContainer(oldChild->GetContainer());
            thisItem->appendChild(pChild);
            qDebug() << "Appending child";
        
    
    return thisItem;

树以正确的方式恢复。

但是现在我有一个问题,旧位置的树项和新位置的树项链接在一起,如果我对旧位置的树项进行任何更改,它也会影响新位置的树项。

【问题讨论】:

【参考方案1】:

改变父级->appendChild(thisItem); to parent->insertChild(row, thisItem);现在解决了这个问题,BuildTree 函数有效。

TreeItem * TreeModel::restoreTree(QDataStream & ds , TreeItem* parent , int row) const

    Container cont; 
    // Restore the info from the stream
    int childCount;     
    qlonglong nodePtr;
    QModelIndex parentIndex;
    ds >> nodePtr;
    ds >> childCount;

    TreeItem *currentItem = reinterpret_cast<TreeItem *>(nodePtr);
    if (currentItem == nullptr)
        return nullptr;

    TreeItem *thisItem = new TreeItem(currentItem->GetContainer(), currentItem->parent() );
    thisItem->setContainer(currentItem->GetContainer());
    //*thisItem = *currentItem;
//  parent->appendChild(thisItem);
    parent->insertChild(row, thisItem);
    for (auto nChild = 0; nChild < childCount; ++nChild)
       
       restoreTree(ds, thisItem , nChild);
    
    return thisItem;

如果有人可以解释 parent->appendChild(thisItem); 之间的区别,那就更受欢迎并尝试找到有效的解决方案到 parent->insertChild(row, thisItem) 会很棒。

或任何替代解决方案。

【讨论】:

以上是关于为啥不同的treeItems链接到相同的数据的主要内容,如果未能解决你的问题,请参考以下文章

相同的数据在 angular9 中显示不同。为啥?

为啥通过同一个 COM 对象的不同接口检索到的 IUnknown* 指针具有相同的值?

为啥使用 UIImageJPEGRepresentation 和通过 localpath 获取图像之间的相同图像的数据大小/长度不同

为啥 RSA 加密文本给我相同文本的不同结果

TCPDF:为啥即使单击不同单元格的按钮,“生成 pdf”按钮也会显示相同的数据?

HashMap为啥会死锁