Qt development technology: graphics view framework (two) scene QGraphicsScene, QGraphicsItem and QGraphicsView detailed explanation

If the article is an original article, please indicate the original source for reprinting.
The blog address of this article: https://hpzwl.blog.csdn.net/article/details/117660217

Dear readers, knowledge is infinite but manpower is poor. Either change your needs, find professionals, or do your own research.

Red Fatty (Red Imitation)'s blog post: development technology collection (including Qt practical technology, Raspberry Pi, 3D, OpenCV, OpenGL, ffmpeg, OSG, single-chip microcomputer, software and hardware combination, etc.) is being continuously updated... (click on the portal)

Qt Development Column: Development Technology (click on the portal)

Previous: " Qt Development Technology: Graphic View Framework (1) Basic Introduction "
Next: Stay tuned


Foreword

The three core classes of Qt's graphics view framework are: QGraphicsScene, QGraphicsItem and QGraphicsView.


Advanced Whiteboard Software Framework Demo

Insert picture description here



QGraphicsScene

description

The QGraphicsScene class provides a surface for managing a large number of two-dimensional graphics items.
This class is used as a container for QGraphicsItems. It is used with QGraphicsView to visualize graphical items on a two-dimensional surface, such as lines, rectangles, text, and even custom items. QGraphicsScene is part of the graphics view framework.
QGraphicScene also provides some functions that can effectively determine the location of items and determine which items are visible in any area of ​​the scene. Using the QGraphicsView widget, you can visualize the entire scene, or zoom in and view only parts of the scene.
Example:

QGraphicsScene *pScene = new QGraphicsScene();
pScene->addText("Hello, world!");
QGraphicsView *pView = new QGraphicsView(pScene, this);
Insert picture description here


Please note that QGraphicScene itself has no visual appearance; it only manages projects. You need to create a QGraphicsView widget to visualize the scene (set its parent class as a visual window, such as QWidget).
To add items to the scene, first construct a QGraphicsScene object. Then, there are two options: either add an existing QGraphicsItem object (mainly a custom inherited QGraphicsItem) by calling addIitem(), or call the convenience functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon (), addRect() or addText(), these functions all return a pointer to the newly added item. The size of items added using these functions is relative to the item's coordinate system, and the item position is initialized to (0, 0) in the scene.
Then you can use QGraphicsView to visualize the scene. When the scene changes (for example, when the project moves or transitions), QGraphicScene will emit a changed() signal. To remove an item, call RemoveItem().
QGraphicScene uses an indexing algorithm to effectively manage the location of items. By default, a BSP (Binary Space Partition) tree is used; this algorithm is suitable for large-scale scenarios where most projects remain static (ie, do not move). You can choose to disable this index by calling setItemIndexMethod(). For more information about the available indexing algorithms, see the ItemIndexMethod property.
The bounding rectangle of the scene is set by calling setSceneRect(). Items can be placed anywhere in the scene, and by default, the size of the scene is unlimited. The scene rectangle is only used for internal accounting and maintains the item index of the scene. If the scene rect is not set, QGraphicScene will use the boundary area of ​​all items returned by itemsBoundingRect() as the scene rectangle. However, itemsBoundingRect() is a relatively time-consuming function because it collects the location information of each item in the scene. Therefore, when operating on a large scene, you should always set the scene rectangle.
One of the biggest advantages of QGraphicScene is that it can effectively determine the location of the project. Even if there are millions of items on site, the items() function can determine the location of the items within a few milliseconds. There are several overloads of items(): one to find items in a specific location, one to find items within or intersecting the polygon or rectangle, and so on. The list of returned items is sorted in stacking order, with the top item being the first item in the list. For convenience, there is also an itemat() function that returns the top item at a given position.
QGraphicScene maintains scene selection information. To select items, call setSelectionArea(), and to clear the current selection, call clearSelection(). Call selectedItems() to get a list of all selected items.

Event handling and propagation

Another responsibility of QGraphicsScene is to propagate events from QGraphicsView. To send an event to the scene, you can construct an event that inherits QEvent, and then use QApplication::SendEvent() to send it. event() is responsible for dispatching events to various projects. Some common events are handled by convenient event handlers. For example, key press events are handled by keypressEvent(), and mouse key press events are handled by mousePressEvent().
The key event is passed to the focus item. To set the focus item, you can call setFocusItem(), passing the item that receives the focus, or the item itself can call QGraphicsItem::setFocus(). Call focusItem() to get the current focus item. In order to be compatible with widgets, the scene also maintains its own focus information. By default, the scene has no focus and all key events will be discarded. If setFocus() is called, or an item in the scene gets the focus, the scene will automatically get the focus. If the scene has focus, hasFocus() will return true, and key events will be forwarded to the focused item (if any). If the scene loses focus (that is, someone calls clearFocus()), and an item has focus, the scene will maintain its item focus information, and once the scene returns to focus, it will ensure that the last focused item returns to focus.
For mouse hover effects, QGraphicsScene will send hover events. If an item accepts hover events (see QGraphicsItem::acceptHoverEvents()), it will receive a QGaphicsSceneHoverCenter event when the mouse enters its area. When the mouse continues to move within the project area, QGraphicsScene will send a GraphicsSceneHoverMove event to it. When the mouse leaves the project area, the project will receive a GraphicsSceneHoverLeave event.
All mouse events will be passed to the current mouse grabber item. If an item accepts mouse events (see QGraphicsItem::acceptedMouseButtons()) and receives a mouse press, it will become the mouse grabber of the scene. It keeps the mouse grabber until it receives a mouse release when no other mouse buttons are pressed. You can call mouseGramberItem() to determine which item is currently acquiring the mouse.

QGraphicsView

The QGraphicsView class provides a window for displaying the contents of QGraphicsScene.
In the viewport where QGraphicsView scrolls the visual content. For the steps of creating a scene for geometric items, refer to the QGraphicsScene documentation, part of the QGraphicsView graphics view framework.
To visualize a scene, by constructing QGraphicsView and passing the address of the object, you can see the constructor of QGraphicsView, or you can call setScene() to display it later. After you call show(), the window will scroll to the center of the view by default and display all visible items. E.g:

QGraphicsScene *pScene = new QGraphicsScene();
pScene->addText("Hello, world!");
QGraphicsView *pView = new QGraphicsView(pScene, this);
Insert picture description here


You can use the scroll bar or call centerOn() to explicitly scroll to any position in the scene. By passing the point to centerOn(), QGraphicsView will scroll its viewport to ensure that the point is centered in the view. Provides an overload for scrolling to QGraphicsItem, in this case, QGraphicsView will see the center of the item centered in the view. If you only want to ensure that a certain area is visible (but not necessarily centered), you can call ensureVisible().
QGraphicsView can be used to visualize the entire scene, or only a part of it. By default, the visualization area is automatically detected when the view is first displayed (by calling QGraphicsScene::itemsBoundingRect()). To set the visualization area rectangle yourself, you can call setScenRect(). This will adjust the range of the scroll bar appropriately. Please note that although the scene supports almost unlimited sizes, the range of the scroll bar will never exceed the range of integers (INT_MIN, INT_MAX).
QGraphicsView visualizes the scene by calling render(). By default, items are drawn to the viewport by using the regular QPainer and the default rendering hints. To change the default rendering hints passed by QGraphicsView to QPainter when drawing items, you can call setRenderHints().
By default, QGraphicsView provides a regular QWidget for the viewport widget. You can access this widget by calling viewport(), or you can replace it by calling setViewport(). To use OpenGL for rendering, just call setViewPort(new QGLWidget). QGraphicsView owns the ownership of the viewport widget.
QGraphicsView uses QTransform to support affine transformation. You can pass the matrix to setTransform(), or you can call the convenience functions rotate(), scale(), translate() or shear(). The two most common conversions are scaling, which is used to achieve scaling and rotation. QGraphicsView maintains the center of the view during the transition. Due to scene alignment (setAligment()), switching views will not have a visual impact.
You can use the mouse and keyboard to interact with items in the scene. QGraphicsView converts mouse and key events into scene events (events inheriting QGraphicsSceneEvent) and forwards them to the visualized scene. Finally, it is a single project that processes and reacts to events. For example, if you click on a selectable item, the item will usually let the scene know that it has been selected, and it will also redraw itself to display a selection rectangle. Similarly, if you click and drag the mouse to move a movable item, it is processing the mouse movement and moving its own item. Item interaction is enabled by default, you can switch it by calling setInteractive().
You can also provide your own custom scene interaction by creating a subclass of QGraphicsView and re-implementing mouse and key event handlers. To simplify how to programmatically interact with items in the view, QGraphicsView provides mapping functions mapToScene() and mapFromScene(), as well as item accessors items() and itemat(). These functions allow mapping points, rectangles, polygons, and paths between view coordinates and scene coordinates, and use view coordinates to find items in the scene.

