QT 状态机详解 statemachine (转)

状态机顾名思义,应该有不同的状态在切换。上面状态机图中,我们提供了两种状态state1和state2。而状态的区分是由状态的属性来描述的,比如p1,p2…等等。从一个状态到另一个状态的转化,必须由触发条件来完成,上图state1到state2的状态转换由transition1来表示,state2到state1的状态转换由transition2来表示。如果希望在状态转换过程中有动画来展示,那么可以在transition1和transition2中加入动画效果animation1和animation2 。最后,状态机进入需要有一个初始状态,我们可以设定state1为我们这个状态机的初始态。

有了状态机的描述图,我们就可以看看用Qt-4.6的代码,如何实现以上功能。

创建状态机

QStateMachine *machine = new QStateMachine;

创建两个状态,状态的属性由一个QPushButton的位置大小决定。

QPushButton *button = new QPushButton(“Animated Button”);
QState *state1 = new QState(machine);
state1->assignProperty(button, “geometry”, QRect(0, 0, 150, 30));
QState *state2 = new QState(machine);
state2->assignProperty(button, “geometry”, QRect(250, 250, 150, 30));

将状态1设置为状态机的初始状态

machine->setInitialState(state1);

增加触发状态1到状态2的触发条件,QPushButton按钮被按下,动画效果由addAnimation()完成

QSignalTransition *transition1 = state1->addTransition(button,SIGNAL(clicked()), state2);
transition1->addAnimation(new QPropertyAnimation(button, “geometry”));

细心的读者可能发现QPropertyAnimation的setStartValue()和setEndValue()都没有被调用到。其实这里动画变化的初始态和结束态,由state1和state2决定的。另外,如果没有设置动画的持续时长,则默认是250毫秒。

同理,增加状态2到状态1的触发条件,也是按钮被按下

QSignalTransition *transition2 = state2->addTransition(button,SIGNAL(clicked()), state1);
transition2->addAnimation(new QPropertyAnimation(button, “geometry”));

最后一步,将状态机启动即可,是不是很简单?

machine->start();

完整代码在下头

#include <QApplication>
#include <QPushButton>
#include <QStateMachine>
#include <QState>
#include <QSignalTransition>
#include <QPropertyAnimation>
int main(int argc,char *argv[]){
QApplication app(argc,argv);
QPushButton *button = new QPushButton(“Animated Button”);
button->show();
QStateMachine *machine = new QStateMachine;
//QState *state1 = new QState(machine->rootState());
QState *state1 = new QState(machine);
state1->assignProperty(button, “geometry”, QRect(0, 0, 150, 30));
machine->setInitialState(state1);
//QState *state2 = new QState(machine->rootState());
QState *state2 = new QState(machine);
state2->assignProperty(button, “geometry”, QRect(250, 250, 150, 30));
QSignalTransition *transition1 = state1->addTransition(button,
SIGNAL(clicked()), state2);
transition1->addAnimation(new QPropertyAnimation(button, “geometry”));
QSignalTransition *transition2 = state2->addTransition(button,
SIGNAL(clicked()), state1);
transition2->addAnimation(new QPropertyAnimation(button, “geometry”));
machine->start();
app.exec();
}

//这个代码来自于Qt-4.6 Assistant帮助的Animation索引,原代码的rootState()函数是没有的,应该算是bug了吧:)

]]> http://www.cuteqt.com/blog/?feed=rss2&p=1171 1 http://www.cuteqt.com/blog/?p=1146 http://www.cuteqt.com/blog/?p=1146#comments Sat, 19 Dec 2009 01:39:19 +0000 臭虫 http://ladybug.yo2.cn/articles/%e5%88%a9%e7%94%a8qt-460-%e5%8a%a8%e7%94%bbapi%e5%ae%9e%e7%8e%b0%e9%a2%9c%e8%89%b2%e6%b8%90%e5%8f%98%e5%85%bc%e5%9b%9esanfangling.html前文Qt-4.6动画Animation快速入门三字决介绍了怎么使用Qt-4.6的动画类来实现位置的自动变化,有时候还会一些自定义属性变化需求,比如颜色的变化,以及某些非数值直接相关的属性,这时候可以用自定义的变量来灵活控制。下面我实现了一个非常简单的例子用于让Label上的文字自动做颜色变化,不过样子很丑  ,主要是演示功能

前文sanfanling提到QTextBrowser中选中文字的变色可以用类似方法来操作,不过我觉得更简便的方法是用timerEvent,呵呵(八卦一下,不知此sanfanling是否就是云帆论坛的KDE名人三翻领?)
//这一部分代码主要是利用继承给QLabel增加了一个颜色属性
#include <QApplication>
#include <QLabel>
#include <QPropertyAnimation>

class Label:public QLabel{
Q_OBJECT
Q_PROPERTY(int color READ color WRITE setColor)
public:
Label(const QString&text,QLabel *p=0):QLabel(text,p){icolor=0;};
inline const int& color() const{return icolor;};
void setColor(const int& );
private:
int icolor;
};

void Label::setColor(const int &rcolor) {
QPalette pal;
pal.setColor(QPalette::Foreground, rcolor);
setPalette(pal);
if(rcolor!=icolor){
icolor=rcolor;
//4 lines get “text”
QString color_str=QString("%1").arg(icolor,2,16);
color_str+=QString("00")+color_str;
QString str=QString("");
str+=QString("http://www.cuteqt.com/blog")+QString(">") + color_str;
setText(str);
}
repaint();
}

//标准的QPropertyAnimation动画接口,利用属性color进行自动变化
int main(int argc,char *argv[]){
QApplication app(argc,argv);
Label label("hello,www.cuteqt.com/blog");

QPropertyAnimation *anim=new QPropertyAnimation(&label, "color");
anim->setDuration(1800);
anim->setStartValue(16);
anim->setEndValue(0xffffff);
anim->start();

label.show();
return app.exec();
}

#include "main.moc"

]]> http://www.cuteqt.com/blog/?feed=rss2&p=1146 3 http://www.cuteqt.com/blog/?p=1142 http://www.cuteqt.com/blog/?p=1142#comments Sat, 05 Dec 2009 11:20:40 +0000 臭虫 http://www.cuteqt.com/blog/?p=1142 Qt-4.6新增了Animation Framework(动画框架),让我们能够方便的写一些生动的程序。不必像以前的版本一样,所有的控件都枯燥的呆在伟大光荣的QLayout里,也许它们可以唱个歌,跳个舞。

前面写过一篇文章Qt动画效果的幕后英雄:QTimeLine,介绍了怎么利用QTimeLine写一动画程序。今天又再重申前文里的一句话,所谓动画就是在一个时间段内的不同时间点有不同的状态,只要定义好这样状态,实现动画就是水到渠成的事情。当然做这件事情,最好用的就是状态机,没错Qt-4.6.0提供了QStateMachine类,不过今天我要讲的三字决要简单一些。

第一决:QPropertyAnimation

QPropertyAnimation用于和QObject中的属性properties进行通信,比如QWidget的大小,坐标等。来看代码

QPropertyAnimation *animation = new QPropertyAnimation(myWidget, “geometry”); 
animation->setDuration(10000); 
animation->setStartValue(QRect(0, 0, 100, 30)); 
animation->setEndValue(QRect(250, 250, 100, 30)); 
animation->start();

第一行创建的QPropertyAnimation对象关联了myWidget这个窗体的几何属性。后面的几句分别设置了这个动画的时长,起始坐标和结束坐标。剩下的事情就交改QProperAnimation去做就行了。然后调用start()启动它。没错,五行代码就完成了一个完成了一个自动从一个坐标点移动到另一个坐标点的窗体。下面我给出一个可以运行的代码,是一只小鸟从下角移到中间的一个小动画,当然你得自己准备这个同名的图片:)

#include <QApplication>
#include <QLabel>
#include <QPixmap>
#include <QPropertyAnimation>

int main(int argc,char *argv[]){
QApplication app(argc,argv);
QWidget *w=new QWidget();
w->resize(300,400);

QPixmap birdimg=QPixmap(“twitter-bird.png”).scaled(40,40);

QLabel *bird_1=new QLabel(w);
bird_1->setPixmap(birdimg);

QPropertyAnimation *anim1=new QPropertyAnimation(bird_1, “pos”);
anim1->setDuration(2000);
anim1->setStartValue(QPoint(0, 360));
anim1->setEndValue(QPoint(110, 180));
anim1->start();
bird_1->move(-40,-40);
w->show();
return app.exec();
}

上面的例子使用了label的位置属性pos。当然你可以在自己的类里增加其它property的,比如让颜色在变。

第二决:setEasingCurve

上面那个例子中小鸟的移动是线性的,未免太单调了点。QPropertyAnimation中的void setEasingCurve (const QEasingCurve & easing)函数正是用于实现不同的曲率变化的,QEasingCurve可用的参数列表(包括函数曲线图)可在文档中查到 。将上面动画相关的代码部分改成

QPropertyAnimation *anim1=new QPropertyAnimation(bird_1, “pos”);
anim1->setDuration(2000);
anim1->setStartValue(QPoint(0, 360));
anim1->setEndValue(QPoint(110, 180));
anim1->setEasingCurve(QEasingCurve::OutBounce);
anim1->start();

注意,新增的第四句。并且试试其它曲线参数,然后运行,看到的动态效果是不是不一样了。如果你对列表里已经有的曲线都不满意,你还可以继承QEasingCurve,实现你需要的效果。

第三决:QAnimationGroup

前面的例子是只有一个动画在运行,如果想多个动画一起运行的话,那就要用到动画组QAnimationGroup了。动画组分为两种分别为串行和并行,对应于QAnimationGroup的两个子类QSequentialAnimationGroup和QParallelAnimationGroup。其用法很简单

QSequentialAnimationGroup group;
//QParallelAnimationGroup group;
group.addAnimation(anim1);
group.addAnimation(anim2);
group.start();

上面的代码,如果是串行的话,那么动画anim1运行之后,才会运行anim2。如果是并行的话,两个动画是同时运行的。如果加了动画组,那么单个anim1->start()就没必要再单独调用了,由动画组来管理。 下面是一个可运行的代码,两只小鸟分别从窗体左上角和右下角移动到中间。

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPixmap>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <QParallelAnimationGroup>

int main(int argc,char *argv[]){
QApplication app(argc,argv);
QWidget *w=new QWidget();
w->resize(300,400);

QPixmap birdimg=QPixmap(“twitter-bird.png”).scaled(40,40);

QLabel *bird_1=new QLabel(w);
bird_1->setPixmap(birdimg);

QPropertyAnimation *anim1=new QPropertyAnimation(bird_1, “pos”);
anim1->setDuration(2000);
anim1->setStartValue(QPoint(0, 360));
anim1->setEndValue(QPoint(110, 180));
//anim1->setEasingCurve(QEasingCurve::OutBounce);
//anim1->start();

QLabel *bird_2=new QLabel(w);
bird_2->setPixmap(birdimg);

QPropertyAnimation *anim2=new QPropertyAnimation(bird_2, “pos”);
anim2->setDuration(2000);
anim2->setStartValue(QPoint(0, 0));
anim2->setEndValue(QPoint(150, 180));
anim2->setEasingCurve(QEasingCurve::OutBounce);

QSequentialAnimationGroup group;
//QParallelAnimationGroup group;
group.addAnimation(anim1);
group.addAnimation(anim2);
group.start();

bird_1->move(-40,-40);
bird_2->move(-40,-40);
w->show();
return app.exec();
}

