📄 qgraphicsscene.cpp
字号:
\internal*/void QGraphicsScenePrivate::_q_generateBspTree(){ if (!indexTimerId) return; Q_Q(QGraphicsScene); q->killTimer(indexTimerId); indexTimerId = 0; purgeRemovedItems(); // Add unindexedItems to indexedItems QRectF unindexedItemsBoundingRect; for (int i = 0; i < unindexedItems.size(); ++i) { if (QGraphicsItem *item = unindexedItems.at(i)) { unindexedItemsBoundingRect |= item->sceneBoundingRect(); if (!freeItemIndexes.isEmpty()) { int freeIndex = freeItemIndexes.takeFirst(); item->d_func()->index = freeIndex; indexedItems[freeIndex] = item; } else { item->d_func()->index = indexedItems.size(); indexedItems << item; } } } QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; growingItemsBoundingRect |= unindexedItemsBoundingRect; // Determine whether we should regenerate the BSP tree. int depth = bspTreeDepth; if (depth == 0) { int oldDepth = intmaxlog(lastItemCount); depth = intmaxlog(indexedItems.size()); static const int slack = 100; if (bspTree.leafCount() == 0 || oldDepth != depth && qAbs(lastItemCount - indexedItems.size()) > slack) { // ### Crude algorithm. regenerateIndex = true; } } // Regenerate the tree. if (regenerateIndex) { regenerateIndex = false; bspTree.initialize(q->sceneRect(), depth); unindexedItems = indexedItems; lastItemCount = indexedItems.size(); q->update(); // Take this opportunity to reset our largest-item counter for // untransformable items. When the items are inserted into the BSP // tree, we'll get an accurate calculation. largestUntransformableItem = QRectF(); } // Insert all unindexed items into the tree. for (int i = 0; i < unindexedItems.size(); ++i) { if (QGraphicsItem *item = unindexedItems.at(i)) { QRectF rect = item->sceneBoundingRect(); bspTree.insertItem(item, rect); // If the item ignores view transformations, update our // largest-item-counter to ensure that the view can accurately // discover untransformable items when drawing. if (item->d_ptr->itemIsUntransformable()) { QGraphicsItem *topmostUntransformable = item; while (topmostUntransformable && (topmostUntransformable->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations)) { topmostUntransformable = topmostUntransformable->parentItem(); } // ### Verify that this is the correct largest untransformable rectangle. largestUntransformableItem |= item->mapToItem(topmostUntransformable, item->boundingRect()).boundingRect(); } } } unindexedItems.clear(); // Notify scene rect changes. if (!hasSceneRect && growingItemsBoundingRect != oldGrowingItemsBoundingRect) emit q->sceneRectChanged(growingItemsBoundingRect);}/*! \internal*/void QGraphicsScenePrivate::_q_emitUpdated(){ Q_Q(QGraphicsScene); calledEmitUpdated = false; QList<QRectF> oldUpdatedRects; oldUpdatedRects = updateAll ? (QList<QRectF>() << (sceneRect | growingItemsBoundingRect)) : updatedRects; updateAll = false; updatedRects.clear(); emit q->changed(oldUpdatedRects);}/*! \internal Updates all items in the pending update list. At this point, the list is unlikely to contain partially constructed items.*/void QGraphicsScenePrivate::_q_updateLater(){ foreach (QGraphicsItem *item, pendingUpdateItems) item->update(); pendingUpdateItems.clear();}/*! \internal Schedules an item for removal. This function leaves some stale indexes around in the BSP tree; these will be cleaned up the next time someone triggers purgeRemovedItems(). Note: This function is called from QGraphicsItem's destructor. \a item is being destroyed, so we cannot call any pure virtual functions on it (such as boundingRect()). Also, it is unnecessary to update the item's own state in any way. ### Refactoring: This function shares much functionality with removeItem()*/void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item){ Q_Q(QGraphicsScene); if (QGraphicsItem *parent = item->d_func()->parent) { QVariant variant; qVariantSetValue<QGraphicsItem *>(variant, item); parent->itemChange(QGraphicsItem::ItemChildRemovedChange, item); parent->d_func()->children.removeAll(item); } int index = item->d_func()->index; if (index != -1) { // Important: The index is useless until purgeRemovedItems() is // called. indexedItems[index] = (QGraphicsItem *)0; if (!purgePending) { purgePending = true; q->update(); } removedItems << item; } else { // Recently added items are purged immediately. unindexedItems() never // contains stale items. unindexedItems.removeAll(item); q->update(); } // Reset the mouse grabber and focus item data. if (item == mouseGrabberItem) { lastMouseGrabberItem = mouseGrabberItem; mouseGrabberItem = 0; } if (item == focusItem) focusItem = 0; if (item == lastFocusItem) lastFocusItem = 0; // Disable selectionChanged() for individual items ++selectionChanging; int oldSelectedItemsSize = selectedItems.size(); // Update selected & hovered item bookkeeping selectedItems.remove(item); hoverItems.removeAll(item); pendingUpdateItems.removeAll(item); cachedItemsUnderMouse.removeAll(item); // Remove all children recursively. foreach (QGraphicsItem *child, item->children()) _q_removeItemLater(child); // Reenable selectionChanged() for individual items --selectionChanging; if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize) emit q->selectionChanged();}/*! \internal Removes stale pointers from all data structures.*/void QGraphicsScenePrivate::purgeRemovedItems(){ Q_Q(QGraphicsScene); if (!purgePending && removedItems.isEmpty()) return; // Remove stale items from the BSP tree. if (indexMethod != QGraphicsScene::NoIndex) bspTree.removeItems(removedItems); // Purge this list. removedItems.clear(); freeItemIndexes.clear(); for (int i = 0; i < indexedItems.size(); ++i) { if (!indexedItems.at(i)) freeItemIndexes << i; } purgePending = false; // No locality info for the items; update the whole scene. q->update();}/*! \internal Starts or restarts the timer used for reindexing unindexed items.*/void QGraphicsScenePrivate::startIndexTimer(){ Q_Q(QGraphicsScene); if (indexTimerId) { restartIndexTimer = true; } else { indexTimerId = q->startTimer(QGRAPHICSSCENE_INDEXTIMER_TIMEOUT); }}/*! \internal Returns a list of possible mouse grabbers for \a event. The first item in the list is the topmost candidate, and the last item is the bottommost candidate.*/QList<QGraphicsItem *> QGraphicsScenePrivate::possibleMouseGrabbersForEvent(const QList<QGraphicsItem *> &items, QGraphicsSceneMouseEvent *event){ QList<QGraphicsItem *> possibleMouseGrabbers; foreach (QGraphicsItem *item, items) { if (item->acceptedMouseButtons() & event->button()) { if (!item->isEnabled()) { // Disabled mouse-accepting items discard mouse events. break; } possibleMouseGrabbers << item; } } return possibleMouseGrabbers;}/*! Returns all items for the screen position in \a event.*/QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos, const QPointF &scenePos, QWidget *widget) const{ Q_Q(const QGraphicsScene); QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0; QList<QGraphicsItem *> items; if (view) items = view->items(view->viewport()->mapFromGlobal(screenPos)); else items = q->items(scenePos); return items;}/*! \internal*/void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event){ for (int i = 0x1; i <= 0x10; i <<= 1) { if (event->buttons() & i) { mouseGrabberButtonDownPos.insert(Qt::MouseButton(i), mouseGrabberItem->d_ptr->genericMapFromScene(event->scenePos(), event->widget())); mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos()); mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos()); } }}/*! \internal*/void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter){ sceneEventFilters.insert(watched, filter);}/*! \internal*/bool QGraphicsScenePrivate::painterStateProtection(const QPainter *painter) const{ // Detect if painter state protection is disabled. QPaintDevice *device = painter->paintEngine()->paintDevice(); for (int i = 0; i < views.size(); ++i) { QWidget *viewport = views.at(i)->viewport(); if ((QPaintDevice *)viewport == device) return !(views.at(i)->optimizationFlags() & QGraphicsView::DontSavePainterState); } return true;}/*! \internal*/void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter){ if (!sceneEventFilters.contains(watched)) return; QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched); QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched); do { if (it.value() == filter) it = sceneEventFilters.erase(it); else ++it; } while (it != end);}/*! \internal*/bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event){ if (item && !sceneEventFilters.contains(item)) return false; QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item); QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item); while (it != end) { // ### The filterer and filteree might both be deleted. if (it.value()->sceneEventFilter(it.key(), event)) return true; ++it; } return false;}/*! \internal*/bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event){ if (filterEvent(item, event)) return false; return item ? item->sceneEvent(event) : false;}/*! \internal*/void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest, QGraphicsSceneDragDropEvent *source){ dest->setWidget(source->widget()); dest->setPos(source->pos()); dest->setScenePos(source->scenePos()); dest->setScreenPos(source->screenPos()); dest->setButtons(source->buttons()); dest->setModifiers(source->modifiers()); dest->setPossibleActions(source->possibleActions()); dest->setProposedAction(source->proposedAction()); dest->setDropAction(source->dropAction()); dest->setSource(source->source()); dest->setMimeData(source->mimeData());}/*! \internal*/void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item, QGraphicsSceneDragDropEvent *dragDropEvent)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -