На этом шаге рассмотрим машину состояний в Qt.
Цель состояний (States) заключается в создании различных аспектов приложения. С их помощью можно присвоить различные значения свойствам объектов, которые будут храниться в определенном объекте состояния. Таким образом можно создать много состояний и поместить их в группу состояний. Логика функционирования этой группы подобна использованию кнопок переключения, т. е. активным может быть только одно состояние и активация одного из состояний деактивирует все остальные. Если мы будем показывать одно состояние, затем другое, третье и т. д., то просто одна картинка будет резко сменяться другой и получится что-то похожее на показ слайдов, а это не так уж и привлекательно. Поэтому между отдельными состояниями нужны более плавные переходы (Transitions). Переходы являются инструментом смены состояний и соединения состояний с анимациями. В качестве демонстрации работы состояний и переходов реализуем пример элемента базирующегося на двух состояниях Off/On. Первое состояние Off является начальным. Нажатие на кнопку Push будет перемещать ее в противоположный конец и изменять текущее состояние, как это показано на рис. 1.
Рис.1. Состояния и переходы
QWidget wgt;//создаем виджет, на поверхности которого будем размещать элементы wgt.setFixedSize(300, 50);//задаем ему постоянные размеры wgt.show(); QLabel* plblOff = new QLabel("Off");//создаем виджеты надписей QLabel* plblOn = new QLabel("On"); QHBoxLayout* phbx = new QHBoxLayout;//размещаем их в менеджере компоновки phbx->addWidget(plblOn); phbx->addStretch(1); phbx->addWidget(plblOff); wgt.setLayout(phbx); QPushButton* pcmd = new QPushButton("Push", &wgt);//создаем виджет кнопки pcmd->setAutoFillBackground(true); pcmd->show(); int nButtonWidth = wgt.width() / 2; QStateMachine* psm = new QStateMachine;/*создаем объект машины состояний, которая будет управлять нашими состояниями*/ QState* pStateOff = new QState(psm);//создаем первое состояние для состояния Off QRect rect1(0, 0, nButtonWidth, wgt.height()); pStateOff->assignProperty(pcmd, "geometry", rect1);/*устанавливаем значение геометрии для кнопки*/ pStateOff->assignProperty(plblOff, "visible", true);/*устанавливаем состояния видимости для текстовых надписей. В состоянии Off текстовая надпись Off должна быть видима, а On нет*/ pStateOff->assignProperty(plblOn, "visible", false); psm->setInitialState(pStateOff);/*вызов этого метода c передачей указателя pStateOff, из объекта машины состояний делает это состояние начальным*/ QState* pStateOn = new QState(psm);/*для состояния On так же вызываем серию методов assignProperty(), только присваиваем другие значения, соответствующие этому состоянию*/ QRect rect2(nButtonWidth, 0, nButtonWidth, wgt.height()); pStateOn->assignProperty(pcmd, "geometry", rect2); pStateOn->assignProperty(plblOff, "visible", false); pStateOn->assignProperty(plblOn, "visible", true); QSignalTransition* ptrans1 = pStateOff->addTransition(pcmd, SIGNAL(clicked()), pStateOn);/*добавляем переход из того состояния, из которого вызван этот метод, в другое, указанное в этом методе третьим параметром состояния, мы хотим перейти из состояния Off в состояние On, первым и вторым пара- метром мы указываем, что этот переход должен происходить при нажатии на кнопку Push*/ QSignalTransition* ptrans2 = pStateOn->addTransition(pcmd, SIGNAL(clicked()), pStateOff);/*аналогично поступаем и с состоянием On, но только в обратном порядке. Метод addTransction() возвращает указатель на объект класса QSignalTransition, который мы используем дальше для присвоения переходу нужной анимации*/ QPropertyAnimation* panim1 = new QPropertyAnimation(pcmd, "geometry");/*создаем две анимации (указатели panim1 и panim2) для перехода в состояние On и Off и устанавливаем их вызовом методов addAnimation() в объектах переходов (указатели ptrans1 и ptrans2)*/ ptrans1->addAnimation(panim1); QPropertyAnimation* panim2 = new QPropertyAnimation(pcmd, "geometry"); ptrans2->addAnimation(panim2); psm->start();//выполним запуск созданной нами машины состояний вызовом слота start()
Файлы приложения можно взять здесь.
На следующем шаге рассмотрим основные положения OpenGL.