文章的源在:http://docs.google.com/View?id=dhhvrcmh_100m5xs7wf3,如有更新可能会反映在那边
最后罗唆一下,这代码要用在qt-4.6环境下运行:)

]]> http://www.cuteqt.com/blog/?feed=rss2&p=1142 7 http://www.cuteqt.com/blog/?p=509 http://www.cuteqt.com/blog/?p=509#comments Tue, 30 Jun 2009 05:23:07 +0000 臭虫 http://www.cuteqt.com/blog/?p=509 其实动画的本质就是在每一定时间间隔内显示一帧图像,当这个间隔较短的时候人眼就感觉不出来了,觉得看到的是连续的影像。Qt为开发动画效果的人员提供了一个很好的时间控制类QTimeLine.

QTimeLine的最简单用法是

1 QTimeLine timeline=new QTimeLine(1000);
2 timeLine->setFrameRange(0, 100);
3 connect(timeline,SIGNAL(frameChanged(int)),yourobj,SLOT(yourobjslot(int)));
4 timeline->start();

解释:

1. 创建的时间线持续时长,参数值是毫秒数,1000就是1秒

2. 在这段时间线内,创建的输出值范围。也就是第三行中frameChanged信号里传出的参数值范围

3. QTimeLine的默认时间间隔是40ms(也就是1秒25帧),每个间隔会发出一个frameChanged()的信号,此处将该信号连接到你能控制动画效果的对象和槽上。

4. 启动timeline后,每个时间间隔的frameChanged()信号才能正常发出。

当然还有一些复杂的参数设置可以更好的控制你的效果。

setLoopCount(int count)该函数控制了动画的重复次数。默认是1,如果设置成0则表示无限循环。

setUpdateInterval(int interval)该函数用于控制更新动画的时间间隔。

在QTimeLine所设置的持续时长过去后,相应的会发出一个finished()的信号,你可以在接收到这个信号以后做一些扫尾的工作。

另外还有一个别致的选项:

setCurveShape (CurveShape shape),该选项用于控制间隔输出数值的一个变化规律。CurveShage现有的选项是

QTimeLine::EaseInCurve 0 The value starts growing slowly, then increases in speed.

QTimeLine::EaseOutCurve 1 The value starts growing steadily, then ends slowly.

QTimeLine::EaseInOutCurve 2 The value starts growing slowly, then runs steadily, then grows slowly again.

QTimeLine::LinearCurve 3 The value grows linearly (e.g., if the duration is 1000 ms, the value at time 500 ms is 0.5).

QTimeLine::SineCurve 4 The value grows sinusoidally.

QTimeLine::CosineCurve 5 The value grows cosinusoidally.

不多加解释了,2是默认值。因为即使没有这个选项,如果只输出均匀数(选项3),我们还是可以自己对数据进行二次加工,生成我们想要的任意规律的数字。

利用QTimeLine我们很容易实现一些图像消隐的效果,只需要你在每个间隔结束后显示图像消隐过程中不同阶段的一个定格即可。这里就有一个很好的例子,短短300余行,想必用不了你多长时间即可读通

http://qt.gitorious.org/qt-labs/graphics-dojo/trees/master/genie

我们www.cuteqt.com/blog也奉献一个,互相交流:)

timeline-simple.tar

]]> http://www.cuteqt.com/blog/?feed=rss2&p=509 5 http://www.cuteqt.com/blog/?p=276 http://www.cuteqt.com/blog/?p=276#comments Mon, 01 Jun 2009 02:12:51 +0000 shiroki http://www.cuteqt.com/blog/?p=276 看到qtcn上有人在问怎么能动态的变换显示的图片(http://www.qtcn.org/bbs/read.php?tid=18835), 其实这是很容易实现的。 基本的是使用QTimer系列的类来控制时间, 另外从Qt4开始所有的绘制工作应该都放在窗体子类的paintEvent函数里调用, 所以一般情况下你需要把想定制绘图的类派生一下, 重写paintEvent虚函数, 把drawPixmap之类的函数放在这里调用。 笔者的例子一方面是有点取巧, 另一方面也为了和问的问题一致, 没有去派生子类, 而是用了个QLabel来显示图片, 各位看官在看代码的时候要注意了。

下面就简单的介绍一下程序的实现, 非常简单, 三言两语就清楚了。
程序的主窗体采用了QFrame, 其实随便一个类都可以, 比如QWidget也一样。
在主窗体中放了一个layout用来控制内部控件的布局, Label控件和Pushbutton都放在此布局中。 为了显示图片方便, 给Label设置了一个固定大小。
构造函数就是创建布局、子控件和定时器, 并连接信号和槽函数。

主类里定义了两个槽函数, 一个用来响应定时器并变换图片, 另一个用来响应用户点击按钮并启动或停止定时器。
代码看看附件就好了, 有任何不清楚可在本站bbs留言。

例子的打包格式是tar.gz, 由于blog上载的限制, 后缀名被篡改了, 大家下载之后自己改回去一下。 另外因为windows下的qt默认会给debug和release版本创建不同的目录存放binary, 所以代码里用的相对路径在windows下可能会找不到图片, 大家拿回去改改mainwin.cpp, 或者把图片放在程序启动的目录里。 如从debug目录运行,就要把图片放在debug目录中,或者若以debug\ani.exe这样运行的话,图片就要放在debug上级目录。

Qt4.6引入了动画框架,摆脱了以往控件只能安静的呆在布局里的时代,利用Qt提供的动画框架,我们可以让控件跳起舞来,呵呵,很有趣啊… 在Qt4.7中又引入了Qt quick技术,其中的QML语言也是专门来定制GUI动画效果的,这是一种新的GUI动画机制,我刚也接触了些,语法类似CSS,实现预定义的动画很方便,所见即所得,路还得一步步走,先学习一下传统的Qt动画方式——状态机

这里先直接给出例子(见图):

下面是源码:

#include <QApplication>#include <QStateMachine>#include <QPushButton>#include <QSignalTransition>#include <QPropertyAnimation>

int main(int argc,char **argv){    QApplication app(argc,argv);    QWidget *w=new QWidget;    w->resize(240,320);    QPushButton *button = new QPushButton("hicjiajia",w);    QStateMachine *machine = new QStateMachine;     //新建状态机    QState *state1 = new QState(machine);     //状态1    state1->assignProperty(button,"geometry",QRect(0,0,80,30));    //绑定button的geomertry属性    machine->setInitialState(state1);     //state1设为初始化状态    QState *state2 = new QState(machine);    state2->assignProperty(button,"geometry",QRect(w->width()-30,w->height()-80,30,80));    QFont font = QFont("Airl", 12);    state2->assignProperty(button,"font",font);     //状态2字体

    QPropertyAnimation *ani=new QPropertyAnimation(button,"geometry");    ani->setDuration(2000);    ani->setEasingCurve(QEasingCurve::OutBounce);   //动画效果—弹跳

    QSignalTransition *transition1=state1->addTransition(button,SIGNAL(clicked()),state2);      //动画触发信号    transition1->addAnimation(ani);    QSignalTransition *transition2=state2->addTransition(button,SIGNAL(clicked()),state1);    transition2->addAnimation(ani);    machine->start();     //开启状态机

    w->show();    return app.exec();}
时间: 2024-10-06 04:14:40

QT 状态机详解 statemachine (转)的相关文章

qt安装详解

一.Qt  windows 环境安装的安装 第一步: 下载官方安装包,地址:http://www.qt.io/zh-hans/download-open-source/根据你电脑配置选在还是得安装包.下载下来之后双加按照提示安装.当安装成功之后,将qtcreator加入windows的环境变量.方法:右键  计算机>> 属性 >> 高级系统设置 >> 环境变量>> 系统变量中找到 path 将qt的环境安装目录添加进去结尾一定要加" ; 更详细地址

fpga状态机详解

什么是状态机:状态机通过不同的状态迁移来完成特定的逻辑操作 状态机的分类:Moore型状态机和Mealy型状态机 Moore型:状态机的变化只与当前的状态有关 Mealy型:状态机的变化不仅与当前的状态有关,还与输入有关 如何创建状态机:状态机的创建可以分为一段式,两段式和三段式 一段式:主要是讲所有的状态变化以及导致的输出变化都写在了一个always快中. 两段式:将一些复位信号,clk信号单独写在一个always快中,其他的状态变化,输出值得变化写在一个always快中. 三段式:将一些复位