QGraphicsItem

Detailed introduction

The QGraphicsItem class is the base class for all graphics items in QGraphicsScene.
It provides a lightweight foundation for writing your own custom projects. This includes defining item geometry, conflict detection, its drawing realization and item interaction through event handlers. QGraphicsItem is part of the graphics view frame.

Insert picture description here


For convenience, Qt provides a set of standard graphical items for the most common shapes. these are:

  • QGraphicsEllipseItem provides ellipse items
  • QGraphicsLineItem provides line items
  • QGraphicsPathItem provides arbitrary path items
  • QGraphicsPixmapItem provides pixmap items
  • QGraphicsPolygonItem provides polygon items
  • QGraphicsRectItem provides rectangular items
  • QGraphicsSimpleTextItem provides simple text label items
  • QGraphicsTextItem provides advanced text browser items

(Supplement: If it is for in-depth use, it is recommended to rewrite a public accumulation, and then write all the element items by themselves, do not use their own.)
  All geometric information of the project is based on its local coordinate system. The item's position pos() is the only function that does not operate in local coordinates, because it returns the position in parent coordinates. The graphical view coordinate system describes the coordinate system in detail.
You can set whether the item should be visible (that is, draw and receive events) by calling setVisible(). Hiding an item will also hide its children. Similarly, items can be enabled or disabled by calling setEnabled(). If an item is disabled, all its children will also be disabled. By default, the project is both visible and enabled. To switch whether to select an item, first enable selection by setting the itemIsSelectable flag, and then call setSelected(). Usually, the selection is switched by the scene, which is the result of user interaction.
To write your own graphics item, you must first create a subclass of QGraphicsItem, and then start with two purely virtual public functions that implement it: boundingRect(), which returns the estimated value of the area drawn by the item, and paint() implements the actual drawing.
Example:

class SimpleItem : public QGraphicsItem
{
public:
  QRectF boundingRect() const
  {
    qreal penWidth = 1;
    return QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
                 20 + penWidth, 20 + penWidth);
  }
  void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  {
    painter->drawRoundedRect(-10, -10, 20, 20, 5, 5);
  }
};

The boundingRect() function has many different uses. QGraphicsScene builds its item index based on boundingRect(), and QGraphicsView uses it to eliminate invisible items and determine areas that need to be recompiled when drawing overlapping items. In addition, the collision detection mechanism of QGraphicsItem uses boundingRect() to provide an effective cutoff point. The fine-grained collision algorithm in collistsWithItem() is based on calling shape(), which returns the exact outline of the item shape in the form of QPainterPath.
QGraphicScene expects all boundingRect() and shape() items to remain unchanged unless notified. If you want to change the item's geometry in any way, you must first call prepareGeometryChange() to allow QgraphicsScene to update its accounting.
There are two ways of collision detection:

  • Overload shape() to return the exact shape of the item, and rely on the default implementation of collapsWithItem() for shape intersection. If the shape is complex, this may be very expensive (referring to performance consumption).
  • Overload collistWithItem() to provide your own custom item and shape conflict algorithm.

You can call the contains() function to determine whether the item contains points. This function can also be reimplemented by items. The default behavior of contains() is based on calling shape().
Items can contain other items, or they can be included in other items. All items can have parent and child lists. Unless the item has no parent, its position is in the parent's coordinates (that is, the parent's local coordinates). The parent item propagates their position and its transformation to all children.

Insert picture description here

Conversion

In addition to the base position pos(), QGraphicsItem also supports projection conversion. There are several ways to change the conversion of items. For simple transformations, you can call the convenience function setRotation() or setScale(), or you can pass any transformation matrix to setTransform(). For advanced transformation control, you can also set multiple combined transformations by calling setTransforms().
The item transformation is superimposed from parent to child, so if both the parent and child are rotated 90 degrees, the total transformation of the child will be 180 degrees. Similarly, if the parent of an item is scaled to twice its original size, its children will also be twice its original size. The conversion of an item does not affect its own local geometry; all geometry functions (for example, contains(), update(), and all mapping functions) still operate in local coordinates. For convenience, QGraphicsItem provides the function sceneTransform(), which returns the total transformation matrix of the item (including its position and all parent positions and transformations), and scenePos() returns its position in scene coordinates. To reset the matrix of items, call resetTransform().
Certain conversion operations produce different results depending on the order of application. For example, if you scale a transformation and then rotate it, you may get a different result than the first rotation transformation. However, the order in which conversion properties are set on QGraphicsItem does not affect the resulting conversion; QGraphicsItem always applies these properties in a fixed, defined order:

  • The basic transformation of the application ( transform ())
  • List of transformations to apply items in order ( transforms ())
  • The item is rotated relative to its transformation origin ( rotation (), transformOriginPoint ())
  • The item is scaled relative to its transformation origin ( scale (), transformOriginPoint ())

draw

QGraphicsView calls the paint() function to draw the contents of the item. The item itself has no background or default fill; the content behind the item will glow in all areas that are not explicitly drawn in this function. You can call update() to plan the redrawing, or you can choose to pass the rectangle that needs to be redrawn. Depending on whether the item is visible in the view, the item can be repainted or not; there is no equivalent item in QWidget::repaint() in QGraphicsItem.
Items are drawn by the view, starting from the parent item, and then stacking the children in ascending order. You can set the stack order of items by calling setZValue(), and test it by calling zValue(), where items with lower z values ​​are drawn before items with higher z values. The stacking order applies to sibling items; the parent item is always drawn before its children.
Sorting
All items are drawn in a defined, stable order, and this order determines which items will receive mouse input first when the scene is clicked. Normally, you don’t have to worry about sorting, because the items follow the "natural order" and follow the logical structure of the scene.
The child items of the item are stacked on top of the parent item, and the sibling items are stacked in the order of insertion (ie, in the same order as added to the scene or to the same parent). If item A is added and then B is added, then B will be on top of A. If C is added, the stacking order of the items will be A, then B, then C.

Insert picture description here


This example shows the stacking order of all the limbs of the robot from the drag and drop robot example. The torso is the root item (all other items are children or children of the torso), so the torso is drawn first. Next, draw the head because it is the first item in the torso list. Then draw the upper left arm. Since the lower arm is a child of the upper arm, the lower arm will be drawn, and then the next sibling of the upper arm, the upper right arm, will be drawn, and so on.
For advanced users, there are some ways to change the sorting of items:

  • You can call setZValue () on an item to explicitly stack it on top or below other sibling items. The default Z value of the item is 0. Items with the same Z value are stacked in the order of insertion.
  • You can call stackBefore () to reorder the list of sub-items. This will directly modify the insertion order.
  • You can set the ItemStacksBhindParant flag to stack the children after their parent.
    The stacking order of two sibling items also counts the children and children of each item. Therefore, if an item is on top of another project, then all its children will also be on top of all children of the other project.

event

QGraphicsItem receives events from QGraphicsScene through the virtual function sceneEvent(). This function distributes the most common events to a set of convenient event handlers:

  • contextMenuEvent () handles context menu events.
  • focusInEvent () and focusOutEvent () handle focus entry and exit events.
  • hoverEnterEvent (), hoverMoveEvent () and hoverLeaveEvent () handle hoverEnter, move and leave events.
  • inputMethodEvent () handles input events to obtain auxiliary function support, such as Chinese input method to obtain input content.
  • keyPressEvent () and keyReleaseEvent () handle key press and release events.
  • mousePressEvent (), mouseMoveEvent (), mouseReleaseEvent (), and mouseDoubleClickEvent () handle mouse press, move, release, click and double click events.

