zhonghua

C++博客 首页 新随笔 联系 聚合 管理
  72 Posts :: 1 Stories :: 4 Comments :: 0 Trackbacks

2015年2月2日 #

在最近的web开发中是不是就会用到一些选择器,发现很多尤其是CSS3新增的不太熟悉,在此总结一下。

优先级

不同级别

1. 在属性后面使用 !important 会覆盖页面内任何位置定义的元素样式。

2.作为style属性写在元素内的样式

3.id选择器

4.类选择器

5.标签选择器

6.通配符选择器

7.浏览器自定义

同一级别

同一级别中后写的会覆盖先写的样式

 

基础选择器

选择器含义
*通用元素选择器,匹配页面任何元素(这也就决定了我们很少使用)
#idid选择器,匹配特定id的元素
.class类选择器,匹配class包含(不是等于)特定类的元素
element标签选择器

 

复制代码
*         {             /*页面所有元素都使用*/             border:0;         }          #test         {             /*id=test 的元素*/             background-color:#0e0;         }          .staus         {             /*含有类status的元素*/             border:0;         }          div         {             /*页面所有div*/              background-color:#0e0;         }
复制代码

组合选择器

选择器含义
E,F多元素选择器,用”,分隔,同时匹配元素E或元素F
E F后代选择器,用空格分隔,匹配E元素所有的后代(不只是子元素、子元素向下递归)元素F
E>F子元素选择器,用”>”分隔,匹配E元素的所有直接子元素
E+F直接相邻选择器,匹配E元素之后相邻同级元素F
E~F普通相邻选择器(弟弟选择器),匹配E元素之后同级元素F(无论直接相邻与否)
.class1.class2这个姑且也算一个吧,没什么名字,匹配类名中既包含class1又包含class2的元素

我就不一一举例子了,选择器并不是只能写两层,发现有些小朋友有这种误解,认为只能写E>F这样的,我们写可以写E>F.class Element这样,你要你搞得定优先级

 

属性选择器

 

选择器含义
E[attr]匹配所有具有属性attr的元素,div[id]就能取到所有有id属性的div
E[attr=value]匹配属性attr值为value的元素,div[id=test],匹配id=test的div
E[attr~=value]匹配所有属性attr具有多个空格分隔、其中一个值等于value的元素
E[attr|=value]匹配所有att属性具有多个”-”分隔、其中一个值以value开头的元素,主要用于lang属性,比如“en”、“en-us”
E[attr ^=value]匹配属性attr的值以value开头的元素
E[attr $=value]匹配属性attr的值以value结尾的元素
E[attr *=value]匹配属性attr的值包含value的元素

伪类选择器

 

选择器含义
E:first-child匹配元素E的第一个子元素
E:link匹配所有未被点击的链接
E:visited匹配所有已被点击的链接
E:active匹配鼠标已经其上按下、还没有释放的E元素
E:hover匹配鼠标悬停其上的E元素
E:focus匹配获得当前焦点的E元素
E:lang(c)匹配lang属性等于c的E元素
E:enabled匹配表单中可用的元素
E:disabled匹配表单中禁用的元素
E:checked匹配表单中被选中的radio或checkbox元素
E::selection匹配用户当前选中的元素
E:root匹配文档的根元素,对于HTML文档,就是HTML元素
E:nth-child(n)匹配其父元素的第n个子元素,第一个编号为1
E:nth-last-child(n)匹配其父元素的倒数第n个子元素,第一个编号为1
E:nth-of-type(n)与:nth-child()作用类似,但是仅匹配使用同种标签的元素
E:nth-last-of-type(n)与:nth-last-child() 作用类似,但是仅匹配使用同种标签的元素
E:last-child匹配父元素的最后一个子元素,等同于:nth-last-child(1)
E:first-of-type匹配父元素下使用同种标签的第一个子元素,等同于:nth-of-type(1)
E:last-of-type匹配父元素下使用同种标签的最后一个子元素,等同于:nth-last-of-type(1)
E:only-child匹配父元素下仅有的一个子元素,等同于:first-child:last-child或 :nth-child(1):nth-last-child(1)
E:only-of-type匹配父元素下使用同种标签的唯一一个子元素,等同于:first-of-type:last-of-type或 :nth-of-type(1):nth-last-of-type(1)
E:empty匹配一个不包含任何子元素的元素,文本节点也被看作子元素
E:not(selector)匹配不符合当前选择器的任何元素

伪元素选择器

 

选择器含义
E:first-line匹配E元素内容的第一行
E:first-letter匹配E元素内容的第一个字母
E:before在E元素之前插入生成的内容
E:after在E元素之后插入生成的内容
posted @ 2015-02-02 15:01 米米 阅读(87) | 评论 (0)编辑 收藏

2014年1月13日 #

     摘要:       最近写程序中需要将数据输出保存到Excel文件中。翻看《C++ GUI Programming with Qt 4》(Second Edition)发现可以在Qt中运用ActiveX控件,这真是太好了。        看了很久教程也没有学会,毕竟是新手,平时也没学过ActiveX编程。一些在VB中可以方便使用的函数在...  阅读全文
posted @ 2014-01-13 17:23 米米 阅读(1757) | 评论 (0)编辑 收藏

2014年1月9日 #

  • 老有人问如何让Qt的应用程序自动重启,稍微写一点,也顺便理理自己的思路 2011.10.26

自动重启,也就是退出当前进程,启动一个新的进程。于是,先看程序如何退出

退出

Qt程序的一般结构如下:

int main(int argc, char** argv) {     QApplication app(argc, argv);     Widget w;     w.show()     return app.exec(); }

最后一句启动了主线程的事件循环。而要退出程序,就是要退出这个事件循环,使main函数返回。

如何退出?

正确方式:

  • QCoreApplication::exit(int);

它还有一个马甲

  • QCoreApplication::quit();

对于QApplication来说,它有一个常用的属性

quitOnLastWindowClosed

所以,当最后一个窗口关闭时,它可以自动调用前面的exit()

而至于关闭窗口呢,我们还可以使用

  • QApplication::closeAllWindows()

注:一般来说,对于多个窗口的程序,调用这个会比直接调用quit要好。因为这样窗口可以接受到Close事件。

启动外部程序

在Qt中,做这个工作的非QProcess莫属了,要启动当前程序的另一个进程,有要使二者没有"父子"关系。恩

QProcess::startDetached(qApp->applicationFilePath(), QStringList());

可是,为什么不写成下面这样?

QProcess::startDetached(qApp->applicationFilePath());

当然,如果路径中不包含空格,这个也可以工作。

重新启动1

现在简单了,要重新启动,只需要调用

void XXX::onXXX() {     qApp->quit();     QProcess::startDetached(qApp->applicationFilePath(), QStringList()); }

或者:

void XXX::onXXX() {     qApp->closeAllWindow();     QProcess::startDetached(qApp->applicationFilePath(), QStringList()); }

重新启动2

尽管没什么好处,但有时候,我似乎更喜欢这样写:

void XXX::onXXX() {     qApp->exit(773) }

然后main函数改成

int main(int argc, char** argv) { ....     int ret = app.exec();     if (ret == 773) {         QProcess::startDetached(qApp->applicationFilePath(), QStringList());         return 0;     }     return ret; }

这里面我用了一个魔数:773,没什么特别含义,只是因为我觉得

773 = 'r'+'e'+'s'+'t'+'a'+'r'+'t'  ==>restart

上班了,就写到这儿...

posted @ 2014-01-09 15:13 米米 阅读(550) | 评论 (0)编辑 收藏

