crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в Конечный автомат на Qt
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
Litkevich Yuriy Дата 10.1.2018, 22:33
 
Цитата(Анна @ 18.12.2017, 19:31) *
Но вот как увязать описанный в книге паттерн с классами QState и QStateMachine представить не могу.
Я про этот патерн не читал.

Один из вариантов использования QStateMachine выглядит примерно так:
Сначала описываем сам автомат (без описания полезной работы)
void MyClass::createMachine()
{

_meassureMachine = new QStateMachine(this);

// Список состояний и связь их со слотами полезной работы
QState *meassurePrepareState = new QState();
meassurePrepareState->setObjectName("_meassure_meassurePrepareState");
connect(meassurePrepareState, SIGNAL(entered()), this, SLOT(meassurePrepareStateSlot()));
_meassureMachine->addState(meassurePrepareState);

_meassureMachine->setInitialState(meassurePrepareState);

QState *measureState = new QState();
measureState->setObjectName("_meassure_measureState");
connect(measureState, SIGNAL(entered()), this, SLOT(measureRunStateSlot()));
_meassureMachine->addState(measureState);


QState *repeatState = new QState();
repeatState->setObjectName("_meassure_repeatState");
connect(repeatState, SIGNAL(entered()), this, SLOT(meassureRepeatStateSlot()));
_meassureMachine->addState(repeatState);

QState *twuErrorState = new QState();
twuErrorState->setObjectName("_meassure_twuErrorState");
connect(twuErrorState, SIGNAL(entered()), this, SLOT(meassureTwuErrorStateSlot()));
_meassureMachine->addState(twuErrorState);


// переходы между состояниями
meassurePrepareState->addTransition(_timerNext, SIGNAL(timeout()), measureState);

measureState->addTransition(measureState, SIGNAL(finished()), repeatState);
measureState->addTransition(this, SIGNAL(twuFailed()), twuErrorState);

}



Далее/ранее по коду создаём слоты которые выполняются при входе в соответствующее состояние
void MyClass::meassurePrepareStateSlot()
{
...
}


void MyClass::measureRunStateSlot()
{
...
}


void MyClass::meassureRepeatStateSlot()
{
...
}

void MyClass::meassureTwuErrorStateSlot()
{
...
}


Ну а QAction умеет посылать сигналы.

П.С.
Выдрано как попало из реального кода
Анна Дата 18.12.2017, 17:31
  Вот сейчас читаю про паттерн "Состояние".
В принципе, это то, что мне надо. При срабатывании QAction программа переходила бы в то или иное состояние, в которых по-разному реагировала бы на срабатывания других QAction (например, некоторые действия должны игнорироваться при одном состоянии и выполняться при другом).
Но вот как увязать описанный в книге паттерн с классами QState и QStateMachine представить не могу.

Может, кто подскажет?
Книжные примеры брала у Э.Фримен и Э.Фримен "Паттерны проектирования" и Гамма, Хельм, Джонсон и Влиссидес "Приёмы объектно-ориентированного проектирования"
kuzulis Дата 20.4.2010, 19:56
  ООО!!! Хоть тема и старая, но подниму... Наткнулся на нее и свои 5 копеек добавлю.

Цитата
вообще чаще используют переключатель:


Дадада.. Именно! Есть такая штука - как SWITCH технология программирования в которой и используется такой подход. Чаще всего оно применяется в автоматике, АСУТП, при программировании ПЛК и т.п.

В инете оч много литературы по этому поводу (кратко ознакомится на википедии можно).

Этот подход очень удобен, но необычен для основного контингента программистов, которые привыкли думать "классически". :)
Этот подход в сложных алгоритмах со множеством состояний избавляет нас от большого кол-ва ошибок, позволяя делить алгоритм на несколько КА по вложенности и т.п.

Как я к примеру делаю:
1. Делю алгоритм на различные КА, выполняющие определенные функции
2. Для каждого КА рисую граф переходов
3. По графу пишу программу

При этом каждый КА имеет у меня набор свойств:
1. Набор состояний
2. Набор входных воздействий

И в зависимости от текущего воздействия на автомат и его состояния выполняется некий алгоритм, который переводит КА в другие состояния и т.п. В общем, все оч просто и удобно. :)

Я сам нечто похожее делаю для ПЛК (правда к Qt4 это никоим образом не относится)... Результаты - впечатляют! Ошибок по сравнению с "классикой" гораздо меньше и код гораздо понятнее и читабельней!

Litkevich Yuriy Дата 2.2.2009, 15:58
  вообще чаще используют переключатель:
примерно так
void HModBus (void)
{
  static byte fase=0;
  volatile UINT clcCRC;
  volatile UINT pakCRC;

  //фазы состояний движка ModBus
  enum fase
    {
        FASE_START_RX,    /* запускаем прием */
        FASE_END_RX,    /* ждем завершения приема */
        FASE_NODE_CHK,    /* проверяем номер узла в сети */
        FASE_CRC16_CHK,    /* проверяем CRC16 */
        FASE_FUNK_CHK,    /* проверяем номер номер функции */
        //FASE_FUNK_WRK,    /*  */
        FASE_START_TX,    /* передаем обратно */
        FASE_END_TX        /* ждем завершения передачи */
    };
    
    switch (fase)
    {
        //====== ЗАПУСК ПРИЕМА ======
        case FASE_START_RX:    
        {
            MbusRxRun();
            fase=FASE_END_RX;
            break;
        };
        //====== ЖДЕМ ЗАВЕРШЕНИЯ ПРИЕМА ======
        case FASE_END_RX:
        {
            if (mbus_f_rxend)
            {
                fase=FASE_NODE_CHK;
            }
            break;
        };
        //====== ПРОВЕРЯЕМ ПРИНЯТОЕ - НОМЕР УЗЛА ======
        case FASE_NODE_CHK:
        {
            BYTE temp;
            
            temp=*(mbus_buff.buff+MBUS_FIELD_NODE);
            if ((temp!=mbus_cfg.node)&&(temp!=MMBUS_ALL_NODE)&&(temp!=MMBUS_PRG_NODE))
            {
                fase=FASE_START_RX;    // Пакет не нам, в любом случае
            }
            else
            {
                fase=FASE_CRC16_CHK;
            }
            break;
        };    
        //====== ПРОВЕРЯЕМ ПРИНЯТОЕ - CRC16 ======
        case FASE_CRC16_CHK:
        {
            BYTE *pbuff=mbus_buff.buff;
            
            // вызвать функцию проверки CRC16
            clcCRC=CalcCRC16(pbuff, rxcnt-2);
            
            pakCRC=pbuff[rxcnt-2];    // младший байт
            pakCRC|=((UINT)pbuff[rxcnt-1])<<8;    // старший байт 03 04 83 00
            
            if (clcCRC!=pakCRC)
            {
                fase=FASE_START_RX;
            }
            else /**/
            {
                fase=FASE_FUNK_CHK;
            }
            break;
        };
        //====== ПРОВЕРЯЕМ/ИСПОЛНЯЕМ ПРИНЯТУЮ ФУНКЦИЮ =====
        case FASE_FUNK_CHK:
        {
            /* если определена функция проверки/исполнения
                ModBus'овских функций, то исполняем ее */
            if(modbusFunc)
            {
                if (modbusFunc()) fase=FASE_START_RX;    //функция вернула не нуль->передавать не надо
                else fase=FASE_START_TX;    // иначе передаем ответ
            }
            else
            {
                #ifdef DBG_MBUS_ON
                    fase=FASE_START_TX;
                #else  // !DBG_MBUS_ON
                    fase=FASE_START_RX;
                #endif // DBG_MBUS_ON            
            }
            break;
        };            
        //====== ПЕРЕДАЕМ ОТВЕТ ======
        case FASE_START_TX:
        {
            MbusTxRun();
            fase=FASE_END_TX;
            break;
        };
        //====== ЖДЕМ ЗАВЕРШЕНИЯ ПЕРЕДАЧИ ======
        case FASE_END_TX:
        {
            if (mbus_f_txend)
            {
                fase=FASE_START_RX;
            }
            break;
        };
    }

} // END OF HModBus()
SABROG Дата 2.2.2009, 15:45
  Видимо if'ы обеспечивают как раз тот механизм "непоследовательности" автомата, в то время как операция взяти по модулю - последовательное выполнение.
Tonal Дата 2.2.2009, 15:25
 
Цитата(SABROG @ 1.2.2009, 3:04) *
Почитал в инете примеры со строками на эту тему тут, тут и тут, а так и не понял какое преимущество он дает.
Ну, а чем тогда конечный автомат лучше для QCheckBox по сравнению с этим кодом?
    Qt::CheckState state = checkBox1->checkState();
    if (checkBox1->isTristate())
    {
        checkBox1->setCheckState((state+1)%3); //чеким по-кругу 0,1,2,0,1,2...n
    }
    else
    {
        checkBox1->setCheckState(state^Qt::Checked); //xor'им 0 или 2 с 2 (Qt::Checked).
    }

Возможно и не работает, но идея должна быть понятна

Этот код - тот же конечный автомат только запрограммированный через if-ы.
Конечный автомат - это способ (математический формализм) для описаия поведения некоторой системы через состояния и переходы между ними.
Конечным автоматом можно описать поведения GUI программы, работу с устройством, сетевым протоколом, разбор текстового файла...
Те же регулярные выражения реализуются через конечные автоматы - строка регэкспа разбирается, по ней строится КА (конечный автомат), после чего через него пропускается поток символов - каждый символ - событие, переводящее КА в какое-то состояние. :)

Так что вопрос "что лучше" тут бессмысленен.
Если научится работать с КА и находить их в задачах, то будет проще работать. :)
Litkevich Yuriy Дата 1.2.2009, 18:18
 
Цитата(kwisp @ 1.2.2009, 21:11) *
а пример с кнопкой в Qt State Machine Framework как раз такой
а там как раз во 2 коментарии сказано о не удачности примера

мне собственно стало интересно как они реализовали работу с КА:
QStateMachine machine;

QState *s1 = new QState(machine.rootState());
s1->setPropertyOnEntry(&button, ”text”, ”In s1?);

QState *s2 = new QState(machine.rootState());
s2->setPropertyOnEntry(&button, ”text”, ”In s2?);

QState *s3 = new QState(machine.rootState());
s3->setPropertyOnEntry(&button, ”text”, ”In s3?);

s1->addTransition(&button, SIGNAL(clicked()), s2);
s2->addTransition(&button, SIGNAL(clicked()), s3);
s3->addTransition(&button, SIGNAL(clicked()), s1);


machine.setInitialState(s1);
machine.start();
Т.е. реализовано добавление переходов (addTransition) и используются сигналы, такое мне в голову не приходило.
Эту штуку можно использовать в программах опрашивающих разные устройства, например, на шине ModBas
kwisp Дата 1.2.2009, 18:11
  Litkevich Yuriy,
Цитата
вообще любой пример не удачен, если все состояния в нем изменяются последовательно.

в любом наборе.
а пример с кнопкой в Qt State Machine Framework как раз такой. нужно попробовать реализовать "простой" пример, состояний 5 хотя бы с запрещенными переходами непоследовательный может быть не с одним уровнем истории состояний своим (у каждого наверное свой) методом и способом который предлагает Qt State Machine Framework
тогда станет все наглядно ясно.
Litkevich Yuriy Дата 1.2.2009, 18:04
  вообще любой пример не удачен, если все состояния в нем изменяются последовательно.
Нематематическое, а электрощиско-практическое определение:
Конечный автомат (КА) - автомат выходной сигнал которого (читай его состояние) зависит от текущего входного сигнала и текущего состояния КА (можно представить в виде предыстории его входных сигналов)

Пожарный шлейф сигнализации (ШС) обладает такими свойствами:
1) снят с ошраны
2) на охране
3) сигнал (состояние) "Внимание"
4) сигнал (состояние) "Пожар"
5) постановка в движении

Обычно пожарные ШС - круглосуточные, т.е. их нельзя снять с охраны (человек нажимает кнопку "Снять с охраны"). вместо снятия с охраны для любых круглосуточных (как пожарных так и охранных ШС) осуществляют "перепостановку". При перепостановке снимается питание с ШС и с линий питаний датчиков, чтобы сброить их состояние. Затем подается питание, с этого момента состояние ШС = №5 (постановка в движении), нужно для установления рабочих режимов датчиков.
т.е.
6) перепостановка (переход в сост. №1 и последующий автоматический переход в состояние №5)

И работа КА выглядит так:
Подаем питание прибора, в КА поступает входной сигнал "Поставить на охрану"
тогда КА переходит в состояние №5, по истечении некоторого времени КА переходит в одно из состояний №2 или №3 или №4

Из состояния №2 может перейти в №6 или №3 или №4
Из состояния №3 может перейти в №6 или №4
Из состояния №4 может перейти в №6

Т.е. состояния непоследовательные
---
Написал наспех может чего пропустил
Antrix Дата 1.2.2009, 17:33
  Возможно пример неудачен, ну я старался объснить как мог :rolleyes: . А с переменными bool я думал будет легче понять.
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 28.3.2024, 22:23