You can filter the events of any other project by installing an event filter. This feature is different from Qt's regular event filter (see QObject::InstallEventFilter()), which only works on subclasses of QObject. After the project is installed as an event filter of another project by calling InstallSceneEventFilter(), the virtual function sceneEventFilter() will receive the filtered events. The item event filter can be removed by calling removeSceneEventFilter().

Custom data

Sometimes it is useful to register custom data to an item, custom item, or standard item. You can call setData() on any item to use a key-value pair (the key is an integer and the value is QVariant) to store the data in it. To get custom data from the item, call data(). This feature is completely unaffected by qt itself; it is provided for the convenience of users.

Detailed enumeration

enum QGraphicsItem::CacheMode: Cache mode

This enumeration describes the cache mode of QGraphicsItem. The cache is used to speed up rendering by allocating and rendering to a non-screen pixel buffer. When the item needs to be redrawn, the buffer can be reused. For some drawing devices, the cache is stored directly in the graphics memory, which makes rendering very fast.

Insert picture description here

enum QGraphicsItem::GraphicsItemChange: Notify status changes

This enumeration describes state changes notified by QGraphicsItem::itemChange(). The notification will be sent as a status change, and in some cases, adjustments can be made (see the documentation of each change for details).
Note: Be careful to call the function of QGraphicsItem itself in itemChange(), because some function calls may cause unwanted recursion. For example, you cannot call setPos() in itemChange() for the itemPositionChange notification, because the setPos() function will call itemChange(itemPositionChange) again. Instead, the new adjusted position can be returned from itemChange().

Insert picture description here


Insert picture description here



Insert picture description here


Insert picture description here


Insert picture description here

enum QGraphicsItem::GraphicsItemFlag, flags QGraphicsItem::GraphicsItemFlags: Represents function items

This enumeration describes the different flags that can be set on the item to switch between different functions in the item's behavior. All flags are disabled by default.

Insert picture description here


Note: This flag is similar to ItemContainChildrenInShape, but it also enforces inclusion by cutting children.

Insert picture description here


Note: After setting this flag, the project itself can still be zoomed, and the zoom conversion will affect the sub-items of the project.

Insert picture description here


Insert picture description here


Note: If this flag and ItemClipsChildrenToShape are set at the same time, the clip will be enforced. This is equivalent to only setting ItemClipsChildrenToShape.
The GRaphicsItemFlags type is the typedef of QFlags. It stores one or more GraphicsItemFlag values.

enum QGraphicsItem::PanelModality: Panel behavior

This enum specifies the behavior of the modal panel. Modal panels are panels that prevent input to other panels. Please note that items that are children of the mode panel will not be blocked.
Possible values ​​are:

Insert picture description here

Member functions (important ones)

bool QGraphicsItem::acceptDrops() const

If the item accepts the hover event (QGraphicsSceneHoverEvent), it will return true; otherwise, it will return false. By default, the element item does not accept hover events.
This feature was introduced in QT 4.4.

bool QGraphicsItem::acceptTouchEvents() const

If the item accepts a touch event, it returns true; otherwise, it returns false. By default, the project does not accept touch events.
This feature was introduced in Qt4.6.

Qt::MouseButtons QGraphicsItem::acceptedMouseButtons() const

Returns the mouse button that accepts mouse events. By default, all mouse buttons are accepted.
If an item accepts a mouse button, it will become a mouse grab item when the mouse button's mouse down event is passed. However, if the item does not accept the button, QGraphicsScene will forward the mouse event to the first item below it.

[pure virtual] QRectF QGraphicsItem::boundingRect() const

This pure virtual function defines the outer boundary of the item as a rectangle; all drawing must be limited to the bounding rectangle of the item. QGraphicsView uses it to determine whether the item needs to be redrawn.
Although the shape of the item can be arbitrary, the bounding rectangle is always rectangular and is not affected by the conversion of the item.
If you want to change the border of the item, you must first call PrepareGeteryChange(). This will notify the scene of upcoming changes so that it can update its item geometry index; otherwise, the scene will not know the item's new geometry, and the result will be undefined (usually, rendering artifacts are left in view).
Reimplement this function and let QGraphicsView determine which parts of the widget (if any) need to be redrawn.
Note: For drawing outline/stroke shapes, it is important to include half the pen width in the bounding rectangle. However, there is no need to compensate for antialiasing.
Example:

