Search code examples
c++qtqt5qgraphicssceneqstatemachine

QStateMachine how to show and hide QGraphicsView and QObject in different QState


this is my simple code:

I've created a new scene, view and QPixmapItem

QGraphicsScene *scena = new QGraphicsScene();
QGraphicsPixmapItem *object1= new QGraphicsPixmapItem();
object1->setPixmap(QPixmap(":/prova/prova.png"));

QGraphicsView *view = new QGraphicsView();

view->setScene(scena);
scena->addItem(object1);

view->show();

and next I've created a new QStateMachine with two QState

QStateMachine *machine = new QStateMachine();
QState *s1 = new QState();
QState *s2 = new QState();

machine -> addState(s1);
machine -> addState(s2);

//mouse click in a void mousePressEvent
s1 -> addTransition(this,SIGNAL(mouseclick()),s2);

machine -> start();
  1. I want to show the view in s1 and set object1 visible.

  2. With a mouse click on the scene I've added a transition to s2.

  3. In s2 I want to hide only object1.

How can I do this? Someone can help me with a small tutorial?

I'm using Qt 5.6.0 with MinGW 4.9.2 32bit.


Solution

  • Each QState has entered and exited signals that you can connect functors to. This is a common idiom in modern Qt 5 code. The functors can be concisely given using lambda expressions, where you can invoke arbitrary operations on non-objects, such as on the QPixmapItem. If QPixmapItem derived from QGraphicsObject, you could use QState::assignProperty to assign the desired visibility state instead of calling show() and hide().

    Below is a complete example.

    // https://github.com/KubaO/stackoverflown/tree/master/questions/scenestate-37684315
    #include <QtWidgets>
    
    void addTransition(QState * src, QObject * eventSource, QEvent::Type type, QAbstractState * dst)
    {
       auto transition = new QEventTransition(eventSource, type);
       transition->setTargetState(dst);
       src->addTransition(transition);
    }
    
    struct Window : public QWidget {
       QHBoxLayout m_layout{this};
       QGraphicsScene m_scene;
       QGraphicsPixmapItem m_item;
       QGraphicsView m_view{&m_scene};
    
       QStateMachine m_mach;
       QState s1{&m_mach};
       QState s2{&m_mach};
       Window() {
          m_layout.addWidget(&m_view);
          QPixmap pix{128, 128};
          QPainter p{&pix};
          p.setBrush(Qt::white);
          p.drawRect(pix.rect().adjusted(0,0,-1,-1));
          p.drawText(pix.rect(), "Hello");
          m_item.setPixmap(pix);
          m_scene.addItem(&m_item);
    
          // I want to show the view in s1...
          s1.assignProperty(&m_view, "visible", true);
          // and set object1 visible.
          s1.connect(&s1, &QState::entered, [&]{ m_item.show(); });
          // With a mouse click on the scene I've added a transition to s2.
          addTransition(&s1, &m_view, QEvent::MouseButtonPress, &s2);
          // In s2 I want to hide only object1.
          s2.connect(&s2, &QState::entered, [&]{ m_item.hide(); });
          m_mach.setInitialState(&s1);
          m_mach.start();
       }
    };
    
    int main(int argc, char ** argv) {
       QApplication app{argc, argv};
       Window w;
       w.show();
       return app.exec();
    }