QGraphicsItem:为啥没有`stackAfter`方法?

Posted

技术标签:

【中文标题】QGraphicsItem:为啥没有`stackAfter`方法?【英文标题】:QGraphicsItem: Why no `stackAfter` method?QGraphicsItem:为什么没有`stackAfter`方法? 【发布时间】:2013-02-26 04:37:24 【问题描述】:

我在尝试绕过“推荐”的做事方式时遇到了烦人的事情。

所以,我有一堆卡片。我想让它在我发牌时成为整个场景中最后绘制的对象(典型的bring_to_front 功能)。

推荐的方法是添加到对象的 zValue 直到它大于其他对象,但我希望通过明智地使用stackBefore 方法,它模拟重新组织对象添加到场景中的顺序。

当我在有限的集合中洗牌时,这非常有效(获取所选项目的列表,random.shuffle,对于 item do item.stackBefore(next item)),但在冒泡时它肯定不起作用卡到整个场景的顶部。

我考虑将对象的副本添加到场景中,然后删除原始对象,但似乎我应该能够像使用 Python 列表(或 insertAt 或其他东西)那样做 stackAfter .

示例代码:

  def deal_items(self):
    if not self.selection_is_stack():
      self.statusBar().showMessage("You must deal from a stack")
      return

    item_list = self.scene.sorted_selection()
    for i,item in enumerate(item_list[::-1]):
      width = item.boundingRect().width()
      item.moveBy(width+i*width*0.6,0)

      another_list = self.scene.items()[::-1]
      idx = another_list.index(item)
      for another_item in another_list[idx+1:]:
        another_item.stackBefore(item)

这行得通。只是看起来有点……丑陋。

【问题讨论】:

也许有像setZValue=0 这样的技巧会自动将对象放在zValue==0 的所有对象的末尾?我不知道 【参考方案1】:

self.scene.items 按堆叠顺序返回项目 (link)。所以如果你想stackAfter一个项目,你只需查询当前最顶层项目的z值,然后将新最顶层卡片的z值设置为大一即可。

item.setZValue(self.scene.items().first().zValue() + 1)

希望对您有所帮助。

编辑从http://gitorious.org/qt/ 为stackBeforesetZValue 添加了src src/gui/graphicsview/qgraphicsitem.cpp

void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)

    if (sibling == this)
        return;
    if (!sibling || d_ptr->parent != sibling->parentItem()) 
        qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
        return;
    
    QList<QGraphicsItem *> *siblings = d_ptr->parent
                                       ? &d_ptr->parent->d_ptr->children
                                       : (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0);
    if (!siblings) 
        qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
        return;
    

    // First, make sure that the sibling indexes have no holes. This also
    // marks the children list for sorting.
    if (d_ptr->parent)
        d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
    else
        d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();

    // Only move items with the same Z value, and that need moving.
    int siblingIndex = sibling->d_ptr->siblingIndex;
    int myIndex = d_ptr->siblingIndex;
    if (myIndex >= siblingIndex) 
        siblings->move(myIndex, siblingIndex);
        // Fixup the insertion ordering.
        for (int i = 0; i < siblings->size(); ++i) 
            int &index = siblings->at(i)->d_ptr->siblingIndex;
            if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
                ++index;
        
        d_ptr->siblingIndex = siblingIndex;
        for (int i = 0; i < siblings->size(); ++i) 
            int &index = siblings->at(i)->d_ptr->siblingIndex;
            if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
                siblings->at(i)->d_ptr->siblingOrderChange();
        
        d_ptr->siblingOrderChange();
    


void QGraphicsItem::setZValue(qreal z)

    const QVariant newZVariant(itemChange(ItemZValueChange, z));
    qreal newZ = newZVariant.toReal();
    if (newZ == d_ptr->z)
        return;

    if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) 
        // Z Value has changed, we have to notify the index.
        d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
    

    d_ptr->z = newZ;
    if (d_ptr->parent)
        d_ptr->parent->d_ptr->needSortChildren = 1;
    else if (d_ptr->scene)
        d_ptr->scene->d_func()->needSortTopLevelItems = 1;

    if (d_ptr->scene)
        d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);

    itemChange(ItemZValueHasChanged, newZVariant);

    if (d_ptr->flags & ItemNegativeZStacksBehindParent)
        setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0));

    if (d_ptr->isObject)
        emit static_cast<QGraphicsObject *>(this)->zChanged();

【讨论】:

确实如此(我喜欢first 电话,以前没见过),但我只想将zValues 用于完全不同的事情。我想过让 dz = 0.000001 这样我就不必担心突破障碍,但是我必须跟踪它并每隔一段时间不断重置值...... idk,我只是想从中挤出尽可能多的价值stackBefore 尽可能。 如果您需要另一个“z”变量,您可以子类化该项目并添加它。如果您之前阅读过堆栈文档,它所做的只是根据另一个对象的 z 值编辑 z 值。 qt-project.org/doc/qt-4.8/qgraphicsitem.html#stackBefore 祝你好运。 qt-project.org/doc/qt-4.8/qgraphicsitem.html#sorting 还谈到了使用育儿来对项目进行分组和排序 (ItemStacksBehindParent)。 嘿@phyatt,在您的链接中它说“兄弟姐妹必须具有与此项目相同的 Z 值,否则调用此函数将无效。” “当Z值相同时,插入顺序将决定堆叠顺序。”这就是我要使用/修改的插入顺序。它似乎更健壮,非常适合我的目的。 我明白你的意思......但文档并没有指出任何简单的方法。你可以看看 stackBefore 是如何在源代码中实现的,并以这种方式创建一个类似的......

以上是关于QGraphicsItem:为啥没有`stackAfter`方法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 itemAt() 并不总能找到 QGraphicsItem

如果选择该项目,为啥 QGraphicsItem 子项不再单击鼠标?

为啥自定义 QGraphicsItem 会导致场景或视图移动,除非 boundingRect 为空?

为啥缩放 qgraphicsview qgraphicsitem 后会留下痕迹

QGraphicsItem在移动后没有留在原地

在调用 QGraphicsItem::paint 之前