2013年12月11日 #

     摘要:         昨晚在一个邮件列表里面看见一个关于在线程种使用signal/slot的讨论,由于回复太多,这里就不贴出原文了。        主要是关于怎样从一个线程发送信号到另外一个线程的问题。其实这个也不是什么复杂的问题,在qt的asstant里面已经描诉...  阅读全文
posted @ 2013-12-11 17:08 米米 阅读(565) | 评论 (0)编辑 收藏

2013年11月17日 #

 转自:http://indure.chinaunix.com/space.php?uid=25520556&do=blog&id=2211406

       主要使用QTableView和QTableWidget中的三个函数实现

QTableView::verticalScrollBar()->setSliderPosition()  //设置当前滑动条的位置

QTableView::verticalScrollBar()->maximum();             //滑动条能移动的最大位置

QTableView::verticalScrollBar()->value();                   //获得当前滑动条的位置

 

 

  1. static int nCurScroller=0; //翻页时的当时滑动条位置
  2. static int pageValue = 10; // 一页显示条数

  3. void SplayHisForm::createHisForm()
  4. {
  5.                 …….
  6.     hisTableWidget = new QTableWidget;
  7.     hisTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
  8.     hisTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
  9.             …….
  10. }

  11. /***下一页***/
  12. void SplayHisForm::nextPageHis()
  13. {
  14.     int maxValue = hisTableWidget->verticalScrollBar()->maximum(); // 当前SCROLLER最大显示值25
  15.     nCurScroller = hisTableWidget->verticalScrollBar()->value(); //获得当前scroller值

  16.     if(nCurScroller<maxValue)
  17.         hisTableWidget->verticalScrollBar()->setSliderPosition(pageValue+nCurScroller);
  18.     else
  19.         hisTableWidget->verticalScrollBar()->setSliderPosition(0);
  20. }

  21. /***上一页***/
  22. void SplayHisForm::prePageHis()
  23. {
  24.     int maxValue = hisTableWidget->verticalScrollBar()->maximum(); // 当前SCROLLER最大显示值25
  25.     nCurScroller = hisTableWidget->verticalScrollBar()->value();

  26.     if(nCurScroller>0)
  27.         hisTableWidget->verticalScrollBar()->setSliderPosition(nCurScroller-pageValue);
  28.     else
  29.         hisTableWidget->verticalScrollBar()->setSliderPosition(maxValue);
  30. }

 QTableView和QTableWidget翻页功能实现

posted @ 2013-11-17 17:15 米米 阅读(1699) | 评论 (0)编辑 收藏

2013年9月12日 #

vs生成的工程 用
qmake -project 生成pro
在pro里增加

TRANSLATIONS += myapp.ts

然后命令行输入lupdate ***.pro
打开.ts文件,一条一条的翻译就是了
最后lrelease ***.pro

posted @ 2013-09-12 15:59 米米 阅读(299) | 评论 (0)编辑 收藏

2013年6月5日 #

Qt4中的tooltip与win32中的tooltip有很多不一样的地方,下面来总结一下。

一是不能直在堆或栈中生成QToolTip对象。因为其构造函数为私有。
二是从widget获取的tooltip不是tooltip对象,而是tooltip中的文本。
三是tooltip跟本不是一个widget。所以不把它当作widget用。
四是tooltip类是一个静态类,所以跟本不必生成tooltip对象就可以使用。
五是tooltip类不能被定制,所以不能从它产生各种形状的tooltip窗口。

QtoolTip有两种使用方式:
一是静态tooltip。比如为一个widget设置一个不变的tooltip文本,当鼠标移上去时显示tooltip。此时很简单,只需调用widget的setToolTip()设置文本即可。
二是动态tooltip。也就是一个widget上的tooltip是变化的。此时需要重写QWidget::event()函数,在里面判断事件类型,如果是QEvent::ToolTip,则控制显示的文本的内容,即可实现动态tooltip。

