4. Introduction
• I Qt 4.6 the new State Machine Framework was introduced
In 4 6 th St t M hi F k i t d d
• The idea is to define:
• The possible states the application can be in, and
p pp ,
• How the application can move from one state to another
• Animations can also be applied to transitions if needed
• State change is event driven (e g a signal or mouse press event triggered
event-driven (e.g.
due to the user’s actions)
• Notice that the classes in the State Machine FW belong in most part
to the QtCore module – not QtGui!
• The State Machine FW integrates with Qt’s meta-object system,
property system and the Animation Framework, as explained later
• We will take a look at the basic usage of the State Machine FW and
integrating it with animations
4
6. Demonstration – The States Application
S2
QPushButton::clicked() QPushButton::clicked()
S1 S3
QPushButton::clicked()
QP hB tt li k d()
6
7. Recap: Qt Property System 1(2)
• Data members of QObject-derived classes can be exposed as properties
• Properties are defined in class declarations using the Q PROPERTY macro
Q_PROPERTY
• Syntax:
Q_PROPERTY( type name READ getFunction
[WRITE setFunction ] [RESET resetFunction ]
[DESIGNABLE bool ] [SCRIPTABLE bool ] [STORED bool ] )
• Examples:
Q_PROPERTY( QString title READ title WRITE setTitle )
Q_PROPERTY( bool enabled READ isEnabled WRITE setEnabled )
• Properties can be accessed using the functions QObject::property() and
QObject::setProperty()
• No need to even know the exact type of the object you are manipulating!
• If the property named in QObject::setProperty() does not exist, it will be dynamically added to the
object at run-time
run time
• Many widget members are Qt properties
• Used e.g. in the animation framework
7
8. Recap: Qt Property System 2(2)
// MyObject.h
class MyObject : public QObject {
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)
public: // Constructor and destructor omitted for simplicity
void setText(const QString& text) const { m_text = text; }
QString text() const { return m_text; }
p
private:
QString m_text;
};
// Usage in SomeCode.cpp:
MyObject* myObject = new MyObject();
QObject* object = myObject;
myObject->setText(”Some text”); // Access either in the normal way...
object->setProperty(”tex”, ”Other text”); // ... or by using the property system
8
9. First State Machine 1(4)
• Conceptually our state machine could be presented as shown below
• State 1 is the initial state
• In the next few slides we will fill in the source code and run the application as a
simple demo
p
• Useful base class signals:
• QAbstractState::entered() and
• QAbstractState::exited()
s1 button.clicked s2
button.clicked button.clicked
s3
9
10. First State Machine 2(4)
• The initial application could be written as follows
int main(int argc, char *argv[ ])
{
QApplication a(argc, argv);
QWidget window;
window.setFixedSize(200, 200);
Q
QPushButton* button =
new QPushButton("Switch to state 2", &window);
window.show();
return a.exec();
}
10
11. First State Machine 3(4)
• Define the state machine
• Typically before entering the application event loop
(QApplication::exec())
• The machine can be started later if needed
QStateMachine* machine = new QStateMachine(&window);
QState* s1 = new QState();
QState* s2 = new QState();
QState* s3 = new QState();
s1->addTransition(button, SIGNAL(clicked()), s2);
s2 >addTransition(button,
s2->addTransition(button, SIGNAL(clicked()), s3);
s3->addTransition(button, SIGNAL(clicked()), s1);
machine->addState(s1);
machine->addState(s2);
machine->addState(s3);
machine >setInitialState(s1);
machine->setInitialState(s1);
machine->start();
11
12. First State Machine 4(4)
• So far our state machine does not perform any meaningful work
• Typically such work means changing the properties of various QObjects in the
application
• For example, the button’s text:
example button s
s1->assignProperty(button, ”text”, ”Switch to state 2”);
s2->assignProperty(button, ”text”,
s2 >assignProperty(button ”text” ”Switch to state 3”);
s3->assignProperty(button, ”text”, ”Switch to state 1”);
• Questions:
• How would you make the button move to a different position each time
the state changes?
• How about changing the window title to display the current state?
12
14. Animations with a State Machine 1(2)
• As mentioned before, the Animation FW can easily be made to work with the
State Machine
St t M hi FW
• Simply a matter of assigning one or more animations for each wanted state
transition
• Works the same way for both QSignalTransitions and QEventTransitions
• In this case a property animation itself does not need a start or an end value
• These come from the states in the state machine
• Intermediate values can be set as before using the base class
QVariantAnimation::setKeyValueAt() function
14
16. Default Animations
• If a specific animation is wanted regardless of the state transition, a default
animation can b set
i ti be t
• E.g. always animate ”pos” property if its value is different in the start and target states
• Animations explicitly set on transitions will take precedence over any default
animation for the given property
// Created earlier: QState* s1, s2; QStateMachine* machine;
s2->assignProperty(object, "fooBar", 2.0);
s1->addTransition(s2);
machine->setInitialState(s1);
machine->addDefaultAnimation(new QPropertyAnimation(object, "fooBar"));
16
18. Introduction 1(2)
• R
Represented b th class QTouchEvent
t d by the l
• Contain touch points (QTouchEvent::TouchPoint)
• Each touch point has a state (Pressed, Moved, Stationary,
Released)
• Generated by a touch screen or a touch pad
• See QTouchEvent::DeviceType
• GUI widgets do not accept touch events by default - need to explicitly
enable them:
• QWidget::setAttribute(Qt::WA_AcceptTouchEvents)
• QGraphicsItem::setAcceptTouchEvents(true)
• Multiple widgets may reveice touch events simultanously
18
19. Introduction 2(2)
• Th
There are three t
th touch event types:
h tt
• QEvent::TouchBegin,
• QEvent::TouchUpdate and
QEvent::TouchUpdate,
• QEvent::TouchEnd
• The TouchUpdate and TouchEnd events are sent to the widget that
accepted the TouchBegin event
• Qt guarantees that duplicate TouchBegin events will never be sent
to the same widget
• Touch events and mouse events are not the same thing!
• Delivered independently from each other
p y
19
20. Handling Touch Events 1(2)
• Depending on your widget type, you will need to reimplement either
• QWidget::event(),
• QGraphicsItem::sceneEvent(), or
• QAbstractScrollArea::viewportEvent()
• Use QTouchEvent::touchPoints() to get all touch points contained in the
event
• The event is accepted by default
• If your widget is not interested in the event, return false from the event() function
• Eff ti l th same as calling i
Effectively the lli ignore() on it
()
• This way the event can be propagated properly
20
21. Handling Touch Events 2(2)
MyNewWidget::MyNewWidget(QWidget* parent) : QWidget(parent) {
setAttribute(Qt::WA_AcceptTouchEvents); // Enable touch events
}
// Override base class event() function to intercept touch events
bool MyNewWidget::event(QEvent* event) {
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{ // Process the event, return true if consumed, f l
h d false otherwise
h i
return myTouchHandler(event);
}
}
return QWidget::event(event); // Other events to base class function
}
21
22. Propagation and Grouping
• With QWid t the event is propagated to the widget’s parent in case it is
QWidgets,
explicitly ignored by the widget
• With QGraphicsItems, the event is given to the next item under the touch
point when ignored
• A grouping algorithm is used with touch events to
• Prevent duplicate events being delivered to the same widget, and
• Enable touch event delivery to multiple widgets simultaneously
• When an additional touch point is detected, the following happens (in this
order)
1) If an active touch point is found in any of the widget’s descendants or ancestors,
the new point is grouped with the first one in the same event
• The widget under the touch point will not receive an event
2) Otherwise the widget under the touch point receives a new touch event
22
23. Grouping Examples
1) N
New t
touch point ( 2) when a widget ( hild1) already h one ( 1)
h i t (P2) h id t (Child1) l d has (P1)
• Points P1 and P2 are grouped, Parent does not get an event
Parent
Child1 P1 P2 Child2
2) New touch point to a sibling widget (
) p g g (Child2)
)
• An existing point not found on Child2 or its parent/children, P2 is sent as a
separate touch event to Child2
Parent
Child1 P1 Child2 P2
23
25. Introduction 1(2)
• G t
Gestures are typically f
t i ll formed f
d from a series of events
i f t
• Independently from the input methods used
• E.g. a movement of mouse, or a touch screen action
g
• It is up to the developer to decide how to react to gestures
• Base class in Qt is QGesture, extended by a few specialized
standard gesture classes
• QPanGesture
• QSwipeGesture
• QPinchGesture
• QTapGesture
• QTapAndHoldGesture
Q p
• More ready-made gestures might be provided in the future
25
26. Introduction 2(2)
• The framework provides the developer with means to create additional custom
gestures
t
• Subclass QGestureRecognizer (and possibly QGesture as well)
• Implement the needed pure virtual functions
• Standard gestures only work based on QTouchEvents
• Gestures based on e.g. mouse events must be provided by the developer
• Gestures can be enabled on QWidgets and QGraphicsObjects
• Implies that meta-objects and the property system are once again heavily utilized
behind the scenes
scenes…
26
27. Using Standard Gestures 1(3)
• Si il l t t
Similarly to touch event h dli
h t handling, th b
the base class event f
l t function
ti
needs to be reimplemented
• QWidget::event()
• QGraphicsItem::sceneEvent()
• To indicate that your widget is interested in gestures, call either
• QWidget::grabGesture(Qt::GestureType) or
QWidget::grabGesture(Qt::GestureType),
• QGraphicsItem::grabGesture(Qt::GestureType)
• Gestures will then be delivered to your widget in a QGestureEvent
• Event type is QEvent::Gesture
• Can contain multiple gestures
• QGesture* QGestureEvent::gesture(Qt::GestureType)
QGestu e QGestu e e t::gestu e(Qt::Gestu e ype)
• QList<QGesture*> QGestureEvent::gestures()
27
28. Using Standard Gestures 2(3)
MyWidget::MyWidget(QWidget* parent) : QWidget(parent) {
grabGesture(Qt::PanGesture); // Qt::GestureType contains an enum value
grabGesture(Qt::SwipeGesture); // for each standard gesture.
}
// Override base class event() function to intercept gesture events
bool MyWidget::event(QEvent* event) {
if (event->type() == QEvent::Gesture)
return myGestureHandler(static_cast<QGestureEvent*>(event));
// Other events to base class function
return QWidget::event(event);
}
28
29. Using Standard Gestures 3(3)
bool MyWidget::myGestureHandler(QGestureEvent *event) {
if (QGesture *swipe = event->gesture(Qt::SwipeGesture))
swipeTriggered(static_cast<QSwipeGesture *>(swipe));
else if (QGesture *pan = event->gesture(Qt::PanGesture))
panTriggered(static_cast<QPanGesture >(pan));
panTriggered(static cast<QPanGesture *>(pan));
return true;
}
void MyWidget::swipeTriggered(QSwipeGesture *gesture) {
if (gesture->state() == Qt::GestureFinished) {
if (gesture->horizontalDirection() == QSwipeGesture::Left)
g p
goPrevImage();
else
goNextImage();
update();
}
}
29
30. Summary
• State Machine Framework assists you in creating applications that internally need
to it h f
t switch from one state to another
t t t th
• Can be used together with the Animation Framework to provide animated state
transitions
• Qt supports multi-touch on all platforms
• Depends on hardware support, of course
• A group of standard gestures is also provided
• Pan, swipe, pinch,…
• Easy to create custom gestures when needed
30