简体   繁体   English

Qt:已选择的项目出现在QGraphicsScene的顶部

[英]Qt: having selected items appear on top in QGraphicsScene

So i have a QGraphicsScene with various items. 所以我有一个QGraphicsScene与各种项目。 Some of the can take the same coordinates in the scene. 有些可以在场景中采用相同的坐标。 When I display the scene the ones displayed on top are the ones which were added last. 当我显示场景时,在顶部显示的是最后添加的。 Is there a way to make a certain item always appear on top or even better make it reappear on top during the program (rather than deleting it and adding it again)?. 有没有一种方法可以使某个项目始终显示在顶部,甚至更好地使其在程序运行期间重新显示在顶部(而不是删除它并再次添加它)? I've been thinking about drawing everything beforehand and then using setVisible() to show only the items I want to, but since I want to add new things online it seems to be a bit problematic. 我一直在考虑事先绘制所有内容,然后使用setVisible()仅显示我想要的项目,但是由于我想在线添加新内容,因此似乎有点问题。

You can use QGraphicsItem::setZValue ( qreal z ) to set the Z-value of the item. 您可以使用QGraphicsItem::setZValue ( qreal z )设置项目的Z值。 The Z value decides the stacking order of sibling items. Z值决定兄弟项目的堆叠顺序。 An item with a higher Z value will always be drawn on top of another item with a lower Z value. Z值较高的项目将始终绘制在Z值较低的另一个项目的顶部。 The default Z value is zero. Z的默认值为零。 So you can set it to a higher value to bring it on top : 因此,您可以将其设置为更高的值以使其位于最上方:

item->setZValue(1);

or bring it to bottom of other items : 或将其置于其他项目的底部:

item->setZValue(-1);

After doing some research I think that @Leslie 's answer is in a way more correct than @Nejat 's. 经过研究后,我认为@Leslie的答案比@Nejat的答案更正确。 However it is very inefficient if you have a lot of items and you have to do that check very often. 但是,如果您有很多物品,并且必须经常进行检查,则效率很低。

I my case I have a QGraphicsTextItem that shows the coordinates of the cursor inside my scene. 以我QGraphicsTextItem ,我有一个QGraphicsTextItem可以显示场景中光标的坐标。

void QCVN_SceneView::mouseMoveEvent(QMouseEvent *event)
{
  QPointF cursorPoint = mapToScene(event->pos());
//  cout << "Event pos: x=" << event->pos().x() << ", y=" << event->pos().y() << endl;
//  cout << "Event pos (in scene): x=" << cursorPoint.x() << ", y=" << cursorPoint.y() << endl;

  QString coords = QString("%1, %2")
                          .arg(cursorPoint.x())
                          .arg(cursorPoint.y());

  cursorSceneCoords->setPlainText(coords);
  cursorSceneCoords->setPos(cursorPoint);

  QGraphicsView::mouseMoveEvent(event);
}

Obviously if I have 10000000 items in the scene using setZValue(1) will not do the trick unless all items are with a z-value under 1. Iterating through the whole list of items is also a bad way of doing it. 显然,如果我在场景中有1000万个项目,则除非所有项目的z-value在1以下,否则使用setZValue(1)不会达到目的,遍历整个项目列表也是一种不好的方法。

I gave it a little thought and it struck me once I remembered that setZValue() uses a qreal argument. 我想了一下,当我想起setZValue()使用qreal参数时,它就使我qreal Depending on the system it can be a double or a float however this is not important. 根据系统的不同,它可以是doublefloat但这并不重要。 We can simply use std::numeric_limits to get the very, very top value possible. 我们可以简单地使用std::numeric_limits来获得非常非常高的值。 Of course we have to limit all our items in the scene (except the desired once that we want on top) to have a maximum z-value of maximum possible value minus 1 (or 0.1 or whatever). 当然,我们必须限制场景中的所有项目(除了我们想要在顶部想要的一次),最大z-value为最大可能值减去 1(或0.1或其他值)。 So if you do 所以如果你这样做

YOUR_GRAPHICS_ITEM.setZValue(std::numeric_limits<qreal>::max());

the item will always be on top of the rest. 该项目将始终位于其余项目之上。

Check this 检查一下

http://www.qtcentre.org/threads/5428-help-with-ZValue!! http://www.qtcentre.org/threads/5428-help-with-ZValue !!

// Find largest Z
qreal maxZ = 0;
foreach (QGraphicsItem *item, 
        clickedItem>collidingItems(Qt::IntersectsItemBoundingRect))
    maxZ = qMax(maxZ, item->zValue());

// Assign new Z
clickedItem->setZValue(maxZ + some);

This question is a little confusing. 这个问题有点令人困惑。 The subject mentions wanting items on top when selected, while the description talks about more permanent ordering concerns (creation and such). 当选择主题时,主题会提到想要的物品在最上面,而描述中谈到的是更持久的订购问题(创作等)。 I'm adding this answer to clarify possible solutions for those coming here due to the subject: 我正在添加此答案,以阐明针对此主题而来的解决方案:

  • For permanent order depth management setZValue is the way to go. 对于永久订单深度管理, setZValue是必经之路。 For example, a node view with group backdrops where backdrops should always be behind all other items, the zValue can be set to -100. 例如,对于具有组背景的节点视图,其中背景应始终位于所有其他项目的后面, zValue可以设置为-100。
  • For temporary ordering, such as selections, where you don't want to mess with the permanent ordering (which should be reserved for user-set or application-specific order state needs), you can use stackBefore . 对于临时排序(例如选择),您不想弄乱永久排序(应保留给用户设置或特定于应用程序的订单状态需求),可以使用stackBefore This will change the order of items within the same zDepth . 这将更改 同一 zDepth 的项目顺序 So, when items are selected you could run through all items and adjust the order and you don't have to worry about trying to reset zDepth back to what it was before when done (I suppose you could still want to restore, but at least this way the concerns are separate from zDepth ). 因此,选择项目后,您可以遍历所有项目并调整顺序,而不必担心尝试将zDepth重置为完成后的状态(我想您仍然可以恢复,但至少这样,关注点便与zDepth分离了)。 Note, FWIW, I find the stackBefore ordering of sibling to feel backwards. 请注意,FWIW,我在sibling排序之前先找到了stackBefore ,以使其感到向后。

https://github.com/sonichy/HTYPaint2/blob/master/mainwindow.cpp#L775 https://github.com/sonichy/HTYPaint2/blob/master/mainwindow.cpp#L775

void MainWindow::on_action_layerTop_triggered()
{
    if(scene->selectedItems().size() > 0){
        QList<QGraphicsItem*> collidingItems = scene->collidingItems(scene->selectedItems().first());
        for(int i=0; i<collidingItems.size(); i++){
            collidingItems.at(i)->stackBefore(scene->selectedItems().first());
        }
        scene->update();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM