3

I am building a program with a largely sequential flow but also some alternative paths. I thought that a state machine might be the simplest way of implementing this since Qt provides such a class: QStateMachine (also see API).

However, I seem to have quite a number of states (20+). Also, I have a number of different transition events (let's say buttons 1-10). So e.g. pressing button x would cause a transition of state 13 to 14.

Entering or leaving each state should be able to execute specific functions with parameters, and while each state emits such signals, it is not possible to pass parameters, so that it requires a potentially large number of paramter-less functions.

Reimplementing QAbstractState also seems tedious for this matter, unless it would have methods similar to assignProperty() which allows setting QObject properties on "state-entry".

Is QSignalMapper along with several Signal-Slot-Connections for each state's transition signals to handle multiple actions an appropriate approach?

RAM
  • 2,257
  • 2
  • 19
  • 41
handle
  • 5,859
  • 3
  • 54
  • 82
  • As an aside: If you have 20 states in a "fairly linear program" and 10 buttons that each transition to a different state, then you might be doing something wrong on the conceptual level. – Zimano Nov 27 '17 at 12:59
  • @Zimano Thanks for your input. But please don't quote something I did not write. Also: you're basically just saying I am doing it wrong, and that might be a good hint, but it's not really helpful. So - how might I do it correctly instead? – handle Nov 28 '17 at 06:57
  • No, I am not "basically just saying you are doing it wrong." You might have done it perfectly. I am saying that if the number of states is so large, and quite a big amount of buttons generate unique state transitions while the program in its entirety is "sequential" with some alternative paths, there might be a conceptual error in your design and you might go back to redefining your states and its transitions. I don't know what you are modelling or what your domain is, so I cannot give you any directions. I was just noting this. I am not perscribing anything and had no intent to post an answer – Zimano Nov 29 '17 at 19:37

1 Answers1

2

If you're using C++11, you can connect directly to a lambda that then invokes your function with a specified parameter.

Otherwise, figure out what object is the sender() of your signal, and set a dynamic property on that object. That property can be queried in the slot, and passed on to the function as a parameter.

For example (within a class):

void setup() {
  QState *s2 = new QState();
  s2->assignProperty(myLabel, "text", "state two");
  s2->setProperty("prop", 0);
  connect(s2, SIGNAL(entered()), io, SLOT(testSlot()));
}
Q_SLOT void testSlot() {
  QObject *obj = this->sender();
  QVariant prop = obj->property("prop");
  qDebug() << __FUNCTION__ << prop.toString();
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • I've taken the liberty to add example code to your answer. And: Great! The feature I was looking for pretty much built-in! This sure seems less complex than using QSignalMapper and can potentially execute a number of actions with a single Signal-Slot connection, of course, depending on the property type and its 'interpretation' by the Slot. – handle Sep 26 '13 at 08:30
  • I was trying to set a QList as property to be able to 'pass' more information but ended up using a QVariantList: http://stackoverflow.com/q/19029623/ – handle Sep 26 '13 at 14:06