看如下代码示例:

  1. bool SortingBox::event(QEvent *event)  
  2.  {  
  3.      if (event->type() == QEvent::ToolTip) {  
  4.          QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);  
  5.          int index = itemAt(helpEvent->pos());  
  6.          if (index != -1) {  
  7.              QToolTip::showText(helpEvent->globalPos(), shapeItems[index].toolTip());  
  8.          } else {  
  9.              QToolTip::hideText();  
  10.              event->ignore();  
  11.          }  
  12.   
  13.          return true;  
  14.      }  
  15.      return QWidget::event(event);  
  16.  }  
可以看到,是调用 QtoolTip::showText()在某个位置显示tooltip文本。

那么,如果想随时显示tooltip,该怎么做呢?其实十分简单:直接调用QToolTip::showText(),指定要显示的位置就行了。因为tooltip类的函数跟本就相当于全局函数而已。

呵呵,其实很简单,但从win32转过来的人,觉得真别扭。
posted @ 2013-06-05 16:41 米米 阅读(1101) | 评论 (0)编辑 收藏

QThread从QObject派生。它发出信号来表明线程开始了或结束了。并且也提供了几个槽。

更有趣的是,QObject可以在多个程中同时使用,可以发出信号给另外线程的槽,以及向“活在”另外线程中的对象邮寄事件。以上之所以能发生,是因为每个初程都被允许拥有它自己的事件循环。

QObject 重入

QObject 是可重入的。它大多数非界面派生类,比如QTimer,QTcpSocket,QFtp,和QProcess,也都是可重入的,使得在多个线程中同时使用 这些类成为可能。但是注意这些类被设计为在一个线程中创建和使用;在一个线程中创建一个对象然后在另一个线程中调用它的方法是不能保证一定能工作的。有三 个限制条件要注意:
QObject的儿子必须在创建它爹的线程中创建。这表示,你永远不能将QThread对象(this)作为parent传给在此thread创建的对象,因为线程对象自己就是在另一个线程中创建的。
事件驱动的对象应该只用于一个线程中。这一条尤其应用于定时器和网络模块。比如,你不能在创建对象之外的线程中启动一个定时器或连接一个socket。
你必须保证在线程中创建的一切对象在QThread被删除之前被删除。这可以通过在你的run()实现中在棧中创建对象来轻松搞定。

尽管QObject是可重入的,但GUI类,尤其是QWidget和它所有的派生类们,都不是可重入的。它们只能在主线程中使用。QCoreApplication::exec()必须在这个线程中调用。

在实际应用中,最好的方式是把耗时的计算放到主线程中外进行,完成后通知主线程显示结果。

Pre-Thread Event循环

每 个线程都可以有它自己的事件循环。初始的线程使用QCoreApplication::exec()来开始它的事件循环;其它的线程可以使用 QThread::exec()来启动循环。就像QCoreApplication,QThread也提供了一个exit(int)方法和一个 quit()槽。

线程中的事件循环使得在线程中使用依靠消息循环的非GUI的QT类成为可能(比如QTimer,QTcpSocket,QProcess)。它也使得从任何线程连接信号到一个线程的槽成为可能。这在下面的“信号和槽穿越线程”一节中有详细解释。

一个QObject实例在那个线程中创建,就叫做“活”在那个线程中。给这个对象的事件们通过线程的事件循环派发。一个QObject对象所“活在”的线程通过QObject::thread()可以取得。

注 意在QApplication之前创建的QObject调用QObject::thread()会返回0.这意味着主线程将只为这些对象处理邮寄的事件; 对于没有线程的对象,其它的事件处理跟本不会发生。使用QObject::moveToThread()方法来改变对象(和它儿子们)的线程(如果一个对 象有爹,它就不能被移动到另外线程)。

在拥有对象之外的线程中调用删除对象是不安全的,除非你能保证在被删除时不在处理事件。但可以使用 QObject::deleteLater(),它会寄出DeferedDelete事件,对象的线程的事件循环最终会抓住它。默认下,拥有 Qobject的线程就是创建QObject的线程,但在QObject::moveToTread()之后就变了。

