📄 qgraphicsscene.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;/*! \class QGraphicsScene \brief The QGraphicsScene class provides a surface for managing a large number of 2D graphical items. \since 4.2 \ingroup multimedia \mainclass The class serves as a container for QGraphicsItems. It is used together with QGraphicsView for visualizing graphical items, such as lines, rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is part of \l{The Graphics View Framework}. QGraphicsScene also provides functionality that lets you efficiently determine both the location of items, and for determining what items are visible within an arbitrary area on the scene. With the QGraphicsView widget, you can either visualize the whole scene, or zoom in and view only parts of the scene. Example: \code QGraphicsScene scene; scene.addText("Hello, world!"); QGraphicsView view(&scene); view.show(); \endcode Note that QGraphicsScene has no visual appearance of its own; it only manages the items. You need to create a QGraphicsView widget to visualize the scene. To add items to a scene, you start off by constructing a QGraphicsScene object. Then, you have two options: either add your existing QGraphicsItem objects by calling addItem(), or you can call one of the convenience functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(), addRect(), or addText(), which all return a pointer to the newly added item. You can then visualize the scene using QGraphicsView. When the scene changes, (e.g., when an item moves or is transformed) QGraphicsScene emits the changed() signal. To remove an item, call removeItem(). QGraphicsScene uses an indexing algorithm to manage the location of items efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an algorithm suitable for large scenes where most items remain static (i.e., do not move around). You can choose to disable this index by calling setItemIndexMethod(). For more information about the available indexing algorithms, see the itemIndexMethod property. The scene's bounding rect is set by calling setSceneRect(). Items can be placed at any position on the scene, and the size of the scene is by default unlimited. The scene rect is used only for internal bookkeeping, maintaining the scene's item index. If the scene rect is unset, QGraphicsScene will use the bounding area of all items, as returned by itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a relatively time consuming function, as it operates by collecting positional information for every item on the scene. Because of this, you should always set the scene rect when operating on large scenes. One of QGraphicsScene's greatest strengths is its ability to efficiently determine the location of items. Even with millions of items on the scene, the items() functions can determine the location of an item within few milliseconds. There are several overloads to items(): one that finds items at a certain position, one that finds items inside or intersecting with a polygon or a rectangle, and more. The list of returned items is sorted by stacking order, with the topmost item being the first item in the list. For convenience, there is also an itemAt() function that returns the topmost item at a given position. QGraphicsScene maintains selection information for the scene. To select items, call setSelectionArea(), and to clear the current selection, call clearSelection(). Call selectedItems() to get the list of all selected items. \section1 Event Handling and Propagation Another responsibility that QGraphicsScene has, is to propagate events from QGraphicsView. To send an event to a scene, you construct an event that inherits QEvent, and then send it using, for example, QApplication::sendEvent(). event() is responsible for dispatching the event to the individual items. Some common events are handled by convenience event handlers. For example, key press events are handled by keyPressEvent(), and mouse press events are handled by mousePressEvent(). Key events are delivered to the \e {focus item}. To set the focus item, you can either call setFocusItem(), passing an item that accepts focus, or the item itself can call QGraphicsItem::setFocus(). Call focusItem() to get the current focus item. For compatibility with widgets, the scene also maintains its own focus information. By default, the scene does not have focus, and all key events are discarded. If setFocus() is called, or if an item on the scene gains focus, the scene automatically gains focus. If the scene has focus, hasFocus() will return true, and key events will be forwarded to the focus item, if any. If the scene loses focus, (i.e., someone calls clearFocus(),) while an item has focus, the scene will maintain its item focus information, and once the scene regains focus, it will make sure the last focus item regains focus. For mouse-over effects, QGraphicsScene dispatches \e {hover events}. If an item accepts hover events (see QGraphicsItem::acceptsHoverEvents()), it will receive a \l {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters its area. As the mouse continues moving inside the item's area, QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove} events. When the mouse leaves the item's area, the item will receive a \l {QEvent::}{GraphicsSceneHoverLeave} event. All mouse events are delivered to the current \e {mouse grabber} item. An item becomes the scene's mouse grabber if it accepts mouse events (see QGraphicsItem::acceptedMouseButtons()) and it receives a mouse press. It stays the mouse grabber until it receives a mouse release when no other mouse buttons are pressed. You can call mouseGrabberItem() to determine what item is currently grabbing the mouse. \sa QGraphicsItem, QGraphicsView*//*! \enum QGraphicsScene::SceneLayer \since 4.3 This enum describes the rendering layers in a QGraphicsScene. When QGraphicsScene draws the scene contents, it renders each of these layers separately, in order. Each layer represents a flag that can be OR'ed together when calling functions such as invalidate() or QGraphicsView::invalidateScene(). \value ItemLayer The item layer. QGraphicsScene renders all items are in this layer by calling the virtual function drawItems(). The item layer is drawn after the background layer, but before the foreground layer. \value BackgroundLayer The background layer. QGraphicsScene renders the scene's background in this layer by calling the virtual function drawBackground(). The background layer is drawn first of all layers. \value ForegroundLayer The foreground layer. QGraphicsScene renders the scene's foreground in this layer by calling the virtual function drawForeground(). The foreground layer is drawn last of all layers. \value AllLayers All layers; this value represents a combination of all three layers. \sa invalidate(), QGraphicsView::invalidateScene()*//*! \enum QGraphicsScene::ItemIndexMethod This enum describes the indexing algorithms QGraphicsScene provides for managing positional information about items on the scene. \value BspTreeIndex A Binary Space Partitioning tree is applied. All QGraphicsScene's item location algorithms are of an order close to logarithmic complexity, by making use of binary search. Adding, moving and removing items is logarithmic. This approach is best for static scenes (i.e., scenes where most items do not move). \value NoIndex No index is applied. Item location is of linear complexity, as all items on the scene are searched. Adding, moving and removing items, however, is done in constant time. This approach is ideal for dynamic scenes, where many items are added, moved or removed continuously. \sa setItemIndexMethod(), bspTreeDepth*/#include "qgraphicsscene.h"#ifndef QT_NO_GRAPHICSVIEW#include "qgraphicsitem.h"#include "qgraphicsitem_p.h"#include "qgraphicsscene_p.h"#include "qgraphicssceneevent.h"#include "qgraphicsview.h"#include <private/qobject_p.h>#include <QtCore/qcoreapplication.h>#include <QtCore/qlist.h>#include <QtCore/qrect.h>#include <QtCore/qset.h>#include <QtCore/qtimer.h>#include <QtGui/qevent.h>#include <QtGui/qtransform.h>#include <QtGui/qmatrix.h>#include <QtGui/qpainter.h>#include <QtGui/qpaintengine.h>#include <QtGui/qpolygon.h>#include <QtGui/qstyleoption.h>#include <QtGui/qtooltip.h>#include <math.h>#include <qdebug.h>// QRectF::intersects() returns false always if either the source or target// rectangle's width or height are 0. This works around that problem.static QRectF _q_adjustedRect(const QRectF &rect){ static const qreal p = 0.00001; QRectF r = rect; if (!r.width()) r.adjust(-p, 0, p, 0); if (!r.height()) r.adjust(0, -p, 0, p); return r;}/*! \internal*/QGraphicsScenePrivate::QGraphicsScenePrivate() : indexMethod(QGraphicsScene::BspTreeIndex), bspTreeDepth(0), lastItemCount(0), hasSceneRect(false), updateAll(false), calledEmitUpdated(false), selectionChanging(0), regenerateIndex(true), purgePending(false), indexTimerId(0), restartIndexTimer(false), hasFocus(false), focusItem(0), lastFocusItem(0), mouseGrabberItem(0), lastMouseGrabberItem(0), dragDropItem(0), lastDropAction(Qt::IgnoreAction){}/*! \internal*/QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &rect) const{ Q_Q(const QGraphicsScene); const_cast<QGraphicsScenePrivate *>(this)->purgeRemovedItems(); if (indexMethod == QGraphicsScene::BspTreeIndex) { // ### Only do this once in a while. QGraphicsScenePrivate *that = const_cast<QGraphicsScenePrivate *>(this); // Get items from BSP tree QList<QGraphicsItem *> items = that->bspTree.items(rect); // Fill in with any unindexed items for (int i = 0; i < unindexedItems.size(); ++i) { if (QGraphicsItem *item = unindexedItems.at(i)) { QRectF boundingRect = _q_adjustedRect(item->sceneBoundingRect()); if (!item->d_ptr->itemDiscovered && item->isVisible() && (boundingRect.intersects(rect) || boundingRect.contains(rect))) { item->d_ptr->itemDiscovered = 1; items << item; } } } // Reset the discovered state of all discovered items for (int i = 0; i < items.size(); ++i) items.at(i)->d_func()->itemDiscovered = 0; return items; } QList<QGraphicsItem *> itemsInRect; foreach (QGraphicsItem *item, q->items()) { QRectF boundingRect = _q_adjustedRect(item->sceneBoundingRect()); if (item->isVisible() && (boundingRect.intersects(rect) || boundingRect.contains(rect))) itemsInRect << item; } return itemsInRect;}/*! \internal*/void QGraphicsScenePrivate::addToIndex(QGraphicsItem *item){ if (indexMethod == QGraphicsScene::BspTreeIndex) { if (item->d_func()->index != -1) { bspTree.insertItem(item, item->sceneBoundingRect()); foreach (QGraphicsItem *child, item->children()) child->addToIndex(); } else { // The BSP tree is regenerated if the number of items grows to a // certain threshold, or if the bounding rect of the graph doubles in // size. startIndexTimer(); } }}/*! \internal*/void QGraphicsScenePrivate::removeFromIndex(QGraphicsItem *item){ if (indexMethod == QGraphicsScene::BspTreeIndex) { int index = item->d_func()->index; if (index != -1) { bspTree.removeItem(item, item->sceneBoundingRect()); freeItemIndexes << index; indexedItems[index] = 0; item->d_func()->index = -1; unindexedItems << item; foreach (QGraphicsItem *child, item->children()) child->removeFromIndex(); } startIndexTimer(); }}/*! \internal*/void QGraphicsScenePrivate::resetIndex(){ purgeRemovedItems(); if (indexMethod == QGraphicsScene::BspTreeIndex) { for (int i = 0; i < indexedItems.size(); ++i) { if (QGraphicsItem *item = indexedItems.at(i)) { item->d_ptr->index = -1; unindexedItems << item; } } indexedItems.clear(); freeItemIndexes.clear(); regenerateIndex = true; startIndexTimer(); }}static inline int intmaxlog(int n){ return (n > 0 ? qMax(int(::ceil(::log(double(n)) / ::log(double(2)))), 5) : 0);}/*!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -