Detail Analyze On State Machine Framework

 

Detail Analyze On State Machine Framework

It’s November 6, I must work hard for my Qt Application for four days. November 10 is the limit time of our work. But I will not stop analyzing the Qt Source.

Now let’s begin today’s work. Look at the following code.

QStateMachine machine;

QState *s1 = new QState;

QState *s2 = new QState;

machine.addState (s1);

machine.addState (s2);

machine.setInitialState (s2);

 

 

for (int i = 0;i<12;i++)

{

Pixmap * pPixmap = new Pixmap(QPixmap(100,100));

      s1->assignProperty(pPixmap,"pos",QPointF(cos(i*30/57.297)*130,sin(i*30/57.297)*130));

       

   s2->assignProperty(pPixmap,"pos",QPointF(0,0));

 

   scene.addItem(pPixmap);

}

QTimer timer;

timer.start(1000);

timer.setSingleShot(true);

s2->addTransition(&timer, SIGNAL(timeout()), s1);

machine.start();

 

This is a simple code to show how to use the state machine framework.

First we need an object of QStateMachine. So let’s look at the constructor.

/*!

  Constructs a new state machine with the given /a parent.

*/

QStateMachine::QStateMachine(QObject *parent)

    : QState(*new QStateMachinePrivate, /*parentState=*/0)

{

    // Can't pass the parent to the QState constructor, as it expects a QState

    // But this works as expected regardless of whether parent is a QState or not

    setParent(parent);

}

This function is just to add this object to the main object tree, and create a new object from QStateMachinePrivate class. So let’s have a look at the constructor of QStateMachinePrivate class.

QStateMachinePrivate::QStateMachinePrivate()

{

    state = NotRunning;

    _startState = 0;

    processing = false;

    processingScheduled = false;

    stop = false;

    stopProcessingReason = EventQueueEmpty;

    error = QStateMachine::NoError;

    globalRestorePolicy = QStateMachine::DoNotRestoreProperties;

    signalEventGenerator = 0;

#ifndef QT_NO_ANIMATION

    animationsEnabled = true;

#endif

}

It’s easy to understand, the only thing this function do is to initialize the member variable. From this definition, QT_NO_ANIMATION, we can find that this class always using with the animation framework.

And then, let’s look at the next sentence.

QState *s1 = new QState;

QState *s2 = new QState;

machine.addState (s1);

machine.addState (s2);

machine.setInitialState (s2);

First, they create two object of QState. And then call the addState () function from the object named machine. At yesterday’s analysis, we mentioned that the addState () function is just to add the current object to the main object tree for auto destruction. And what did the setInitialState () function do? We can find this function is a member of QState class.

/*!

  Sets this state's initial state to be the given /a state.

  /a state has to be a child of this state.

*/

void QState::setInitialState(QAbstractState *state)

{

    Q_D(QState);

    if (d->childMode == QState::ParallelStates) {

        qWarning("QState::setInitialState: ignoring attempt to set initial state "

                 "of parallel state group %p", this);

        return;

    }

    if (state && (state->parentState() != this)) {

        qWarning("QState::setInitialState: state %p is not a child of this state (%p)",

                 state, this);

        return;

    }

    d->initialState = state;

}

You see, it just save the point of state to its member variable, and waiting for the start () function is called.

The important thing is to understand how this sentence to work.

s2->assignProperty(pPixmap,"pos",QPointF(0,0));

To make this function works, they use the meta-object system.

/*!

  Instructs this state to set the property with the given /a name of the given

  /a object to the given /a value when the state is entered.

 

  /sa polished()

*/

void QState::assignProperty(QObject *object, const char *name,

                            const QVariant &value)

{

    Q_D(QState);

    if (!object) {

        qWarning("QState::assignProperty: cannot assign property '%s' of null object", name);

        return;

    }

    for (int i = 0; i < d->propertyAssignments.size(); ++i) {

        QPropertyAssignment &assn = d->propertyAssignments[i];

        if ((assn.object == object) && (assn.propertyName == name)) {

            assn.value = value;

            return;

        }

    }

    d->propertyAssignments.append(QPropertyAssignment(object, name, value));

}

At this function, they use the QPropertyAssignment class. It’s an inner class which storage the data of state property.

struct QPropertyAssignment

{

    QPropertyAssignment()

        : object(0), explicitlySet(true) {}

    QPropertyAssignment(QObject *o, const QByteArray &n,

                        const QVariant &v, bool es = true)

        : object(o), propertyName(n), value(v), explicitlySet(es)

        {}

    QObject *object;

    QByteArray propertyName;

    QVariant value;

    bool explicitlySet;

};

They use a list of QPropertyAssignment’s object to save the data. And save data by call the assignProperty () function.

The next step is to set the trigger signal access to call addTransition () function.

/*!

  Adds the given /a transition. The transition has this state as the source.

  This state takes ownership of the transition. If the transition is successfully

  added, the function will return the /a transition pointer. Otherwise it will return null.

*/

QAbstractTransition *QState::addTransition(QAbstractTransition *transition)

{

    Q_D(QState);

    if (!transition) {

        qWarning("QState::addTransition: cannot add null transition");

        return 0;

    }

 

    transition->setParent(this);

    const QList<QWeakPointer<QAbstractState> > &targets = QAbstractTransitionPrivate::get(transition)->targetStates;

    for (int i = 0; i < targets.size(); ++i) {

        QAbstractState *t = targets.at(i).data();

        if (!t) {

            qWarning("QState::addTransition: cannot add transition to null state");

            return 0;

        }

        if ((QAbstractStatePrivate::get(t)->machine() != d->machine())

            && QAbstractStatePrivate::get(t)->machine() && d->machine()) {

            qWarning("QState::addTransition: cannot add transition "

                     "to a state in a different state machine");

            return 0;

        }

    }

    if (machine() != 0 && machine()->configuration().contains(this))

        QStateMachinePrivate::get(machine())->registerTransitions(this);

    return transition;

}

I have no enough time to analyze this function. The next day, I will continue to do it.

 

November 7, 2009 00:22

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值