如果没有事件循环,事件将不能传给对象。比如,如果你在一个线程中创建一个QTimer对象,但是没有再调用exec(),那么QTimer将永不能触发timeout()信号。deleteLater()也不再能工作。(这些也同样适用于主线程。)

你可以在任何线程中使用QCoreApp:postEvent()手动向任何对象邮寄事件。事件将被对象所在线程的事件循环自动派发。

事 件过滤器被所有的线程所支持,但有个限制条件:监视对象必须与被监视对象位于同一个线程中。同样 的,QCoreApplication::sendEvent()(不同于 QCoreApplication::postEvent())只能在同一线程中的对象之间发送事件。

从另外线程访问QObject子类


QObject和它所有的子类都不是线程安全的,这也包含整个事件派送系统。要记住,当你从另外线程访问对象时,事件循环可能派送事件到你的QObject子类。

如果你调用一个非本线程的QObject的子类的函数并且这个对象可能接收事件,你必须用mutex保护所有对你的QObject子类的内部数据的访问;否则,你可能体验的什么叫崩溃。

就像其它对象,QThread对象“活”在创建它的线程中,而不是它自己所代表的线程中。通常在你的QThread子类中提供槽是不安全的,除非你用mutex保护成员变量。

另一方面,你可以从你的QThread tun()中安全的发出信号,因为信号发射是线程安全的。


穿越线程的信号和槽们


Qt支持如下信号-槽连接类型:
 自动连接(默认)- 如果信号是从接收对象所在的线程发出的,其行为与“直接连接”相同。否则,其行为与“队列连接”相同。
 直接连接- 当信号发出,槽会被立马调用。此槽在发出者的线程中执行,而不一定是接收者所在的线程。
 队列连接- 当控制返回到接收者所在线程的事件循环时调用。槽在接收者的线程中执行。
 阻塞的队列连接- 槽像“队列连接”那样被调用,除了一点:当前线程会阻塞住直到槽返回。注:在同一线程中使用此类型的连接将导致死锁!
 唯一连接- 行为与“自动连接”相同,但连接必须在无复制品时才能建立。也就是,如果在相同的两个对象之间已经建立了同一个信号到同一个槽的连接,那么连接就不能建立,connect()返回false。

连接类型可以通过给connect()传递一个额外的参数来指定。注意当接收者和发送者位于不同的线程中时,使用“直接连接”,如果事件循环是运行于接收者的线程中,此时是不安全的,同理调用位于另外线程的对象的任何函数都是不安全的。

QObject::connect()本身是线程安全的。
posted @ 2013-06-05 16:40 米米 阅读(917) | 评论 (0)编辑 收藏

将动画们弄到一起


一个应用通常将包含不止一个动画。例如,你可能想同时移动多个图形item也可能顺序的一个接一个的移动。
QanimationGroup 的子类们(QSequentialAnimationGroup和QParallelAnimationGroup)是其它动画的容器,所以这些动画既可 以并行也可以串行。QAnimationGroup是一个非属性动画的例子,但是它定期的收到时间改变的通知。这使得它可以把时间改变传输给所包含的动画 们,从而控制何时播放那些动画们。

让我们看一下使用QSequentialAnimatoinGroup和QParallelAnimationGroup的代码示例。
QPushButton *bonnie = new QPushButton("Bonnie");
bonnie->show();
QPushButton *clyde = new QPushButton("Clyde");
clyde->show();
QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");
// Set up anim1
QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");
// Set up anim2
QParallelAnimationGroup *group = new QParallelAnimationGroup;
group->addAnimation(anim1);
group->addAnimation(anim2);
group->start();
一个并行group在同一时刻播放多个动画。对start()的调用将启动它所统治的所有的动画。

