[Qt-interest] eventTest() and parallel states in QStateMachine
Daniel Zollinger
dh.zollinger at googlemail.com
Sun Jan 30 13:24:45 CET 2011
Hi all,
I've encountered some problems with eventTest() and parallel states. I'm
using a QStateMachine to handle (q)actions of a GIS Application. I give
you a somehow simplified example:
The state machine has two sub states "Overview" and "Map". The Overview
state shows a map with at a very high scale and allows the user just to
do limited actions. The "Map" state shows a detailed map. "Map"
aggregates sub states for different mouse modes (dragging, insert
graphics item, ...). The hierarchy looks like this:
Machine
Overview
Map
Drag
Insert
...
I've attached some transitions to the state machine. One, for example,
to select a different set of maps. Therefore I derived from
QSignalTransition and reimplemented eventTest() to let the user select
another set through a dialog. The user has also the possibility to
cancel the selection and eventTest() returns false. Let's call that
transition "MapSelection".
So far, everything works well!
Now I was displaying overlays of calculation results on the map (e.g.
areas of visibility from a certain position). Depending of the current
overlay I had a different set of user interactions. That means I had the
need for additional "Map" sub states. To avoid the combinatorial
explosion of states (Qt-Doc: QStateMachine framework), I decided to use
state "Map" as a parallel state group. Now the hierarchy of states looks
like this:
Machine
Overview
Map (parallel)
P1
Drag
Insert
...
P2
NoOverlay
Overlay
Now I ran into troubles:
If the state machine is in state "Overview" and "MapSelection" gets
triggered, the dialog is shown once, but if the the machine is in state
"Map" the dialog is shown twice.
My first thought was: that's a bug, and I contacted the qt support. It
turned out that It's actually consistent with the SCXML spec, on which
the qt state machine implementation is based on.
SCXML defines a function selectTransitions() which is supposed to create
a result set of enabled transitions. But actually, this definition
doesn't make sense to me.
In selectTransitions() all current atomic states are put into a list. In
case of parallel states we've got more than one atomic state. In my
example we could be in "Drag" and "Overlay". Now these atomic states are
iterated. In each iteration the ancestors are put into a list. In my
case it's
"Drag"
"P1"
"Map"
"Machine"
and
"Overlay"
"P2"
"Map"
"Machine"
For each state in the lists the associated transitions are taken and
eventTest() invoked on them with EXACTLY THE SAME QEvent* ARGUMENT. If
eventTest() evaluates to true the transition is put into the result set
of enabled transitions.
In my example the "MapSelection" is associated with "Machine", and it's
eventTest() is executed twice. Once for each iteration of atomic states.
As long as eventTest() evaluates one time to true the transition goes
into the result set, which will be returned. selectTransitions() returns
the same result for the following results of eventTest():
- true, false
- false, true
- true, true
And the transition is only ignored if eventTest() returns false twice.
If we introduce more parallel states to "Map", eventTest() will be
invoked even more often.
This inconvenient behaviour could be avoided by putting all transitions
of each atomic state iteration into a set and invoke eventTest() later.
Preventing to open dialogs repeatedly is quite cumbersome, since I need
to know the context of the calling function. Is it triggered by the same
or another trigger?
My workaround is to remember the QEvent* and the boolean result. If
eventTest() is invoked with the same QEvent* the previous result is
returned. It's not completely safe, since I can't be sure to get the
same QEvent* in another context. To make it a bit safer I trigger a
timerEvent to reset the remembered values.
Did anybody of you had the same problems, and came up with another
(better) solution?
Or maybe anybody of you can give me an example where this repeatedly
invocation of eventTest() is needed?
Thanks in advance,
Daniel
More information about the Qt-interest-old
mailing list