diff options
author | Warwick Allison <warwick.allison@nokia.com> | 2010-05-04 00:09:14 (GMT) |
---|---|---|
committer | Warwick Allison <warwick.allison@nokia.com> | 2010-05-04 00:09:14 (GMT) |
commit | 536d0f141a13474122f99daf98bf6b54e635b474 (patch) | |
tree | 7f0219f0625f20b2678c344f6c5e97dff3bc8a59 /doc | |
parent | e0c8fc977738ca4ac6d31e45bdd2aa1b32828f54 (diff) | |
parent | bec679624c642fb9914c8c43672c249ab0c1ab4c (diff) | |
download | Qt-536d0f141a13474122f99daf98bf6b54e635b474.zip Qt-536d0f141a13474122f99daf98bf6b54e635b474.tar.gz Qt-536d0f141a13474122f99daf98bf6b54e635b474.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt into 4.7
Conflicts:
src/declarative/graphicsitems/qdeclarativeitem.cpp
Diffstat (limited to 'doc')
-rw-r--r-- | doc/src/classes.qdoc | 4 | ||||
-rw-r--r-- | doc/src/examples/dragdroprobot.qdoc | 334 | ||||
-rw-r--r-- | doc/src/examples/elasticnodes.qdoc | 391 | ||||
-rw-r--r-- | doc/src/getting-started/examples.qdoc | 4 | ||||
-rw-r--r-- | doc/src/getting-started/installation.qdoc | 203 | ||||
-rw-r--r-- | doc/src/platforms/platform-notes.qdoc | 29 | ||||
-rw-r--r-- | doc/src/snippets/code/doc_src_installation.qdoc | 86 |
7 files changed, 1028 insertions, 23 deletions
diff --git a/doc/src/classes.qdoc b/doc/src/classes.qdoc index 6ba31a2..1552f56 100644 --- a/doc/src/classes.qdoc +++ b/doc/src/classes.qdoc @@ -59,7 +59,7 @@ /*! \page classes.html - \title All Qt Classes (main index) + \title All Qt Classes \ingroup classlists \brief If you know the name of the class you want, find it here. @@ -146,7 +146,7 @@ /*! \page functions.html - \title All Functions (main index) + \title All Functions \ingroup funclists \brief All documented Qt functions listed alphabetically with a diff --git a/doc/src/examples/dragdroprobot.qdoc b/doc/src/examples/dragdroprobot.qdoc index 413f190..887b254 100644 --- a/doc/src/examples/dragdroprobot.qdoc +++ b/doc/src/examples/dragdroprobot.qdoc @@ -43,9 +43,337 @@ \example graphicsview/dragdroprobot \title Drag and Drop Robot Example - This GraphicsView example shows how to implement drag and drop in - a QGraphicsItem subclass, as well as how to animate items using - QGraphicsItemAnimation and QTimeLine. + This GraphicsView example shows how to implement Drag and Drop in a + QGraphicsItem subclass, as well as how to animate items using Qt's + \l{Animation Framework}. \image dragdroprobot-example.png + + Graphics View provides the QGraphicsScene class for managing and + interacting with a large number of custom-made 2D graphical items derived + from the QGraphicsItem class, and a QGraphicsView widget for visualizing + the items, with support for zooming and rotation. + + This example consists of a \c Robot class, a \c ColorItem class, and a main + function: the \c Robot class describes a simple robot consisting of several + \c RobotPart derived limbs, including \c RobotHead and \c RobotLimb, the \c + ColorItem class provides a draggable colored ellipse, and the \c main() + function provides the main application window. + + We will first review the \c Robot class to see how to assemble the + different parts so that they can be individually rotated and animated using + QPropertyAnimation, and we will then review the \c ColorItem class to + demonstrate how to implement Drag and Drop between items. Finally we will + review the main() function to see how we can put all the pieces together, + to form the final application. + + \section1 Robot Class Definition + + The robot consists of three main classes: the \c RobotHead, the \c + RobotTorso, and the \c RobotLimb, which is used for the upper and lower + arms and legs. All parts derive from the \c RobotPart class, which in turn + inherits \c QGraphicsObject. The \c Robot class itself has no visual + appearance and serves only as a root node for the robot. + + Let's start with the \c RobotPart class declaration. + + \snippet examples/graphicsview/dragdroprobot/robot.h 0 + + This base class inherits QGraphicsObject. QGraphicsObject provides signals + and slots through inheriting QObject, and it also declares QGraphicsItem's + properties using Q_PROPERTY, which makes the properties accessible for + QPropertyAnimation. + + RobotPart also implements the three most important event handlers for + accepting drop events: + \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()}, + \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()}, and + \l{QGraphicsItem::dropEvent()}{dropEvent()}. + + The color is stored as a member variable, along with the \c dragOver + variable, which we will use later to indicate visually that the limb can + accept colors that are is dragged onto it. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 0 + + \c RobotPart's constructor initializes the dragOver member and sets the + color to Qt::lightGray. In the constructor body we enable support for + accepting drop events by calling + \l{QGraphicsItem::setAcceptDrops()}{setAcceptDrops(true)}. + + The rest of this class's implementation is to support Drag and Drop. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 1 + + The \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} handler is called + when a Drag and Drop element is dragged into the robot part's area. + + The handler implementation determines whether or not this item as a whole + can accept the mime data assiciated with the incoming drag object. \c + RobotPart provides a base behavior for all parts that accepts color drops. + So if the incoming drag object contains a color, the event is accepted, we + set \c dragOver to \c true and call update() to help provide positive + visual feedback to the user; otherwise the event is ignored, which in turn + allows the event to propagate to parent elements. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 2 + + The \l{QGraphicsItem::dragLeaveEvent()}{dragLeaveEvent()} handler is called + when a Drag and Drop element is dragged away from the robot part's area. + Our implementation simply resets \e dragOver to false and calls + \l{QGraphicsItem::update()}{update()} to help provide visual feedback that + the drag has left this item. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 3 + + The \l{QGraphicsItem::dropEvent()}{dropEvent()} handler is called when a + Drag and Drop element is dropped onto an item (i.e., when the mouse button + is released over the item while dragging). + + We reset \c dragOver to false, assign the item's new color, and call + \l{QGraphicsItem::update()}{update()}. + + The declaration and implementation of \c RobotHead, \c RobotTorso, and \c + RobotLimb are practically identical. We will review \c RobotHead in detail, + as this class has one minor difference, and leave the other classes as an + exercise for the reader. + + \snippet examples/graphicsview/dragdroprobot/robot.h 1 + + The \c RobotHead class inherits \c RobotPart and provides the necessary + implementations of \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()}. It also reimplements + \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} and dropEvent() to + provide special handling of image drops. + + The class contains a private pixmap member that we can use to implement + support for accepting image drops. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 4 + + \c RobotHead has a rather plain constructor that simply forwards to + \c RobotPart's constructor. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 5 + + The \l{QGraphicsItem::boundingRect()}{boundingRect()} reimplementation + returns the extents for the head. Because we want the center of rotation to + be the bottom center of the item, we have chosen a bounding rectangle that + starts at (-15, -50) and extends to 30 units wide and 50 units tall. When + rotating the head, the "neck" will stay still while the top of the head + tilts from side to side. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 6 + + In \l{QGraphicsItem::paint()}{paint()} we draw the actual head. The + implementation is split into two sections; if an image has been dropped + onto the head, we draw the image, otherwise we draw a round rectangular + robot head with simple vector graphics. + + For performance reasons, depending on the complexity of what is painted, it + can often be faster to draw the head as an image rather than using a + sequence of vector operations. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 7 + + The robot head can accept image drops. In order to support this, its + reimplementation of \l{QGraphicsItem::dragEnterEvent()}{dragEnterEvent()} + checks if the drag object contains image data, and if it does, then the + event is accepted. Otherwise we fall back to the base \c RobotPart + implementation. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 8 + + To follow up on image support, we must also implement + \l{QGraphicsItem::dropEvent()}{dropEvent()}. We check if the drag object + contains image data, and if it does, we store this data as a member pixmap + and call \l{QGraphicsItem::update()}{update()}. This pixmap is used inside + the \l{QGraphicsItem::paint()}{paint()} implementation that we reviewed + before. + + \c RobotTorso and \c RobotLimb are similar to \c RobotHead, so let's + skip directly to the \c Robot class. + + \snippet examples/graphicsview/dragdroprobot/robot.h 4 + + The \c Robot class also inherits \c RobotPart, and like the other parts it + also implements \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()}. It provides a rather special + implementation, though: + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 9 + + Because the \c Robot class is only used as a base node for the rest of the + robot, it has no visual representation. Its + \l{QGraphicsItem::boundingRect()}{boundingRect()} implementation can + therefore return a null QRectF, and its paint() function does nothing. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 10 + + The constuctor starts by setting the flag + \l{QGraphicsItem::ItemHasNoContents}{ItemHasNoContents}, which is a minor + optimization for items that have no visual appearance. + + We then construct all the robot parts (head, torso, and upper/lower arms + and legs). The stacking order is very important, and we use the + parent-child hierarchy to ensure the elements rotate and move properly. We + construct the torso first, as this is the root element. We then construct + the head and pass the torso to \c HeadItem's constructor. This will make + the head a child of the torso; if you rotate the torso, the head will + follow. The same pattern is applied to the rest of the limbs. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 11 + + Each robot part is carefully positioned. For example, the upper left arm is + moved precisely to the top-left area of the torso, and the upper right arm + is moved to the top-right area. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 12 + + The next section creates all animation objects. This snippet shows the two + animations that operate on the head's scale and rotation. The two + QPropertyAnimation instances simply set the object, property, and + respective start and end values. + + All animations are controlled by one top-level parallel animation group. + The scale and rotation animations are added to this group. + + The rest of the animations are defined in a similar way. + + \snippet examples/graphicsview/dragdroprobot/robot.cpp 13 + + Finally we set an easing curve and duration on each animation, ensure the + toplevel animation group loops forever, and start the toplevel animation. + + \section1 ColorItem Class Definition + + The \c ColorItem class represents a circular item that can be pressed to + drag colors onto robot parts. + + \snippet examples/graphicsview/dragdroprobot/coloritem.h 0 + + This class is very simple. It does not use animations, and has no need for + properties nor signals and slots, so to save resources, it's most natural + that it inherits QGraphicsItem (as opposed to QGraphicsObject). + + It declares the mandatory \l{QGraphicsItem::boundingRect()}{boundingRect()} + and \l{QGraphicsItem::paint()}{paint()} functions, and adds + reimplementations of + \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()}, + \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()}, and + \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()}. It contains a + single private color member. + + Let's take a look at its implementation. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 0 + + \c ColorItem's constructor assigns an opaque random color to its color + member by making use of qrand(). For improved usability, it assigns a + tooltip that provides a useful hint to the user, and it also sets a + suitable cursor. This ensures that the cursor will chance to + Qt::OpenHandCursor when the mouse pointer hovers over the item. + + Finally, we call + \l{QGraphicsItem::setAcceptedMouseButtons()}{setAcceptedMouseButtons()} to + ensure that this item can only process Qt::LeftButton. This simplifies the + mouse event handlers greatly, as we can always assume that only the left + mouse button is pressed and released. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 1 + + The item's bounding rect is a fixed 30x30 units centered around the item's + origin (0, 0), and adjusted by 0.5 units in all directions to allow a + scalable pen to draw its outline. For a final visual touch the bounds + also compensate with a few units down and to the right to make room + for a simple dropshadow. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 2 + + The \l{QGraphicsItem::paint()}{paint()} implementation draws an ellipse + with a 1-unit black outline, a plain color fill, and a dark gray + dropshadow. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 3 + + The \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()} handler is + called when you press the mouse button inside the item's area. Our + implementation simply sets the cursor to Qt::ClosedHandCursor. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 4 + + The \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()} handler is + called when you release the mouse button after having pressed it inside an + item's area. Our implementation sets the cursor back to Qt::OpenHandCursor. + The mouse press and release event handlers together provide useful visual + feedback to the user: when you move the mouse pointer over a \c CircleItem, + the cursor changes to an open hand. Pressing the item will show a closed + hand cursor. Releasing will restore to an open hand cursor again. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 5 + + The \l{QGraphicsItem::mouseMoveEvent()}{mouseMoveEvent()} handler is called + when you move the mouse around after pressing the mouse button inside the + \c ColorItem's area. This implementation provides the most important piece + of logic for \c CircleItem: the code that starts and manages drags. + + The implementation starts by checking if the mouse has been dragged far + enough to eliminate mouse jitter noise. We only want to start a drag if the + mouse has been dragged farther than the application start drag distance. + + Continuing, we create a QDrag object, passing the event + \l{QGraphicsSceneEvent::widget()}{widget} (i.e., the QGraphicsView + viewport) to its constructor. Qt will ensure that this object is deleted at + the right time. We also create a QMimeData instance that can contain our + color or image data, and assign this to the drag object. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 6 + + This snippet has a somewhat random outcome: once in a while, a special + image is assigned to the drag object's mime data. The pixmap is also + assiged as the drag object's pixmap. This will ensure that you can see the + image that is being dragged as a pixmap under the mouse cursor. + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 7 + + Otherwise, and this is the most common outcome, a simple color is assigned + to the drag object's mime data. We render this \c ColorItem into a new + pixmap to give the user visual feedback that the color is being "dragged". + + \snippet examples/graphicsview/dragdroprobot/coloritem.cpp 8 + + Finally we execute the drag. QDrag::exec() will reenter the event loop, and + only exit if the drag has either been dropped, or canceled. In any case we + reset the cursor to Qt::OpenHandCursor. + + \section1 The main() Function + + Now that the \c Robot and \c ColorItem classes are complete, we can put all + the pieces together inside the main() function. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 0 + + We start off by constructing QApplication, and initializing the random + number generator. This ensures that the color items have different colors + every time the application starts. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 1 + + We construct a fixed size scene, and create 10 \c ColorItem instances + arranged in a circle. Each item is added to the scene. + + In the center of this circle we create one \c Robot instance. The + robot is scaled and moved up a few units. It is then added to the scene. + + \snippet examples/graphicsview/dragdroprobot/main.cpp 2 + + Finally we create a QGraphicsView window, and assign the scene to it. + + For increased visual quality, we enable antialiasing. We also choose to use + bounding rectangle updates to simplify visual update handling. + The view is given a fixed sand-colored background, and a window title. + + We then show the view. The animations start immediately after + control enters the event loop. */ + diff --git a/doc/src/examples/elasticnodes.qdoc b/doc/src/examples/elasticnodes.qdoc index f7b1c37..edc62d8 100644 --- a/doc/src/examples/elasticnodes.qdoc +++ b/doc/src/examples/elasticnodes.qdoc @@ -43,7 +43,396 @@ \example graphicsview/elasticnodes \title Elastic Nodes Example - This GraphicsView example shows how to implement edges between nodes in a graph. + This GraphicsView example shows how to implement edges between nodes in a + graph, with basic interaction. You can click to drag a node around, and + zoom in and out using the mouse wheel or the keyboard. Hitting the space + bar will randomize the nodes. The example is also resolution independent; + as you zoom in, the graphics remain crisp. \image elasticnodes-example.png + + Graphics View provides the QGraphicsScene class for managing and + interacting with a large number of custom-made 2D graphical items derived + from the QGraphicsItem class, and a QGraphicsView widget for visualizing + the items, with support for zooming and rotation. + + This example consists of a \c Node class, an \c Edge class, a \c + GraphWidget test, and a \c main function: the \c Node class represents + draggable yellow nodes in a grid, the \c Edge class represents the lines + between the nodes, the \c GraphWidget class represents the application + window, and the \c main() function creates and shows this window, and runs + the event loop. + + \section1 Node Class Definition + + The \c Node class serves three purposes: + + \list + \o Painting a yellow gradient "ball" in two states: sunken and raised. + \o Managing connections to other nodes. + \o Calculating forces pulling and pushing the nodes in the grid. + \endlist + + Let's start by looking at the \c Node class declaration. + + \snippet examples/graphicsview/elasticnodes/node.h 0 + + The \c Node class inherits QGraphicsItem, and reimplements the two + mandatory functions \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \l{QGraphicsItem::paint()}{paint()} to provide its visual appearance. It + also reimplements \l{QGraphicsItem::shape()}{shape()} to ensure its hit + area has an elliptic shape (as opposed to the default bounding rectangle). + + For edge management purposes the node provides a simple API for adding + edges to a node, and for listing all connected edges. + + The \l{QGraphicsItem::advance()}{advance()} reimplementation is called + whenever the scene's state advances by one step. The calculateForces() + function is called to calculate the forces that push and pull on this node + and its neighbors. + + The \c Node class also reimplements + \l{QGraphicsItem::itemChange()}{itemChange()} to react to state changes (in + this case, position changes), and + \l{QGraphicsItem::mousePressEvent()}{mousePressEvent()} and + \l{QGraphicsItem::mouseReleaseEvent()}{mouseReleaseEvent()} to update the + item's visual appearance. + + We will start reviewing the \c Node implementation by looking at its + constructor: + + \snippet examples/graphicsview/elasticnodes/node.cpp 0 + + In the constructor, we set the + \l{QGraphicsItem::ItemIsMovable}{ItemIsMovable} flag to allow the item to + move in response to mouse dragging, and + \l{QGraphicsItem::ItemSendsGeometryChanges}{ItemSendsGeometryChanges} to + enable \l{QGraphicsItem::itemChange()}{itemChange()} notifications for + position and transformation changes. We also enable + \l{QGraphicsItem::DeviceCoordinateCache}{DeviceCoordinateCache} to speed up + rendering performance. To ensure that the nodes are always stacked on top + of edges, we finally set the item's Z value to -1. + + \c Node's constructor takes a \c GraphWidget pointer and stores this as a + member variable. We will revisit this pointer later on. + + \snippet examples/graphicsview/elasticnodes/node.cpp 1 + + The addEdge() function adds the input edge to a list of attached edges. The + edge is then adjusted so that the end points for the edge match the + positions of the source and destination nodes. + + The edges() function simply returns the list of attached edges. + + \snippet examples/graphicsview/elasticnodes/node.cpp 2 + + The \e calculateForces() function implements the elastic forces effect that + pulls and pushes on nodes in the grid. In addition to this algorithm, the + user can move one node around with the mouse. Because we do not want the + two to interfere, we start by checking if this \c Node is the current mouse + grabber item (i.e., QGraphicsScene::mouseGrabberItem()). Because we need to + find all neighboring (but not necessarily connected) nodes, we also make + sure the item is part of a scene in the first place. + + \snippet examples/graphicsview/elasticnodes/node.cpp 3 + + The algorithm has two steps: the first is to calculate the forces that push + the nodes apart, and the second is to subtract the forces that pull the + nodes together. First we need to find all the nodes in the graph. We call + QGraphicsScene::items() to find all items in the scene, and then use + qgraphicsitem_cast() to look for \c Node instances. + + We make use of \l{QGraphicsItem::mapFromItem()}{mapFromItem()} to create a + vector pointing from this node to each other node, in \l{The Graphics View + Coordinate System}{local coordinates}. We use the decomposed components of + this vector to determine the direction and strength of force that apply to + the node. The forces are added up for each node, and weighted so that the + closest nodes are given the strongest force. The sum of all forces are + stored in \e xvel (X-velocity) and \e yvel (Y-velocity). + + \snippet examples/graphicsview/elasticnodes/node.cpp 4 + + The edges between the nodes represent the forces that pull the nodes + together. By visiting each edge that is connected to this node, we can use + a similar approach as above to find the direction and strength of all + forces. These forces are subtracted from \e xvel and \e yvel. + + \snippet examples/graphicsview/elasticnodes/node.cpp 5 + + In theory, the sum of pushing and pulling forces should stabilize to + precisely 0. In practise, however, they never do. To circumvent errors in + numerical precision, we simply force the sum of forces to be 0 when they + are less than 0.1. + + \snippet examples/graphicsview/elasticnodes/node.cpp 6 + + The final step of \e calculateForces() determines the node's new position. + We add the force to the node's current position. We also make sure the new + position stays inside of our defined boundaries. We don't actually move the + item in this function; that's done in a separate step, from \e advance(). + + \snippet examples/graphicsview/elasticnodes/node.cpp 7 + + The \e advance() function updates the item's current position. It is called + from \e GraphWidget::timerEvent(). If the node's position changed, the + function returns true; otherwise false is returned. + + \snippet examples/graphicsview/elasticnodes/node.cpp 8 + + The \e Node's bounding rectangle is a 20x20 sized rectangle centered around + its origin (0, 0), adjusted by 2 units in all directions to compensate for + the node's outline stroke, and by 3 units down and to the right to make + room for a simple drop shadow. + + \snippet examples/graphicsview/elasticnodes/node.cpp 9 + + The shape is a simple ellipse. This ensures that you must click inside the + node's elliptic shape in order to drag it around. You can test this effect + by running the example, and zooming far enough in so that the nodes become + very large. Without reimplementing \l{QGraphicsItem::shape()}{shape()}, the + item's hit area would be identical to its bounding rectangle (i.e., + rectangular). + + \snippet examples/graphicsview/elasticnodes/node.cpp 10 + + This function implements the node's painting. We start by drawing a simple + dark gray elliptic drop shadow at (-7, -7), that is, (3, 3) units down and + to the right. + + We then draw an ellipse with a radial gradient fill. This fill is either + Qt::yellow to Qt::darkYellow when raised, or the opposite when sunken. In + sunken state we also shift the center and focal point by (3, 3) to + emphasize the impression that something has been pushed down. + + Drawing filled ellipses with gradients can be quite slow, especially when + using complex gradients such as QRadialGradient. This is why this example + uses \l{QGraphicsItem::DeviceCoordinateCache}{DeviceCoordinateCache}, a + simple yet effective measure that prevents unnecessary redrawing. + + \snippet examples/graphicsview/elasticnodes/node.cpp 11 + + We reimplement \l{QGraphicsItem::itemChange()}{itemChange()} to adjust the + position of all connected edges, and to notify the scene that an item has + moved (i.e., "something has happened"). This will trigger new force + calculations. + + This notification is the only reason why the nodes need to keep a pointer + back to the \e GraphWidget. Another approach could be to provide such + notification using a signal; in such case, \e Node would need to inherit + from QGraphicsObject. + + \snippet examples/graphicsview/elasticnodes/node.cpp 12 + + Because we have set the \l{QGraphicsItem::ItemIsMovable}{ItemIsMovable} + flag, we don't need to implement the logic that moves the node according to + mouse input; this is already provided for us. We still need to reimplement + the mouse press and release handlers though, to update the nodes' visual + appearance (i.e., sunken or raised). + + \section1 Edge Class Definition + + The \e Edge class represents the arrow-lines between the nodes in this + example. The class is very simple: it maintains a source- and destination + node pointer, and provides an \e adjust() function that makes sure the line + starts at the position of the source, and ends at the position of the + destination. The edges are the only items that change continuously as + forces pull and push on the nodes. + + Let's take a look at the class declaration: + + \snippet examples/graphicsview/elasticnodes/edge.h 0 + + \e Edge inherits from QGraphicsItem, as it's a simple class that has no use + for signals, slots, and properties (compare to QGraphicsObject). + + The constructor takes two node pointers as input. Both pointers are + mandatory in this example. We also provide get-functions for each node. + + The \e adjust() function repositions the edge, and the item also implements + \l{QGraphicsItem::boundingRect()}{boundingRect()} and + \{QGraphicsItem::paint()}{paint()}. + + We will now review its implementation. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 0 + + The \e Edge constructor initializes its arrowSize data member to 10 units; + this determines the size of the arrow which is drawn in + \l{QGraphicsItem::paint()}{paint()}. + + In the constructor body, we call + \l{QGraphicsItem::setAcceptedMouseButtons()}{setAcceptedMouseButtons(0)}. + This ensures that the edge items are not considered for mouse input at all + (i.e., you cannot click the edges). Then, the source and destination + pointers are updated, this edge is registered with each node, and we call + \e adjust() to update this edge's start end end position. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 1 + + The source and destination get-functions simply return the respective + pointers. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 2 + + In \e adjust(), we define two points: \e sourcePoint, and \e destPoint, + pointing at the source and destination nodes' origins respectively. Each + point is calculated using \l{The Graphics View Coordinate System}{local + coordinates}. + + We want the tip of the edge's arrows to point to the exact outline of the + nodes, as opposed to the center of the nodes. To find this point, we first + decompose the vector pointing from the center of the source to the center + of the destination node into X and Y, and then normalize the components by + dividing by the length of the vector. This gives us an X and Y unit delta + that, when multiplied by the radius of the node (which is 10), gives us the + offset that must be added to one point of the edge, and subtracted from the + other. + + If the length of the vector is less than 20 (i.e., if two nodes overlap), + then we fix the source and destination pointer at the center of the source + node. In practise this case is very hard to reproduce manually, as the + forces between the two nodes is then at its maximum. + + It's important to notice that we call + \l{QGraphicsItem::prepareGeometryChange()}{prepareGeometryChange()} in this + function. The reason is that the variables \e sourcePoint and \e destPoint + are used directly when painting, and they are returned from the + \l{QGraphicsItem::boundingRect()}{boundingRect()} reimplementation. We must + always call + \l{QGraphicsItem::prepareGeometryChange()}{prepareGeometryChange()} before + changing what \l{QGraphicsItem::boundingRect()}{boundingRect()} returns, + and before these variables can be used by + \l{QGraphicsItem::paint()}{paint()}, to keep Graphics View's internal + bookkeeping clean. It's safest to call this function once, immediately + before any such variable is modified. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 3 + + The edge's bounding rectangle is defined as the smallest rectangle that + includes both the start and the end point of the edge. Because we draw an + arrow on each edge, we also need to compensate by adjusting with half the + arrow size and half the pen width in all directions. The pen is used to + draw the outline of the arrow, and we can assume that half of the outline + can be drawn outside of the arrow's area, and half will be drawn inside. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 4 + + We start the reimplementation of \l{QGraphicsItem::paint()}{paint()} by + checking a few preconditions. Firstly, if either the source or destination + node is not set, then we return immediately; there is nothing to draw. + + At the same time, we check if the length of the edge is approximately 0, + and if it is, then we also return. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 5 + + We draw the line using a pen that has round joins and caps. If you run the + example, zoom in and study the edge in detail, you will see that there are + no sharp/square edges. + + \snippet examples/graphicsview/elasticnodes/edge.cpp 6 + + We proceed to drawing one arrow at each end of the edge. Each arrow is + drawn as a polygon with a black fill. The coordinates for the arrow are + determined using simple trigonometry. + + \section1 GraphWidget Class Definition + + \e GraphWidget is a subclass of QGraphicsView, which provides the main + window with scrollbars. + + \snippet examples/graphicsview/elasticnodes/graphwidget.h 0 + + It provides a basic constructor that initializes the scene, an \e + itemMoved() function to notify changes in the scene's node graph, a few + event handlers, a reimplementation of + \l{QGraphicsView::drawBackground()}{drawBackground()}, and a helper + function for scaling the view by mouse or keyboard. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 0 + + \e GraphicsWidget's constructor creates the scene, and because most items + move around most of the time, it sets QGraphicsScene::NoIndex. Then the + scene gets a fixed \l{QGraphicsScene::sceneRect}{scene rectangle}. + The scene is then assigned to the \e GraphWidget view. + + The view enables QGraphicsView::CacheBackground to cache rendering of its + static and somewhat complex background. Because the graph renders a close + collection of small items that all move around, it's unnecessary for + Graphics View to waste time finding accurate update regions, so we set the + QGraphicsView::BoundingRectViewportUpdate viewport update mode. The default + would work fine, but this mode is noticably faster for this example. + + To improve rendering quality, we set QPainter::Antialiasing. + + The transformation anchor decides how the view should scroll when you + transform the view, or in our case, when we zoom in or out. We have chosen + QGraphicsView::AnchorUnderMouse, which centers the view on the point under + the mouse cursor. This makes it easy to zoom towards a point in the scene + by moving the mouse over it, and then rolling the mouse wheel. + + Finally we give the window a minimum size that matches the scene's default + size, and set a suitable window title. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 1 + + The last part of the constructor creates the grid of nodes and edges, and + gives each node an initial position. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 2 + + \e GraphWidget is notified of node movement through this \e itemMoved() + function. Its job is simply to restart the main timer in case it's not + running already. The timer is designed to stop when the graph stabilizes, + and start once it's unstable again. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 3 + + This is \e GraphWidget's key event handler. The arrow keys move the center + node around, the '+' and '-' keys zoom in and out by calling \e + scaleView(), and the enter and space keys randomize the positions of the + nodes. All other key events (e.g., page up and page down) are handled by + QGraphicsView's default implementation. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 4 + + The timer event handler's job is to run the whole force calculation + machinery as a smooth animation. Each time the timer is triggered, the + handler will find all nodes in the scene, and call \e + Node::calculateForces() on each node, one at a time. Then, in a final step + it will call \e Node::advance() to move all nodes to their new positions. + By checking the return value of \e advance(), we can decide if the grid + stabilized (i.e., no nodes moved). If so, we can stop the timer. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 5 + + In the wheel event handler, we convert the mouse wheel delta to a scale + factor, and pass this factor to \e scaleView(). This approach takes into + account the speed that the wheel is rolled. The faster you roll the mouse + wheel, the faster the view will zoom. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 6 + + The view's background is rendered in a reimplementation of + QGraphicsView::drawBackground(). We draw a large rectangle filled with a + linear gradient, with a drop shadow, and then render text in top. The text + is rendered twice to give a similar simple drop-shadow effect. + + This background rendering is quite expensive; this is why the view enables + QGraphicsView::CacheBackground. + + \snippet examples/graphicsview/elasticnodes/graphwidget.cpp 7 + + The \e scaleView() helper function checks that the scale factor stays + within certain limits (i.e., you cannot zoom too far in nor too far out), + and then applies this scale. + + \section1 The main() Function + + In contrast to the complexity of the rest of this example, the \e main() + function is very simple: We create a QApplication instance, seed the + randomizer using qsrand(), and then create and show an instance of \e + GraphWidget. Because all nodes in the grid are moved initially, the \e + GraphWidget timer will start immediately after control has returned to the + event loop. */ diff --git a/doc/src/getting-started/examples.qdoc b/doc/src/getting-started/examples.qdoc index 071a107..542f672 100644 --- a/doc/src/getting-started/examples.qdoc +++ b/doc/src/getting-started/examples.qdoc @@ -649,8 +649,8 @@ \list \o \l{graphicsview/collidingmice}{Colliding Mice}\raisedaster \o \l{graphicsview/diagramscene}{Diagram Scene}\raisedaster - \o \l{graphicsview/dragdroprobot}{Drag and Drop Robot} - \o \l{graphicsview/elasticnodes}{Elastic Nodes} + \o \l{graphicsview/dragdroprobot}{Drag and Drop Robot}\raisedaster + \o \l{graphicsview/elasticnodes}{Elastic Nodes}\raisedaster \o \l{graphicsview/portedasteroids}{Ported Asteroids} \o \l{graphicsview/portedcanvas}{Ported Canvas} \endlist diff --git a/doc/src/getting-started/installation.qdoc b/doc/src/getting-started/installation.qdoc index 3a9d4ea..3ea351e 100644 --- a/doc/src/getting-started/installation.qdoc +++ b/doc/src/getting-started/installation.qdoc @@ -697,6 +697,209 @@ If you are using pre-built binaries, follow the instructions given in the \endlist */ +/*! \page install-Symbian-linux.html +\title Installing Qt on the Symbian platform using Linux (experimental) +\ingroup installation +\ingroup qtsymbian +\brief How to install Qt on the Symbian platform using Linux. + +\note Qt for the Symbian platform has some requirements that are given in more detail +in the \l{Qt for the Symbian platform Requirements} document. TODO list requirements like SDK here. + +\note \bold {This document describes how to install and configure Qt for +the Symbian platform from scratch, using Linux as the build host. +Qt does not come with a binary package for Linux yet, but if you want to avoid +the full build of Qt and start developing applications right away, you can +download drop-in binaries from here: TODO} + +\list 1 + + \o Setup the development environment + + TODO Make sure your Symbian development environment is correctly installed and + patched as explained in the \l{Qt for the Symbian platform Requirements} document. + + \o Install Qt + + Uncompress the \l{http://qt.nokia.com/downloads}{downloaded} source package into the + directory you want Qt installed, e.g. \c{/home/user/qt/%VERSION%}. + + \o Environment variables + + In order to build and use Qt, the \c PATH environment variable needs + to be extended to fine Qt tools and also to find the Symbian platform tools: + + First you need to set the \c EPOCROOT environment variable to point to the location + of your S60 SDK: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 36 + + Then you can update the PATH variable; + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 37 + + \o Configure Qt + + To configure Qt for the Symbian platform, do: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 38 + to build the libraries using RVCT or + \snippet doc/src/snippets/code/doc_src_installation.qdoc 39 + to build the libraries using GCCE. + + \o Build Qt + + To build Qt for the device, type: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 40 + + Congratulations, Qt is now ready to use. + + \o Building Qt packages for the device + + To run any application or demo on a real device, you need to install it + on the device. To do this you first have to create a a package for the + device, containing the libraries: + + \list A + \o Building a Qt package without a certificate + + If you have no certificate, build a self signed Qt: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 41 + + The Qt libraries are built with "All -Tcb" capability, so that + they can support all types of applications. However, these + capabilities are automatically lowered if you make a selfsigned + package. + + \o Building a Qt package with a Symbian developer certificate + + If you have a symbian-signed developer certificate, specify the + capabilities you can sign for, for example: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 42 + \endlist + + \o Installing Qt packages to the device. + + It is possible to install packages to a phone in Linux by putting + the package on the phone memory card and then installing manually + from the phone menu. However, this is tedious and will not work + on phones without a memory card, so the method recommended by Qt is + to use the App TRK tool. + + \list a + \o Obtaining the App TRK package. + + Download the package from the following location. + + \list + \o \l{http://tools.ext.nokia.com/trk/}{Application TRK}. + Choose the correct installation package based on the + S60 version of your device + (\c{S60_<S60-version>_app_trk_<TRK-version>.sisx}). + \endlist + + This package currently has to be installed by putting the + package on the memory card and installing from the phone + menu, or using a Windows PC for doing the install. However, + the installation only has to be done once. + + \o Configuring App TRK on the phone. + + When App TRK is installed, connect the phone to the PC using + the USB cable. Select "PCSuite" as connection type. Then run + App TRK on the phone, and make sure that the connection type is + USB. This can be changed under + the \c Settings menu entry. If necessary, choose \c Connect + from the menu. + + \o Configuring the USB serial driver on the Linux system. + + On Linux, phone should appear as the \c /dev/ttyUSB1 device, + however if you are running an old kernel, you may need to + force the USB module to be loaded correctly before the device + will appear: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 43 + + Note the identifier on the line where your Symbian device + appears. Then execute the following, using the first and + second part of the identifier in place of \c XXXX, + respectively. + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 44 + + The \c rmmod step may fail if the module is not already + loaded, but that is harmless. + + \o Building the \c runonphone tool. + + Note that building the \c runonphone tool requires a separate + installation of Qt for Linux. If there is a version of Qt + installed by your distribution's package mechanism, that that + should do fine. Some distributions separate the libraries from + the development setup which includes qmake. Make sure you have + both installed. + + First make sure that the \c qmake you use is taken from the + Linux installation of Qt. The easiest way to make sure of this + is to open a new shell and run the following command: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 45 + + \c qmake will tell you where it is installed. + + Copy the \c{%QTDIR%/tools/runonphone} folder to a place outside + of the Qt tree. Then go to the folder in a shell and build it: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 46 + + Copy the resulting executable to a folder which is in your + \c PATH environment variable. + + \o Installing the built package onto the phone. + + Return to the root of the Qt tree configured for Symbian. Then + install the Qt libraries by running the following: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 47 + + \note If the installation fails, please make sure that there is + no previously installed version of Qt on the phone. + + Qt requires some dependent packages to be installed on the device, + they are shipped in the Symbian SDK and can be installed using the + runonphone tool as well. + The packages can be found in the EPOCROOT at the following locations; + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 50 + + \endlist + + \o Running Qt demos + + We've included a subset of the Qt demos in this package for you + to try out. An excellent starting point is the "fluidlauncher" + demo. + + Install and run the demo by using the following commands: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 48 + + The same command can be used for other applications: + + \snippet doc/src/snippets/code/doc_src_installation.qdoc 49 + + For more information about building and running Qt programs on the + Symbian platform, see \l{The Symbian platform - Introduction to Qt}. + + We hope you will enjoy using Qt. + +\endlist + +*/ /*! \page requirements.html \title General Qt Requirements diff --git a/doc/src/platforms/platform-notes.qdoc b/doc/src/platforms/platform-notes.qdoc index 83f2833..8f5b6a5 100644 --- a/doc/src/platforms/platform-notes.qdoc +++ b/doc/src/platforms/platform-notes.qdoc @@ -411,7 +411,7 @@ \section1 Source Compatibility Qt for Symbian provides the same level of source compatibility guarantee as - given for other platforms. That is, a program which compiles against a given + given for other platforms. That is, a program which compiles against a given version of Qt for Symbian will also compile against all future versions of the same major release. @@ -496,28 +496,31 @@ \section1 Required Capabilities - Distributions of Qt are typically signed with \c{All -TCB}. What your - application needs to be signed with in order to function with Qt depends - on what functionality it uses: + The Qt libraries are typically signed with \c{All -TCB} capabilites, but + that does not mean your Qt application needs to be signed with the same + capabilities to function properly. The capabilities your application needs + to function properly depends on which parts of Qt you use, here is an + overview: \table - \header \o Technology + \header \o Module \o Required Symbian Capability \row \o QtCore - \o \c PowerMgmt if applications are terminated using QProcess. + \o \c PowerMgmt if QProcess::kill(...) or QProcess::terminate(...) is called. + \row \o QtCore + \o \c AllFiles when \l{http://developer.symbian.org/wiki/index.php/Capabilities_%28Symbian_Signed%29/AllFiles_Capability}{accessing specific areas.} \row \o QtNetwork - \o NetworkServices + \o \c NetworkServices is basically always required for this module. \row \o QtMultiMedia \o \c UserEnvironment if QAudioInput is used. \endtable - Depending on what file paths that are accessed and how AllFiles may be - required. Similarly, if the network is accessed indirectly through - components such as QtXmlPatterns, QtWebkit or QtScript, the capabilities - needs to match accordingly. + Note that some modules rely on other modules. If your application uses + QtXmlPatterns, QtWebkit or QtScript it may still require \c NetworkServices + \o as these modules rely on QtNetwork to go online. - See individual classes' documentation for specifics. If a class does not - mention Symbian capabilities, it requires none. + For more information see the documentation of the individual Qt classes. If + a class does not mention Symbian capabilities, it requires none. \section1 Multimedia and Phonon Support diff --git a/doc/src/snippets/code/doc_src_installation.qdoc b/doc/src/snippets/code/doc_src_installation.qdoc index b3c9903..ac94cf7 100644 --- a/doc/src/snippets/code/doc_src_installation.qdoc +++ b/doc/src/snippets/code/doc_src_installation.qdoc @@ -225,10 +225,8 @@ SYMBIANBUILD_DEPENDENCYOFF=1 //! [34] cd src\s60installs -patch_capabilities.pl Qt_template.pkg release-armv5 make sis QT_SIS_OPTIONS=-i cd ..\3rdparty\webkit\WebCore -patch_capabilities.pl QtWebkit_template.pkg release-armv5 make sis QT_SIS_OPTIONS=-i //! [34] @@ -240,3 +238,87 @@ cd ..\3rdparty\webkit\WebCore patch_capabilities.pl QtWebKit_template.pkg release-armv5 "ALL -Tcb -AllFiles -DRM" make sis QT_SIS_OPTIONS=-i QT_SIS_CERTIFICATE=<certificate file> QT_SIS_KEY=<certificate key file> //! [35] + +//! [36] +EPOCROOT=/home/user/s60-sdk/ +export EPOCROOT +//! [36] + +//! [37] +PATH=/home/user/qt/%VERSION%/bin:$EPOCROOT/epoc32/tools:$PATH +export PATH +//! [37] + +//! [38] +cd /home/user/qt/%VERSION% +./configure -platform linux-g++ -xplatform symbian/linux-armcc -arch symbian +//! [38] + +//! [39] +cd /home/user/qt/%VERSION% +./configure -platform linux-g++ -xplatform symbian/linux-gcce -arch symbian -no-webkit +//! [39] + +//! [40] +make +//! [40] + +//! [41] +cd src/s60installs +make sis +//! [41] + +//! [42] +cd src/s60installs +patch_capabilities.pl Qt_template.pkg - "ALL -Tcb -AllFiles -DRM" +make sis QT_SIS_CERTIFICATE=<certificate file> QT_SIS_KEY=<certificate key file> +cd ../3rdparty/webkit/WebCore +patch_capabilities.pl QtWebKit_template.pkg - "ALL -Tcb -AllFiles -DRM" +make sis QT_SIS_CERTIFICATE=<certificate file> QT_SIS_KEY=<certificate key file> +//! [42] + +//! [43] +lsusb +//! [43] + +//! [44] +sudo rmmod usbserial +sudo modprobe usbserial vendor=0x0XXX product=0x0XXX +//! [44] + +//! [45] +$ qmake -version +QMake version 2.01a +Using Qt version 4.6.2 in /usr/lib/qt4 +//! [45] + +//! [46] +cd $HOME/runonphone +qmake +make +//! [46] + +//! [47] +runonphone -s lib/Qt.sis +//! [47] + +//! [48] +cd demos/embedded/fluidlauncher +runonphone -s fluidlauncher.sis fluidlauncher.exe +//! [48] + +//! [49] +cd myapp +qmake +make +make sis +runonphone -s myapp.sis myapp.exe +//! [49] + +//! [50] +nokia_plugin/openc/s60opencsis/openc_ssl_s60_1_6_ss.sis +nokia_plugin/openc/s60opencsis/pips_s60_1_6_ss.sis +nokia_plugin/opencpp/s60opencppsis/stdcpp_s60_1_6_ss.sis +//! [50] + + |