【数通面试私房菜之BGP专题】第二期:BGP状态机详解

BGP对等体的交互过程中存在6种状态机: 空闲(Idle) .连接(Connect) .活跃(Active) .Open报文已发送(OpenSent) .Open报文已确认(OpenConfirm)和连接已建立(Established) . 在BGP对等体建立的过程中,通常可见的3个状态是:Idle.Active和Established. Idle状态: Idle状态是BGP初始状态.在Idle状态下,BGP拒绝邻居发送的连接请求.只有在收到本设备的Start事件后,BGP才开始尝试和其它BGP

Qt addStretch()详解

addStretch函数,是在布局的时候用到. 函数原型: void QBoxLayout::addStretch ( int stretch = 0 ) 作用:平均分配Layout 比如: QVBoxLayout *buttonLayout = new QVBoxLayout; buttonLayout->addStretch(1); buttonLayout->addWidget(Button1); buttonLayout->addStretch(1); buttonLayout-

Qt Tooltip详解

https://blog.csdn.net/niu_gao/article/details/8204425 Qt4中的tooltip与win32中的tooltip有很多不一样的地方,下面来总结一下. 一是不能直在堆或栈中生成QToolTip对象.因为其构造函数为私有.二是从widget获取的tooltip不是tooltip对象,而是tooltip中的文本.三是tooltip跟本不是一个widget.所以不把它当作widget用.四是tooltip类是一个静态类,所以跟本不必生成tooltip对象

Qt Quick 之 QML 与 C++ 混合编程详解

Qt Quick 技术的引入,使得你能够快速构建 UI ,具有动画.各种绚丽效果的 UI 都不在话下.但它不是万能的,也有很多局限性,原来 Qt 的一些技术,比如低阶的网络编程如 QTcpSocket ,多线程,又如 XML 文档处理类库 QXmlStreamReader / QXmlStreamWriter 等等,在 QML 中要么不可用,要么用起来不方便,所以呢,很多时候我们是会基于这样的原则来混合使用 QML 和 C++: QML 构建界面, C++ 实现非界面的业务逻辑和复杂运算. 请给

详解Qt动画框架(2)--- 实现网易云音乐tag切换

在详解Qt的动画框架(一)介绍了关于Qt动画框架一些基础知识,在这一节中,将会实际的看到有关与动画框架的实现,该案例主要实现的具体是网易云音乐tag的切换,网易云音乐中的切换如图所示: 本文介绍的方法也可以达到这种切换的简易效果. 设计动画框架 首先我们需要设计对于动画框架,其需要的动画效果是什么?对于上图,我们需要的是三个tag可以不停的切换,可以抽象为左移以及右移,即一个tag从一个矩形区域,移动到另外的矩形区域,那么对于Tag的承载体选为什么较为合适呢?因为我们仅仅只需要图片的显示,因此Q

qt的资源替换搜索QDir详解

QDir对跨平台的目录操作提供了很多的便利,为了更加方便的提供全局资源的查找,QDir提供了搜索路径替换功能,解决了资源搜索不便的问题,也能提高文件查找的效率. QDir通过已知的路径前缀去搜索并定位文件,搜索路径增加是有序的.从第一个设置的搜索路径开始,是不是觉得和cocos2d的路径搜索非常相似呢. 见如下QT的原版例子 QDir::setSearchPaths("icons", QStringList(QDir::homePath() + "/images")

Qt Quick之StackView详解(2)

在"StackView详解(1)"中,我们学习了StackView的基本用法,这次呢,我们来讲delegate的定制.被管理的View的生命周期.查找View等主题. 本文还会用到"StackView详解(1)"中的示例,如有需要可以回头看看. 附加属性 首先看看StackView提供的附加属性 Stack(后面会用到): Stack.index,index代表当前Item在StackView里的索引,从0开始哦,和StackView.depth不同哦,depth从