If we create a custom widget and reimplement its paint event, we can draw any graphics we like. This approach was shown in the preceding chapter, and it is ideal for drawing custom widgets, for drawing graphs, and for drawing small numbers of items. But if we need to draw lots of independent items, anything from dozens to tens of thousands of them, or if we need to draw items that the user can interact with individually—for example, clicking, dragging, and selecting them—or if we need to animate items, PyQt's graphics view classes are a much better choice than reimplementing a custom widget's paint event.
The graphics view classes—QGraphicsView, QGraphicsScene, and QGraphics-Item—along with the QGraphicsItem subclasses, were introduced with Qt 4.2, so the examples in this chapter will work only with a version of PyQt that has bindings to Qt 4.2 or later, such as PyQt 4.1. However, we strongly recommend that you use PyQt 4.2 or later for graphics-view-based applications.
To use the graphics view classes we must create a scene, represented by a QGraphicsScene object. Scenes are pure data, and they can be visualized only by associating them with one or more QGraphicsView objects. The items that are drawn in a scene are QGraphicsItem subclasses. PyQt provides several predefined subclasses, including QGraphicsLineItem, QGraphicsPixmapItem, QGraphics-SimpleTextItem (plain text), and QGraphicsTextItem (HTML). It is also possible to create custom graphics item subclasses, as we will see later in this chapter.
Once a scene has been created, and has had items added to it, it can be visualized using a QGraphicsView. One powerful feature of graphics views is that we can apply transformations to them, such as scaling and rotation, that change how the scene appears, but without changing any of the scene's items themselves. It is also possible to associate more than one graphics view with a particular scene, to allow different parts of the scene to be viewed, and with each view having its own independent transformations.
The graphics view classes are essentially two-dimensional; nonetheless, every item has a z value, with higher z-valued items being drawn on top of those with lower z values. Collision detection is based on item (x, y) positions. In addition
Viewport and window coordinates
to information about collisions, the scene can tell us which items contain a particular point or are in a particular region, and which are selected. Scenes have a foreground layer, useful, for example, to draw a grid that overlays all the items in the scene; they also have a background layer that is drawn underneath all the items, useful for providing a background image or color.
Items are either children of the scene (rather like PyQt's normal parent-child widget relationships), or a child of another item. When transformations are applied to an item, they are automatically applied to all the item's children, recursively to the greatest grandchild. This means that if an item is moved—for example, dragged by the user—all its children will be dragged with it. It is also possible to have groups of peer items, that is, transformations on one item in the group affect only that item's children, not the other members of the group.
Figure 12.1 Graphics items use local logical coordinates
The graphics view classes use three different coordinate systems, although in practice we usually care about only two of them. Views use the physical coordinate system. Scenes use a logical coordinate system that we choose when we create them. PyQt automatically maps scene coordinates to view coordinates. In essence, scenes use "window" coordinates and views use "viewport" coordinates. So, when we are positioning items we place them in terms of scene coordinates. The third coordinate system is the one used by items. This is particularly convenient because it is a logical coordinate system centered on point (0, 0). Each item's (0, 0) is actually at the item's position in the scene. This means that in practice, we can always draw items in terms of their center point—and we do not have to care about any transformations that have been applied to them by parent items, since the scene will automatically take care of these for us. Figure 12.1 illustrates the relationship between scene and item coordinates.
In this chapter we will look at two examples that between them show many dif-ferent aspects of the graphics view classes. The first example is typical of the kind of application where the user creates items one by one, and manipulates items either individually or in selected groups. This application also shows user interaction, including selecting, moving, and resizing items. The second example shows animated composite items with complex shapes. It also shows how to minimize the work done to draw items depending on the scene's level of detail (how zoomed in or out it is).
Was this article helpful?
Here's your chance to learn the secret formula that only the top webmaster's know about, that helps them easily dominate any keyword term. Discover How To Unravel The Mysteries Of Googles Search Engine Rankings, and Stay One Step Ahead Of The Rest In The keywords War!