Insert picture description here

QRegion QGraphicsItem::boundingRegion(const QTransform &itemToDeviceTransform) const

Returns the border area of ​​this item. The coordinate space of the returned area depends on itemToDeviceTransform. If the identifier QTransform is passed as a parameter, this function will return the local coordinate area.
The border area describes the rough outline of the visual content of the project. Although it is expensive to calculate, it is also more accurate than boundingrect() and helps avoid unnecessary redrawing when the project is updated. This is especially effective for thin projects such as straight lines or simple polygons. The granularity of the boundary region can be adjusted by calling setBoundingRegionGranularity(). The default granularity is 0; the boundary area of ​​the item is the same as its boundary rectangle.
itemTodeviceTransform is the transformation from item coordinates to device coordinates. If you want this function to return the QRegion in the scene coordinates, you can pass sceneTransform() as a parameter.
This feature was introduced in QT 4.4.

[virtual protected] void QGraphicsItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)

For event events, you can reimplement this event handler to receive drag input events of this item. When the cursor enters the project area, a "drag input" event will be generated.
By accepting events (ie, by calling qEvent:::accept()), the item will accept drop events, in addition to receiving drag move and drag away. Otherwise, the event will be ignored and propagated to the items below. If the event is accepted, the item will receive a drag event before the control returns to the event loop.
Common implementations of DragEnterEvent accept or ignore events based on the MIME data associated with the event. example:

Insert picture description here

[virtual protected] void QGraphicsItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)

For event events, this event handler can be reimplemented to receive drag events for this item. When the cursor moves within the project area, a drag movement event is generated. In most cases, there is no need to reimplement this function; it is used to indicate that only parts of the project can be accepted for placement.
Calling QEvent::Ignore() or QEvent::Accept() on an event will switch whether the item is to be deleted from the event. By default, the event is accepted, indicating that the item is allowed to be placed in the specified location.
By default, the project does not receive drag and drop events; to enable this feature, call setAcceptDrops(true).
The default implementation does nothing.

[virtual protected] void QGraphicsItem::dropEvent(QGraphicsSceneDragDropEvent *event)

For event events, you can reimplement this event handler to receive the placement event of this item. The item can receive drop events only when the last drag move event is accepted.
Calling QEvent::Ignore() or QEvent::Accept() on the event is invalid.
By default, items do not receive drag and drop events; to enable this feature, call setAcceptDrops(true).
The default implementation does nothing.

[virtual protected] void QGraphicsItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)

For event events, you can reimplement this event handler to receive the mouse double-click event of this item.
When an item is double-clicked, the item will first receive a mouse down event, then a release event (ie click), then a double-click event, and finally a release event.
Calling QEvent::Ignore() or QEvent::Accept() on the event is invalid.
The default implementation calls mousePressEvent(). If you want to keep the basic implementation when reimplementing this function, please call QGraphicsItem:: MouseDoubleClickevent() in the reimplementation.
Please note that if an item is neither selectable nor movable, it will not receive a double-click event (in this case, the mouse click will be ignored and the double-click generation will stop).

[virtual] QPainterPath QGraphicsItem::shape() const

Return the shape of this item as the QPainterPath in local coordinates. This shape is used for many things, including collision detection, hit testing, and the QGraphicsScene::items() function.
The default implementation calls boundingRect() to return a simple rectangle, but subclasses can reimplement this function to return a more precise shape for non-rectangular items. For example, round items can choose to return to an ellipse shape to better detect collisions. For example:

Insert picture description here


the outline of the shape can vary according to the width and style of the pen used in drawing. If you want to include this outline in the shape of the item, you can use QPainterPathStroker to create the shape from the stroke.
This function is called by the default implementation of contains() and collipswithpath().

Previous: " Qt Development Technology: Graphic View Framework (1) Basic Introduction "
Next: Stay tuned


If the article is an original article, please indicate the original source for reprinting.
The blog address of this article: https://hpzwl.blog.csdn.net/article/details/117660217