QPushButton button("Animated Button");
button.show();
QPropertyAnimation anim1(&button, "geometry");
anim1.setDuration(3000);
anim1.setStartValue(QRect(0, 0, 100, 30));
anim1.setEndValue(QRect(500, 500, 100, 30));
QPropertyAnimation anim2(&button, "geometry");
anim2.setDuration(3000);
anim2.setStartValue(QRect(500, 500, 100, 30));
anim2.setEndValue(QRect(1000, 500, 100, 30));
QSequentialAnimationGroup group;
group.addAnimation(&anim1);
group.addAnimation(&anim2);
group.start();
QsequentialAnimationGroup顺序的播放它的动画们。它在上一个完成时按顺序播放下一个。

既然一个动画组本就是一个动画类,你可以把它添加到其它组中。如此,你可以建立起一个动画树。


动画和状态
当 使用状态机,我们可以使用一个QSignalTransition或QEventTransition类在状态转换时连接一个或多个动画。这些类都是从 QAbstractTransition派生的,它们定义了简易的函数addAnimation(),使得能够添加一个或多个动画,在状态转换时启动这些 动画。

我们还可能连接属性与状态,而不是手动设置开始与结束值。下面是完整的代码,演示了动画一个QPushButton的geometry属性。

QPushButton *button = new QPushButton("Animated Button");
button->show();
QStateMachine *machine = new QStateMachine;
QState *state1 = new QState(machine);
state1->assignProperty(button, "geometry", QRect(0, 0, 100, 30));
machine->setInitialState(state1);
QState *state2 = new QState(machine);
state2->assignProperty(button, "geometry", QRect(250, 250, 100, 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();
posted @ 2013-06-05 16:40 米米 阅读(503) | 评论 (0)编辑 收藏

概述

Qt动画架构中的主要类如下图所示:



动画框架由基类QAbstractAnimation和它的两个儿子QVariantAnimationQAnimationGroup组成。QAbstractAnimation是所有动画类的祖宗。它包含了所有动画的基本属性。比如开始,停止和暂停一个动画的能力。它也可以接收时间改变通知。


动画框架又进一步提供了QProertyAnimation类。它继承自QVariantAnimation并对某个Qt属性(它须是Qt的”元数据对象系统”的一部分,见http://blog.csdn.net/nkmnkm/article/details/8225089)执行动画。此类对属性执行一个宽松曲线插值。所以当你想去动画一个值时,你可以把它声明为一个属性,并且让你的类成为一个QObject。这给予我们极大的自由度来动画那些已存在的widget和其它QObject


复杂的动画可以通过建立一个QAbstractAnimation的树来构建。这个树通过使用QAnimationGroups来创建,QAnimationGroups作为其它动画的容器。注意动画组也是从QAbstractAnimation派生的,所以动画组可以再包含其它动画组。


动画框架可以单独使用,同时也被设计为状态机框架的一部分。状态机提供了一个特定的状态可以用来播放动画。在进入或退出某个状态时QState也可以设置属性们,并且这个特定的动画状态将在指定QPropertyAnimation时给予的值之间做插值运算。后面我们要进一步介绍此问题。


在场景的背后,动画被一个全局定时器收集,这个定时器发送update到所有的正在播放的动画中。

动画框架中的类们

QAbstractAnimation

所有动画类的基类

QAnimationGroup

动画组的基类

QEasingCurve

控制动画的宽松曲线类

QParallelAnimationGroup

并行动画组类

QPauseAnimation

串行动画组类的暂停类

QPropertyAnimation

动画Qt属性的类

QSequentialAnimationGroup

串行动画组类

QTimeLine

控制动画的时间线类

QVariantAnimation

各动画类的虚基类


动画Qt属性们

如前面所讲,QPropertyAnimation类可以修改Qt属性们。要动画一个值,就需要使用此类。实际上,它的父类,QVariantAnimation,是一个虚拟类,不能被直接使用。


我们选择动画Qt属性的一个主要理由是Qt属性为我们提供了自己动画已存在的类的自由度。尤其是QWidget类(我们也可以把它嵌入到一个QGraphicsView中)具有很多属性表示其bounds,colors等等。让我们看一个小例子:

  1. QPushButton button("Animated Button");  
  2. button.show();  
  3. QPropertyAnimation animation(&button, "geometry");  
  4. animation.setDuration(10000);  
  5. animation.setStartValue(QRect(0, 0, 100, 30));  
  6. animation.setEndValue(QRect(250, 250, 100, 30));  
  7. animation.start();  

这段代码将把按钮在10秒种内从屏幕的左上角移动到(250,250)处。

上面的例子举在开始值和结束值之间做线性插值。还可以在开始和结束值之间设置值,插值运算就会经过这些点。


  1. QPushButton button("Animated Button");  
  2. button.show();  
  3. QPropertyAnimation animation(&button, "geometry");  
  4. animation.setDuration(10000);  
  5. animation.setKeyValueAt(0, QRect(0, 0, 100, 30));  
  6. animation.setKeyValueAt(0.8, QRect(250, 250, 100, 30));  
  7. animation.setKeyValueAt(1, QRect(0, 0, 100, 30));  
  8. animation.start();  

在此例中,动画将按钮在8秒中内弄到(250,250)处,然后在2秒种内又弄回原位。移位是在这些点中间以线性插值进行的。


你 也有可能动画一个QObject的值,虽然这些值并没有被声明为Qt属性。唯一的要求就是这个值具有一个setter。之后你可以从这个类派生子类从而包 含这些值并且声明一个使用这个setter的属性。注意每个Qt属性都需要有一个getter,所以你需要提供一个getter,如果它不存在的话。

  1. class MyGraphicsRectItem : public QObject, public QGraphicsRectItem  
  2. {  
  3.     Q_OBJECT  
  4.     Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)  
  5. };  

在上例中,我们派生了QGraphicsRectItem并定义了一个geometry属性。我们现在可以动画这个widget的geometry了,即使QGraphicsRectItem没有提供geometry属性。

动画和图形视图框架

当你想动画QGraphicsItems,你也要用QPropertyAnimation。然而,QGraphicsItem不是从QObject派生的。一个好的解决方案是派生要动画的图形item。派生类也要从QObject派生。这样,QPropertyAnimation就可以被用于QGraphicsItems了。

  1. class Pixmap : public QObject, public QGraphicsPixmapItem  
  2. {  
  3.     Q_OBJECT  
  4.     Q_PROPERTY(QPointF pos READ pos WRITE setPos)  
  5.     ...  

就如上一节中所讲的,我们需要定义希望去动画的属性。

注意:QObject必须是继承中的第一个,因为元数据对象系统需要这样做。

宽松曲线

QPropertyAnimation在属性的开始值和结束值之间执行一个插值运算。除了向动画添加更多的关键值外,你还可以使用一个宽松曲线。宽松曲线描述了一个在01之间插值的速度变化的函数,如果你想控制一个动画的速度而不改变插值的路径时,就非常有用。


  1. QPushButton button("Animated Button");  
  2. button.show();  
  3. QPropertyAnimation animation(&button, "geometry");  
  4. animation.setDuration(3000);  
  5. animation.setStartValue(QRect(0, 0, 100, 30));  
  6. animation.setEndValue(QRect(250, 250, 100, 30));  
  7. animation.setEasingCurve(QEasingCurve::OutBounce);  
  8. animation.start();  

这里,动画将按照一个曲线进行,这个曲线使得动画像一个跳动的皮球从开始位置跳到结束位置。QEasingCurve具有一个大曲线集合,你可以从里面选择一个。它们被定义为QEasingCurve::Type枚举。如果你需要不一样的曲线,你也可以自己实现一个,然后注册到QEasingCurve

posted @ 2013-06-05 16:39 米米 阅读(429) | 评论 (0)编辑 收藏

仅列出标题  下一页