Petri Niemi Qt Advanced Part 2


Published on

Petri Niemi, Qt Advanced Part 2, 6.3.2010, Hagenberg

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Petri Niemi Qt Advanced Part 2

  1. 1. Qt Advanced Part II 1
  2. 2. Contents • State Machine Framework • Animations with a State Machine • Touch Events • G Gestures 2
  3. 3. Qt Advanced State Machine Framework 3
  4. 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
  5. 5. Main Classes From QtGui 5
  6. 6. Demonstration – The States Application S2 QPushButton::clicked() QPushButton::clicked() S1 S3 QPushButton::clicked() QP hB tt li k d() 6
  7. 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. 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. 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. 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);; return a.exec(); } 10
  11. 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. 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
  13. 13. Qt Advanced Animations with a State Machine 13
  14. 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
  15. 15. Animations with a State Machine 2(2) QStateMachine *machine = new QStateMachine(); QState *s1 = new QState(); machine->addState(s1); QState *s2 = new QState(); machine->addState(s2); s1->assignProperty(button, "geometry", QRect(0 0 100 s1 >assignProperty(button "geometry" QRect(0, 0, 100, 30)); s2->assignProperty(button, "geometry", QRect(250, 250, 100, 30)); QSignalTransition *t1 = s1->addTransition(button SIGNAL(clicked()) s2); t1 s1 >addTransition(button, SIGNAL(clicked()), t1->addAnimation(new QPropertyAnimation(button, "geometry")); QSignalTransition *t2 = s2->addTransition(button, SIGNAL(clicked()), s1); t2 s2 >addTransition(button, t2->addAnimation(new QPropertyAnimation(button, "geometry")); ( ); machine->setInitialState(s1); machine->start(); 15
  16. 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
  17. 17. Qt Advanced Touch Events 17
  18. 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. 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. 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. 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. 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. 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
  24. 24. Qt Advanced Gestures 24
  25. 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. 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. 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. 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. 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. 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