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.
-
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_OBJECTpublic:
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()
{
....
}
@ -
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)- start a QMainWindow; show instructions for 7 seconds
- update QMainWindow with a question
- wait for user text input (note how long it took, it is part of score)
- check answer; say if right/wrong; give a clue; still wrong, show answer for 7 seconds
- loop over steps #2,3,4 for N times (N<10).
- 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
... -
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.