Simple state machine class not updating mainwindow



  • I have two main windows, the first launches the state machine class which creates a second main window.

    The second window then is modified using , for example
    @
    _pushbutton->setVisible(true); // or false
    @
    Each state (corresponds to a method) is generally connected to the next state using slots; the signal comes from the pushbutton of the prior state.

    But my problem is that I do not see updates sometimes, even when I do :

    @ _pushbutton->setVisible(bool);
    _pushbutton->update();

    _lineedit->setVisible(bool);   
    _lineedit->update();
    

    @
    I tried even to create a new MainWindow for every state to no avail. I tried using show()

    @
    _mainwindow->show();
    @

    after every update also. My state machine seems to work for the first few simple states with just changes to a QLabel. Once the lineEdit widget is used, the updates seem to falter. ( I was successful in obtaining the text input however.)

    Also in general am I connecting my states correctly ? (Can this design cause the stack to explode ? There are no cycles here BTW, I swear.) I have two ways to connect, either through a direct call or by a connect:

    @void State::state3()
    {

    ...
    state4(); // direct call
    }

    void State::state4()
    {
    ...
    connect(_pushbutton, SIGNAL(clicked()), this, SLOT(state5())); // by connect
    }
    @

    I had trouble seeing an update esp after a sleep() / Sleep() / usleep() call (I tried all 3) as well.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    I don't understand your need to call update (it should be done for you when you change something like the visibility of a widget) nor the use case of your state machine.

    Could you elaborate on what your state machine should do and with what you implemented it ?



  • Hi, I am using 2 QMainWindows; one is the MainWindow class with a small state machine which launches and changes the widget states of a UserWindow (inherits from QMainWindow also) . In this snippet, the part that is killing me is that the QTimer I have created doesn't go away.
    State 3 keeps coming up every 6 seconds and the on-screen debug info shows the timer is still active after I deleted it. I tried disconnecting the slot, but no go.

    I call update() and show() all over because I was desparately trying to get the timing right. Things work as long as I don't use timers !

    Thanks !

    -pheno
    @
    #include <QMainWindow>
    #include <mainwindow.h>
    #include <userwindow.h>
    #include "ui_mainwindow.h"

    namespace Ui {
    class MainWindow;
    }

    class UserWindow : public QmainWindow
    {

    ... // for eg.
    void UserWindow::showPushButton()
    {
    _pushbutton->setVisible(true);
    _pushbutton->update();
    this->show();
    }
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void createTimer();
    void startTimer(int t);
    void killTimer();

    private slots:
    void on_pushButton_a1_clicked();
    void state1();
    void state2();
    void state3();
    void state_final();
    void dotime();

    private:
    Ui::MainWindow *ui;
    UserWindow *_uw; // inherits from QMainWindow, separate file
    QPushButton *_qpb;
    QTimer *_timer;

    };

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    _uw = new UserWindow();
    _timer = NULL;
    }
    void MainWindow::startTimer(int t)
    {
    _timer->start(t);
    }
    void MainWindow::killTimer()
    {
    if (_timer)
    {
    _timer->stop();
    delete _timer;
    }
    if (_func)
    {
    _func = NULL;
    }
    }

    void MainWindow::createTimer()
    {
    killTimer();
    _timer = new QTimer(this);
    _timer->setSingleShot(true);
    }

    void MainWindow::on_pushButton_a1_clicked()
    {
    _qpb = _uw->getPushButton();
    _uw->showFullScreen();
    createTimer();
    connect(_timer, SIGNAL(timeout()), this, SLOT(state1()));
    startTimer(0);}
    }

    void MainWindow::state1()
    {
    killTimer();
    _uw->setScreenTitle("Directions");
    _uw->setScreenText("blah blah");
    _uw->hideTextInput();
    _uw->showPushButton();

    connect(_qpb, SIGNAL(clicked()), this, SLOT(state2()));
    

    }

    void MainWindow::state2()
    {
    _uw->setScreenTitle("stuff");
    _uw->setScreenText("READ THIS ...");
    _uw->hideTextInput();
    _uw->hidePushButton();

    createTimer();
    connect(_qpb, SIGNAL(clicked()), this, SLOT(state3()));
    startTimer(2000);
    

    }
    void MainWindow::state3()
    {
    killTimer();
    _uw->setScreenTitle("yadda");
    _uw->setScreenText("ipsum lorem ");
    _uw->showTextInput();
    _uw->showPushButton();

    if (_timer && _timer->isActive() )
    {
        _uw->setScreenText("Timer is still active !!");
    }
    else
    {
        _uw->setScreenText("Timer is NOT still active ins State 3 !!");
    }
    connect(_qpb, SIGNAL(clicked()), this, SLOT(state4()));
    

    }

    void MainWindow::state4()
    {
    ....
    }
    @


  • Lifetime Qt Champion

    You are mixing several concepts and have overloaded some non-virtual functions. If you really need a state machine, have a look a the QStateMachine documentation.

    startTimer is a function of QObject as well as killTimer, so your code might not be doing what you think he should do.



  • I don't have to use a state machine. I just want to instantiate a QMainWindow and have parts of it change in a given series of screens as a user interacts with it. Seemed like a natural fit. I tried to use QStateMachine but I could not get assignproperty to work.

    I just need to conduct a quiz that times the student:
    (pseudocode)

    1. start a QMainWindow; show instructions for 7 seconds
    2. update QMainWindow with a question
    3. wait for user text input (note how long it took, it is part of score)
    4. check answer; say if right/wrong; give a clue; still wrong, show answer for 7 seconds
    5. loop over steps #2,3,4 for N times (N<10).
    6. show conclusion screen

    I have a couple of dozen similar quizzes I need to implement each will launch from the main window; the content is quite trivial.

    I saw writing this in one function but couldn't wrap my head around switching control between user and the event loop.

    showscreen1
    wait for 7 seconds
    showscreen2
    wait for text input; record time
    showscreen2 (same screen; 2nd try)
    wait for text input; record time
    showscreen3
    wait for button click
    showscreen4
    wait for 7 seconds
    show screen5
    ...


  • Lifetime Qt Champion

    That sounds more like a QWizard style of application



  • You were right, I was looking at the wrong end of the mule :)

    I essentially created a small state machine. The only two signals of interest are a push button press and a timer timeout, both of which call a function that figures out which state machine to run (I have two). The state machine is small so I decided to leave it as a switch statement over an enum of possible states. If I have time I might change it to use QObjects, but I also like depending less on QT if I have a choice.

    I needed to have the SLOT function call defined for the two events of interest (pushbutton press and a single-shot timer) to the same place ; they are the entry to the control mechanism for my state machine, besides of course the first entry into the state machine which is from the app and not a event. I am also measuring question response times by calculating the time delta.

    Thanks for the feedback

    Lesson: Don't use slots except for simple GUI stuff until I know this better.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.