|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the documentation of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 /*! |
|
43 \group statemachine |
|
44 \title State Machine Classes |
|
45 */ |
|
46 |
|
47 /*! |
|
48 \page statemachine-api.html |
|
49 \title The State Machine Framework |
|
50 \brief An overview of the State Machine framework for constructing and executing state graphs. |
|
51 |
|
52 \ingroup frameworks-technologies |
|
53 |
|
54 \tableofcontents |
|
55 |
|
56 The State Machine framework provides classes for creating and executing |
|
57 state graphs. The concepts and notation are based on those from Harel's |
|
58 \l{Statecharts: A visual formalism for complex systems}{Statecharts}, which |
|
59 is also the basis of UML state diagrams. The semantics of state machine |
|
60 execution are based on \l{State Chart XML: State Machine Notation for |
|
61 Control Abstraction}{State Chart XML (SCXML)}. |
|
62 |
|
63 Statecharts provide a graphical way of modeling how a system reacts to |
|
64 stimuli. This is done by defining the possible \e states that the system can |
|
65 be in, and how the system can move from one state to another (\e transitions |
|
66 between states). A key characteristic of event-driven systems (such as Qt |
|
67 applications) is that behavior often depends not only on the last or current |
|
68 event, but also the events that preceded it. With statecharts, this |
|
69 information is easy to express. |
|
70 |
|
71 The State Machine framework provides an API and execution model that can be |
|
72 used to effectively embed the elements and semantics of statecharts in Qt |
|
73 applications. The framework integrates tightly with Qt's meta-object system; |
|
74 for example, transitions between states can be triggered by signals, and |
|
75 states can be configured to set properties and invoke methods on QObjects. |
|
76 Qt's event system is used to drive the state machines. |
|
77 |
|
78 \section1 Classes in the State Machine Framework |
|
79 |
|
80 These classes are provided by qt for creating event-driven state machines. |
|
81 |
|
82 \annotatedlist statemachine |
|
83 |
|
84 \section1 A Simple State Machine |
|
85 |
|
86 To demonstrate the core functionality of the State Machine API, let's look |
|
87 at a small example: A state machine with three states, \c s1, \c s2 and \c |
|
88 s3. The state machine is controlled by a single QPushButton; when the button |
|
89 is clicked, the machine transitions to another state. Initially, the state |
|
90 machine is in state \c s1. The statechart for this machine is as follows: |
|
91 |
|
92 \img statemachine-button.png |
|
93 \omit |
|
94 \caption This is a caption |
|
95 \endomit |
|
96 |
|
97 The following snippet shows the code needed to create such a state machine. |
|
98 First, we create the state machine and states: |
|
99 |
|
100 \snippet doc/src/snippets/statemachine/main.cpp 0 |
|
101 |
|
102 Then, we create the transitions by using the QState::addTransition() |
|
103 function: |
|
104 |
|
105 \snippet doc/src/snippets/statemachine/main.cpp 1 |
|
106 |
|
107 Next, we add the states to the machine and set the machine's initial state: |
|
108 |
|
109 \snippet doc/src/snippets/statemachine/main.cpp 2 |
|
110 |
|
111 Finally, we start the state machine: |
|
112 |
|
113 \snippet doc/src/snippets/statemachine/main.cpp 3 |
|
114 |
|
115 The state machine executes asynchronously, i.e. it becomes part of your |
|
116 application's event loop. |
|
117 |
|
118 \section1 Doing Useful Work on State Entry and Exit |
|
119 |
|
120 The above state machine merely transitions from one state to another, it |
|
121 doesn't perform any operations. The QState::assignProperty() function can be |
|
122 used to have a state set a property of a QObject when the state is |
|
123 entered. In the following snippet, the value that should be assigned to a |
|
124 QLabel's text property is specified for each state: |
|
125 |
|
126 \snippet doc/src/snippets/statemachine/main.cpp 4 |
|
127 |
|
128 When any of the states is entered, the label's text will be changed |
|
129 accordingly. |
|
130 |
|
131 The QState::entered() signal is emitted when the state is entered, and the |
|
132 QState::exited() signal is emitted when the state is exited. In the |
|
133 following snippet, the button's showMaximized() slot will be called when |
|
134 state \c s3 is entered, and the button's showMinimized() slot will be called |
|
135 when \c s3 is exited: |
|
136 |
|
137 \snippet doc/src/snippets/statemachine/main.cpp 5 |
|
138 |
|
139 Custom states can reimplement QAbstractState::onEntry() and |
|
140 QAbstractState::onExit(). |
|
141 |
|
142 \section1 State Machines That Finish |
|
143 |
|
144 The state machine defined in the previous section never finishes. In order |
|
145 for a state machine to be able to finish, it needs to have a top-level \e |
|
146 final state (QFinalState object). When the state machine enters a top-level |
|
147 final state, the machine will emit the QStateMachine::finished() signal and |
|
148 halt. |
|
149 |
|
150 All you need to do to introduce a final state in the graph is create a |
|
151 QFinalState object and use it as the target of one or more transitions. |
|
152 |
|
153 \section1 Sharing Transitions By Grouping States |
|
154 |
|
155 Assume we wanted the user to be able to quit the application at any time by |
|
156 clicking a Quit button. In order to achieve this, we need to create a final |
|
157 state and make it the target of a transition associated with the Quit |
|
158 button's clicked() signal. We could add a transition from each of \c s1, \c |
|
159 s2 and \c s3; however, this seems redundant, and one would also have to |
|
160 remember to add such a transition from every new state that is added in the |
|
161 future. |
|
162 |
|
163 We can achieve the same behavior (namely that clicking the Quit button quits |
|
164 the state machine, regardless of which state the state machine is in) by |
|
165 grouping states \c s1, \c s2 and \c s3. This is done by creating a new |
|
166 top-level state and making the three original states children of the new |
|
167 state. The following diagram shows the new state machine. |
|
168 |
|
169 \img statemachine-button-nested.png |
|
170 \omit |
|
171 \caption This is a caption |
|
172 \endomit |
|
173 |
|
174 The three original states have been renamed \c s11, \c s12 and \c s13 to |
|
175 reflect that they are now children of the new top-level state, \c s1. Child |
|
176 states implicitly inherit the transitions of their parent state. This means |
|
177 it is now sufficient to add a single transition from \c s1 to the final |
|
178 state \c s2. New states added to \c s1 will also automatically inherit this |
|
179 transition. |
|
180 |
|
181 All that's needed to group states is to specify the proper parent when the |
|
182 state is created. You also need to specify which of the child states is the |
|
183 initial one (i.e. which child state the state machine should enter when the |
|
184 parent state is the target of a transition). |
|
185 |
|
186 \snippet doc/src/snippets/statemachine/main2.cpp 0 |
|
187 |
|
188 \snippet doc/src/snippets/statemachine/main2.cpp 1 |
|
189 |
|
190 In this case we want the application to quit when the state machine is |
|
191 finished, so the machine's finished() signal is connected to the |
|
192 application's quit() slot. |
|
193 |
|
194 A child state can override an inherited transition. For example, the |
|
195 following code adds a transition that effectively causes the Quit button to |
|
196 be ignored when the state machine is in state \c s12. |
|
197 |
|
198 \snippet doc/src/snippets/statemachine/main2.cpp 2 |
|
199 |
|
200 A transition can have any state as its target, i.e. the target state does |
|
201 not have to be on the same level in the state hierarchy as the source state. |
|
202 |
|
203 \section1 Using History States to Save and Restore the Current State |
|
204 |
|
205 Imagine that we wanted to add an "interrupt" mechanism to the example |
|
206 discussed in the previous section; the user should be able to click a button |
|
207 to have the state machine perform some non-related task, after which the |
|
208 state machine should resume whatever it was doing before (i.e. return to the |
|
209 old state, which is one of \c s11, \c s12 and \c s13 in this case). |
|
210 |
|
211 Such behavior can easily be modeled using \e{history states}. A history |
|
212 state (QHistoryState object) is a pseudo-state that represents the child |
|
213 state that the parent state was in the last time the parent state was |
|
214 exited. |
|
215 |
|
216 A history state is created as a child of the state for which we wish to |
|
217 record the current child state; when the state machine detects the presence |
|
218 of such a state at runtime, it automatically records the current (real) |
|
219 child state when the parent state is exited. A transition to the history |
|
220 state is in fact a transition to the child state that the state machine had |
|
221 previously saved; the state machine automatically "forwards" the transition |
|
222 to the real child state. |
|
223 |
|
224 The following diagram shows the state machine after the interrupt mechanism |
|
225 has been added. |
|
226 |
|
227 \img statemachine-button-history.png |
|
228 \omit |
|
229 \caption This is a caption |
|
230 \endomit |
|
231 |
|
232 The following code shows how it can be implemented; in this example we |
|
233 simply display a message box when \c s3 is entered, then immediately return |
|
234 to the previous child state of \c s1 via the history state. |
|
235 |
|
236 \snippet doc/src/snippets/statemachine/main2.cpp 3 |
|
237 |
|
238 \section1 Using Parallel States to Avoid a Combinatorial Explosion of States |
|
239 |
|
240 Assume that you wanted to model a set of mutually exclusive properties of a |
|
241 car in a single state machine. Let's say the properties we are interested in |
|
242 are Clean vs Dirty, and Moving vs Not moving. It would take four mutually |
|
243 exclusive states and eight transitions to be able to represent and freely |
|
244 move between all possible combinations. |
|
245 |
|
246 \img statemachine-nonparallel.png |
|
247 \omit |
|
248 \caption This is a caption |
|
249 \endomit |
|
250 |
|
251 If we added a third property (say, Red vs Blue), the total number of states |
|
252 would double, to eight; and if we added a fourth property (say, Enclosed vs |
|
253 Convertible), the total number of states would double again, to 16. |
|
254 |
|
255 Using parallel states, the total number of states and transitions grows |
|
256 linearly as we add more properties, instead of exponentially. Furthermore, |
|
257 states can be added to or removed from the parallel state without affecting |
|
258 any of their sibling states. |
|
259 |
|
260 \img statemachine-parallel.png |
|
261 \omit |
|
262 \caption This is a caption |
|
263 \endomit |
|
264 |
|
265 To create a parallel state group, pass QState::ParallelStates to the QState |
|
266 constructor. |
|
267 |
|
268 \snippet doc/src/snippets/statemachine/main3.cpp 0 |
|
269 |
|
270 When a parallel state group is entered, all its child states will be |
|
271 simultaneously entered. Transitions within the individual child states |
|
272 operate normally. However, any of the child states may take a transition |
|
273 outside the parent state. When this happens, the parent state and all of its |
|
274 child states are exited. |
|
275 |
|
276 \section1 Detecting that a Composite State has Finished |
|
277 |
|
278 A child state can be final (a QFinalState object); when a final child state |
|
279 is entered, the parent state emits the QState::finished() signal. The |
|
280 following diagram shows a composite state \c s1 which does some processing |
|
281 before entering a final state: |
|
282 |
|
283 \img statemachine-finished.png |
|
284 \omit |
|
285 \caption This is a caption |
|
286 \endomit |
|
287 |
|
288 When \c s1 's final state is entered, \c s1 will automatically emit |
|
289 finished(). We use a signal transition to cause this event to trigger a |
|
290 state change: |
|
291 |
|
292 \snippet doc/src/snippets/statemachine/main3.cpp 1 |
|
293 |
|
294 Using final states in composite states is useful when you want to hide the |
|
295 internal details of a composite state; i.e. the only thing the outside world |
|
296 should be able to do is enter the state, and get a notification when the |
|
297 state has completed its work. This is a very powerful abstraction and |
|
298 encapsulation mechanism when building complex (deeply nested) state |
|
299 machines. (In the above example, you could of course create a transition |
|
300 directly from \c s1 's \c done state rather than relying on \c s1 's |
|
301 finished() signal, but with the consequence that implementation details of |
|
302 \c s1 are exposed and depended on). |
|
303 |
|
304 For parallel state groups, the QState::finished() signal is emitted when \e |
|
305 all the child states have entered final states. |
|
306 |
|
307 \section1 Targetless Transitions |
|
308 |
|
309 A transition need not have a target state. A transition without a target can |
|
310 be triggered the same way as any other transition; the difference is that |
|
311 when a targetless transition is triggered, it doesn't cause any state |
|
312 changes. This allows you to react to a signal or event when your machine is |
|
313 in a certain state, without having to leave that state. Example: |
|
314 |
|
315 \code |
|
316 QStateMachine machine; |
|
317 QState *s1 = new QState(&machine); |
|
318 |
|
319 QPushButton button; |
|
320 QSignalTransition *trans = new QSignalTransition(&button, SIGNAL(clicked())); |
|
321 s1->addTransition(trans); |
|
322 |
|
323 QMessageBox msgBox; |
|
324 msgBox.setText("The button was clicked; carry on."); |
|
325 QObject::connect(trans, SIGNAL(triggered()), &msgBox, SLOT(exec())); |
|
326 |
|
327 machine.setInitialState(s1); |
|
328 \endcode |
|
329 |
|
330 The message box will be displayed each time the button is clicked, but the |
|
331 state machine will remain in its current state (s1). If the target state |
|
332 were explicitly set to s1, however, s1 would be exited and re-entered each |
|
333 time (e.g. the QAbstractState::entered() and QAbstractState::exited() |
|
334 signals would be emitted). |
|
335 |
|
336 \section1 Events, Transitions and Guards |
|
337 |
|
338 A QStateMachine runs its own event loop. For signal transitions |
|
339 (QSignalTransition objects), QStateMachine automatically posts a |
|
340 QStateMachine::SignalEvent to itself when it intercepts the corresponding |
|
341 signal; similarly, for QObject event transitions (QEventTransition objects) |
|
342 a QStateMachine::WrappedEvent is posted. |
|
343 |
|
344 You can post your own events to the state machine using |
|
345 QStateMachine::postEvent(). |
|
346 |
|
347 When posting a custom event to the state machine, you typically also have |
|
348 one or more custom transitions that can be triggered from events of that |
|
349 type. To create such a transition, you subclass QAbstractTransition and |
|
350 reimplement QAbstractTransition::eventTest(), where you check if an event |
|
351 matches your event type (and optionally other criteria, e.g. attributes of |
|
352 the event object). |
|
353 |
|
354 Here we define our own custom event type, \c StringEvent, for posting |
|
355 strings to the state machine: |
|
356 |
|
357 \snippet doc/src/snippets/statemachine/main4.cpp 0 |
|
358 |
|
359 Next, we define a transition that only triggers when the event's string |
|
360 matches a particular string (a \e guarded transition): |
|
361 |
|
362 \snippet doc/src/snippets/statemachine/main4.cpp 1 |
|
363 |
|
364 In the eventTest() reimplementation, we first check if the event type is the |
|
365 desired one; if so, we cast the event to a StringEvent and perform the |
|
366 string comparison. |
|
367 |
|
368 The following is a statechart that uses the custom event and transition: |
|
369 |
|
370 \img statemachine-customevents.png |
|
371 \omit |
|
372 \caption This is a caption |
|
373 \endomit |
|
374 |
|
375 Here's what the implementation of the statechart looks like: |
|
376 |
|
377 \snippet doc/src/snippets/statemachine/main4.cpp 2 |
|
378 |
|
379 Once the machine is started, we can post events to it. |
|
380 |
|
381 \snippet doc/src/snippets/statemachine/main4.cpp 3 |
|
382 |
|
383 An event that is not handled by any relevant transition will be silently |
|
384 consumed by the state machine. It can be useful to group states and provide |
|
385 a default handling of such events; for example, as illustrated in the |
|
386 following statechart: |
|
387 |
|
388 \img statemachine-customevents2.png |
|
389 \omit |
|
390 \caption This is a caption |
|
391 \endomit |
|
392 |
|
393 For deeply nested statecharts, you can add such "fallback" transitions at |
|
394 the level of granularity that's most appropriate. |
|
395 |
|
396 \section1 Using Restore Policy To Automatically Restore Properties |
|
397 |
|
398 In some state machines it can be useful to focus the attention on assigning properties in states, |
|
399 not on restoring them when the state is no longer active. If you know that a property should |
|
400 always be restored to its initial value when the machine enters a state that does not explicitly |
|
401 give the property a value, you can set the global restore policy to |
|
402 QStateMachine::RestoreProperties. |
|
403 |
|
404 \code |
|
405 QStateMachine machine; |
|
406 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
407 \endcode |
|
408 |
|
409 When this restore policy is set, the machine will automatically restore all properties. If it |
|
410 enters a state where a given property is not set, it will first search the hierarchy of ancestors |
|
411 to see if the property is defined there. If it is, the property will be restored to the value |
|
412 defined by the closest ancestor. If not, it will be restored to its initial value (i.e. the |
|
413 value of the property before any property assignments in states were executed.) |
|
414 |
|
415 Take the following code: |
|
416 \code |
|
417 QStateMachine machine; |
|
418 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
419 |
|
420 QState *s1 = new QState(); |
|
421 s1->assignProperty(object, "fooBar", 1.0); |
|
422 machine.addState(s1); |
|
423 machine.setInitialState(s1); |
|
424 |
|
425 QState *s2 = new QState(); |
|
426 machine.addState(s2); |
|
427 \endcode |
|
428 |
|
429 Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state |
|
430 \c s1, the property will be 1.0, since the state explicitly assigns this value to it. When the |
|
431 machine is in state \c s2, no value is explicitly defined for the property, so it will implicitly |
|
432 be restored to 0.0. |
|
433 |
|
434 If we are using nested states, the parent defines a value for the property which is inherited by |
|
435 all descendants that do not explicitly assign a value to the property. |
|
436 \code |
|
437 QStateMachine machine; |
|
438 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
439 |
|
440 QState *s1 = new QState(); |
|
441 s1->assignProperty(object, "fooBar", 1.0); |
|
442 machine.addState(s1); |
|
443 machine.setInitialState(s1); |
|
444 |
|
445 QState *s2 = new QState(s1); |
|
446 s2->assignProperty(object, "fooBar", 2.0); |
|
447 s1->setInitialState(s2); |
|
448 |
|
449 QState *s3 = new QState(s1); |
|
450 \endcode |
|
451 |
|
452 Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar |
|
453 will have the value 2.0, since this is explicitly defined for the state. When the machine is in |
|
454 state \c s3, no value is defined for the state, but \c s1 defines the property to be 1.0, so this |
|
455 is the value that will be assigned to \c fooBar. |
|
456 |
|
457 \section1 Animating Property Assignments |
|
458 |
|
459 The State Machine API connects with the Animation API in Qt to allow automatically animating |
|
460 properties as they are assigned in states. |
|
461 |
|
462 Say we have the following code: |
|
463 \code |
|
464 QState *s1 = new QState(); |
|
465 QState *s2 = new QState(); |
|
466 |
|
467 s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); |
|
468 s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); |
|
469 |
|
470 s1->addTransition(button, SIGNAL(clicked()), s2); |
|
471 \endcode |
|
472 |
|
473 Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2 |
|
474 it is bigger. If we click the button to transition from \c s1 to \c s2, the geometry of the button |
|
475 will be set immediately when a given state has been entered. If we want the transition to be |
|
476 smooth, however, all we need to do is make a QPropertyAnimation and add this to the transition |
|
477 object. |
|
478 |
|
479 \code |
|
480 QState *s1 = new QState(); |
|
481 QState *s2 = new QState(); |
|
482 |
|
483 s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); |
|
484 s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100)); |
|
485 |
|
486 QSignalTransition *transition = s1->addTransition(button, SIGNAL(clicked()), s2); |
|
487 transition->addAnimation(new QPropertyAnimation(button, "geometry")); |
|
488 \endcode |
|
489 |
|
490 Adding an animation for the property in question means that the property assignment will no |
|
491 longer take immediate effect when the state has been entered. Instead, the animation will start |
|
492 playing when the state has been entered and smoothly animate the property assignment. Since we |
|
493 do not set the start value or end value of the animation, these will be set implicitly. The |
|
494 start value of the animation will be the property's current value when the animation starts, and |
|
495 the end value will be set based on the property assignments defined for the state. |
|
496 |
|
497 If the global restore policy of the state machine is set to QStateMachine::RestoreProperties, |
|
498 it is possible to also add animations for the property restorations. |
|
499 |
|
500 \section1 Detecting That All Properties Have Been Set In A State |
|
501 |
|
502 When animations are used to assign properties, a state no longer defines the exact values that a |
|
503 property will have when the machine is in the given state. While the animation is running, the |
|
504 property can potentially have any value, depending on the animation. |
|
505 |
|
506 In some cases, it can be useful to be able to detect when the property has actually been assigned |
|
507 the value defined by a state. For this, we can use the state's polished() signal. |
|
508 \code |
|
509 QState *s1 = new QState(); |
|
510 s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50)); |
|
511 |
|
512 QState *s2 = new QState(); |
|
513 |
|
514 s1->addTransition(s1, SIGNAL(polished()), s2); |
|
515 \endcode |
|
516 |
|
517 The machine will be in state \c s1 until the \c geometry property has been set. Then it will |
|
518 immediately transition into \c s2. If the transition into \c s1 has an animation for the \c |
|
519 geometry property, then the machine will stay in \c s1 until the animation has finished. If there |
|
520 is no animation, it will simply set the property and immediately enter state \c s2. |
|
521 |
|
522 Either way, when the machine is in state \c s2, the property \c geometry has been assigned the |
|
523 defined value. |
|
524 |
|
525 If the global restore policy is set to QStateMachine::RestoreProperties, the state will not emit |
|
526 the polished() signal until these have been executed as well. |
|
527 |
|
528 \section1 What happens if a state is exited before the animation has finished |
|
529 |
|
530 If a state has property assignments, and the transition into the state has animations for the |
|
531 properties, the state can potentially be exited before the properties have been assigned to the |
|
532 values defines by the state. This is true in particular when there are transitions out from the |
|
533 state that do not depend on the state being polished, as described in the previous section. |
|
534 |
|
535 The State Machine API guarantees that a property assigned by the state machine either: |
|
536 \list |
|
537 \o Has a value explicitly assigned to the property. |
|
538 \o Is currently being animated into a value explicitly assigned to the property. |
|
539 \endlist |
|
540 |
|
541 When a state is exited prior to the animation finishing, the behavior of the state machine depends |
|
542 on the target state of the transition. If the target state explicitly assigns a value to the |
|
543 property, no additional action will be taken. The property will be assigned the value defined by |
|
544 the target state. |
|
545 |
|
546 If the target state does not assign any value to the property, there are two |
|
547 options: By default, the property will be assigned the value defined by the state it is leaving |
|
548 (the value it would have been assigned if the animation had been permitted to finish playing.) If |
|
549 a global restore policy is set, however, this will take precedence, and the property will be |
|
550 restored as usual. |
|
551 |
|
552 \section1 Default Animations |
|
553 |
|
554 As described earlier, you can add animations to transitions to make sure property assignments |
|
555 in the target state are animated. If you want a specific animation to be used for a given property |
|
556 regardless of which transition is taken, you can add it as a default animation to the state |
|
557 machine. This is in particular useful when the properties assigned (or restored) by specific |
|
558 states is not known when the machine is constructed. |
|
559 |
|
560 \code |
|
561 QState *s1 = new QState(); |
|
562 QState *s2 = new QState(); |
|
563 |
|
564 s2->assignProperty(object, "fooBar", 2.0); |
|
565 s1->addTransition(s2); |
|
566 |
|
567 QStateMachine machine; |
|
568 machine.setInitialState(s1); |
|
569 machine.addDefaultAnimation(new QPropertyAnimation(object, "fooBar")); |
|
570 \endcode |
|
571 |
|
572 When the machine is in state \c s2, the machine will play the default animation for the |
|
573 property \c fooBar since this property is assigned by \c s2. |
|
574 |
|
575 Note that animations explicitly set on transitions will take precedence over any default |
|
576 animation for the given property. |
|
577 */ |