若该文为原创文章,未经允许不得转载

各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

目录

​前话​

​关于Sprites精灵动画​

​BorderImage​

​描述​

​属性​

​AnimatedImage​

​描述​

​属性​

​AnimatedSprite​

​描述​

​属性​

​方法​

​示例​

​SpriteSequence​

​描述​

​属性​

​方法​

​入坑​

​示例​


​红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中..​​​​.(点击传送门)​

​​Qt开发专栏:qml开发(点击传送门)​​


qml开发笔记(五): 可视化元素BorderImage、AnimatedImage、AnimatedSprite、SpriteSequence


前话

        上一章节介绍了可视化元素Rectangle和Image。本章节将继续学习可视化元素BorderImage、AnimatedImage、AnimatedSprite和SpriteSequence。

        BorderImage是单个图像分区域缩放;

        AnimatedImage是播放gif;

        AnimatedSprite是精灵动画;

        SpriteSequence本人认为非常有必要认真阅读,实现了游戏当中的走路,代码很简单,原理是sprites精灵动画。


关于Sprites精灵动画

        qml的sprites可参照css的sprites,我们可以把一个精灵当作一个动画。

        CSSSprites在国内很多人叫CSS精灵,其实这个技术不新鲜,原理就是:靠不断的切换图片让人感觉视觉上不断在变化,例如gif动画之类的效果,前端实现精灵效果原理有两种方式:

        第一种:传统的就是靠定时器不断去改变一个元素的background-image属性了,简单的来说就是靠不断的替换图片,但是值得注意的问题就是图片如果很多,加载会比较慢,会占用大量网络资源。

        第二种:大多数的做法就是把图片都合成一张大图再利用CSS的属性(background-image、background-repeat、background-position)组合进行背景定位,background-position可以用数字精确的定位出背景图片的位置。


BorderImage

描述

        本元素用于创建有边框分割的图像,图像可缩放和平铺其中的每个部分。一个本元素可将图片分成9个区域,如下图:

qml开发笔记(五): 可视化元素BorderImage、AnimatedImage、AnimatedSprite、SpriteSequence_SpriteSequence

        1.    角区域1/3/7/9是不会缩放的;

        2.    区域2和8缩放是依赖​​horizontalTileMode​​;

        3.    区域4和6缩放是依赖​​verticalTileMode​​;

        4.    区域5缩放是依赖​​horizontalTileMode​​​和​​verticalTileMode​​;

属性

  • asynchronous  : bool [指定本地文件系统上的图像应在单独的线程中异步加载。默认值为false,导致用户界面线程在加载图像时阻塞。将异步设置为true对保持响应性用户界面比立即可见图像更可取] (注意:此属性只对从本地文件系统读取的图像有效。通过网络资源(例如HTTP)加载的图像总是异步加载。)
  • border[该边界是将borderImage分割城9个区域的边界]
Rectangle {
Image {
source: "3.png";
}
BorderImage {
x:150;
source: "3.png";
width: 200; height: 200;
border.left: 35; border.top: 35;
border.right: 35; border.bottom: 35;
}
BorderImage {
x:400;
source: "3.png";
width: 200; height: 200;
border.left: 45; border.top: 45;
border.right: 45; border.bottom: 45;
}
BorderImage {
x:650;
source: "3.png";
width: 200; height: 200;
horizontalTileMode: BorderImage.Repeat
border.left: 35; border.top: 35;
border.right: 35; border.bottom: 35;
}
BorderImage {
x:900;
source: "3.png";
width: 200; height: 200;
horizontalTileMode: BorderImage.Round
border.left: 35; border.top: 35;
border.right: 35; border.bottom: 35;
}
}

qml开发笔记(五): 可视化元素BorderImage、AnimatedImage、AnimatedSprite、SpriteSequence_AnimatedSprite_02

  • border.left: int [参照上面]
  • border.right: int [参照上面]
  • border.top: int [参照上面]
  • border.bottom: int [参照上面]
  • cache : bool [指定是否应缓存图像。默认值为true。在处理大型图像时,将缓存设置为false是很有用的,以确保它们不会以牺牲小UI元素的图像为代价进行缓存]
  • horizontalTileMode : enumeration [如何重复或拉伸边界图像的中间部分,缺省为Stretch]



BorderImage.Stretch - Scales the image to fit to the available area.
BorderImage.Repeat - Tile the image until there is no more space. May crop the last image.
BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped.


  • mirror: bool [rotation为0度时,以纵轴为轴心,做镜像,缺省false]
  • progress : real [这个属性保存图像的加载进度,从0(无负载)到1(完成)]
  • smooth : bool [此属性保存缩放或转换时图像是否平滑地过滤。平滑过滤提供了更好的视觉质量,但在某些硬件上可能会慢一些。如果图像以自然大小(本身大小)显示,则此属性没有视觉效果或性能效果。默认情况下,此属性设置为true]
  • source : url [映像可以处理Qt支持的任何图像格式,它由Qt支持的任何URL方案加载。URL可能是绝对的,或者与组件的URL相对]
  • sourceSize : QSize[此属性包含加载图像的实际宽度和高度。与宽度和高度缩放的属性不同,此属性设置存储的图像的实际像素数,以便大图像不使用比必要的更多内存,参照Image元素的例子,保证图像在内存不大于1024x1024像素]
  • status : enumeration [这个属性保存图像的加载状态]



Image.Null       - no image has been set  
Image.Ready - the image has been loaded
Image.Loading - the image is currently being loaded
Image.Error - an error occurred while loading the image



AnimatedImage

描述


    Animatedimage提供一种方式来播放存储包含一系列的帧的图像动画,如存储图像的gif文件。

Rectangle {
width: animation.width;
height: animation.height + 8;
color: "black";
AnimatedImage {
id: animation;
source: "4.gif";
}
Rectangle {
// 下句报错"depends on non-NOTIFYable properties:
// QQuickAnimatedImage::frameCount"
// rectangle不显示
// property int frames: animation.frameCount; // 报错语句
width: 4; height: 8
// x: (animation.width - width) * animation.frames / frames; // 报错语句
x: (animation.width - width) * animation.currentFrame / animation.frameCount
y: animation.height
color: "red"
}

qml开发笔记(五): 可视化元素BorderImage、AnimatedImage、AnimatedSprite、SpriteSequence_AnimatedImage_03

属性

  • currentFrame : int [当前正在显示的帧的序号]
  • frameCount : int [帧的总数]
  • paused : bool [暂停,播放成功后暂停会停止播放,paused前提是playing为true,每次playing从false变为true,paused会自动变为false]
  • playing : bool [播放中,当成功加载图像后,变为true,用以标志图像加载结果]
  • source : url [gif地址]


AnimatedSprite

描述

        Animatedsprite提供渲染和提供了在同一个图像文件的多个帧的动画控制。可以以固定的速度播放,以显示的帧速率,或手动推进和控制进度。

属性

  • currentFrame : int [当暂停时,可手动设置当前帧或者使用advance()推进一帧]
  • frameCount : int [总帧数]
  • frameDuration : int [每一帧动画的间隔,当等于或小于0时无效;如果frameRate有效,frameRate则会被用于计算该帧的持续时间;如果frameRate无效,但frameDuration有效,那么将使用frameDuration,注意:更改此参数将重新启动动画]
  • frameHeight : int [单帧高度,如果都一样则唯一的,则可忽略]
  • frameRate : qreal [每秒显示的动画帧数,当等于或小于0时无效;如果frameRate有效,frameRate则会被用于计算该帧的持续时间;如果frameRate无效,但frameDuration有效,那么将使用frameDuration,注意:更改此参数将重新启动动画]
  • frameSync : bool [如果为真,则动画将没有持续时间。每次一帧渲染到屏幕时,动画将前进一帧。这使它与绘画速度同步,而不是经过时间。如果framesync设置为true,它将重写的帧率和frameduration。默认为false。更改此参数将重新启动动画]
  • frameWidth: int [单帧宽度,如果都一样则唯一的,则可忽略]
  • frameX : int [在animatedsprite第一帧图像文件的x坐标。如果第一帧在文件左上角开始,则可以忽略]
  • frameY : int [在animatedsprite第一帧图像文件的y坐标。如果第一帧在文件左上角开始,则可以忽略]
  • interpolate : bool [如果为true,则在精灵帧之间会出现插值,使动画看起来更平滑(前一张渐隐后一张渐显)。默认为true]
  • loops : int [动画多次播放后,动画会自动停止。负值是无效的。如果设置为AnimatedSprite.Infinite,动画将会无限循环播放,且默认是无限AnimatedSprite.Infinite]
  • paused : bool [暂停时,当前帧可以手动更新,默认为false。]
  • reverse : bool [是否反向播放,默认为false]
  • running : bool [是否正在播放动画,默认为true]
  • source : url [动画地址]

方法

  • int advance() [前进一帧]
  • int pause() [暂停]
  • int restart() [重新播放]
  • int resume() [暂停后的恢复播放]

示例

Rectangle {
visible: true;
width: 360;
height: 320;
color: "white";
Image {
id:image
source: "./6.png"
x:350
}
AnimatedSprite {
id: animated;
width: image.width/3; // 显示窗口宽度
height: image.height/2; // 显示窗口高度
anchors.centerIn: parent;
source: "6.png";
frameWidth: image.width/4;
frameHeight: image.height/3;
frameDuration: 200;
frameCount: 16;
frameX: 0;
frameY: 0;
onCurrentFrameChanged: {
info.text = "%1/%2".arg(animated.currentFrame).arg(animated.frameCount);
}
}
Row{
spacing: 4;
anchors.horizontalCenter: parent.horizontalCenter;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
Text {
id: info;
width: 60;
height: 24;
color: "red";
verticalAlignment: Text.AlignVCenter;
horizontalAlignment: Text.AlignRight;
}

Button {
width: 60;
height: 24;
text: (animated.paused == true) ? "Play" : "Pause";
onClicked: (animated.paused == true) ? animated.resume() : animated.pause();
}
Button {
width: 70;
height: 24;
text: "Advance";
onClicked: animated.advance();
}
Button {
width: 70;
height: 24;
text: "Restart";
onClicked: animated.restart();
}
Button {
width: 60;
height: 24;
text: "Quit";
onClicked: Qt.quit();
}
}
}

qml开发笔记(五): 可视化元素BorderImage、AnimatedImage、AnimatedSprite、SpriteSequence_SpriteSequence_04

运行时,Quit无法退出,报出错误:” Signal QQmlEngine::quit()emitted, but no receivers connected to handle it.”。因为本人采用的是在QtGui中加载qml,不是纯qml应用,所以qml需要与QtGui中的信号相关联;在QtGui中加入代码:

void MainWindow::initQmlWidget()
{
// 初始化quick窗口
_pQuickView = new QQuickView();
_pQuickView->setSource(QUrl("./qml/start.qml"));
_pQuickWidget = QWidget::createWindowContainer(_pQuickView, this);
_pQuickWidget->hide();
// 用于与qml交互
_pQmlContext = _pQuickView->rootContext();
// 显示qml
_pQuickWidget->show();
// 代码补充处: QtGui 与 qml 退出信号关联
QObject::connect(_pQuickView->engine(), SIGNAL(quit()), qApp, SLOT(quit()));
}


SpriteSequence

描述

        用于作为一系列帧存储的多个动画之间的播放和转换。

属性

  • currentSprite: string [只读][当前正在播放的精灵动画名字,只读,只有在暂停时才可以设置]
  • goalSprite: string [下一个播放的精灵动画名字,如果有可能从目标状态的起始点返回到目标状态,那么它将继续这样做(不断0->goalSprite循环),直到目标状态被设置为“”或一个不可到达的状态]
  • interpolate: bool [切换过渡优化,默认true]
  • running: bool [是否正在播放精灵,默认为true]
  • sprites: list<Sprite> [精灵播放列表,播放时精灵将会被缩放到这个项目的大小]

方法

  • jumpTo​(string sprite) [这个函数会导致立即跳转到指定的精灵,中间的精灵不会被播放。精灵的参数是你想要跳转到的精灵的名字]

入坑

捕捉键盘时,若一直按下按钮,会在短暂的停滞后Release然后不断的OnPressed和OnRelease,等同于连续敲击,这点与传统的桌面应用程序不一样。

示例

        实现一个动画,按方向键上下左右,可以走动,松下就停止,效果如下图:

qml开发笔记(五): 可视化元素BorderImage、AnimatedImage、AnimatedSprite、SpriteSequence_SpriteSequence_05

Rectangle {
visible: true;
width: 240;
height: 200;
color: "black";
Image {
x:100;
id: image1;
source: "./11.png";
}
SpriteSequence {
id: sequence;
width: 100;
height: 100;
interpolate: true;
running: false;
sprites: [
Sprite {
name: "down";
source: image1.source;
frameCount: 4;
frameWidth: image1.width/4;
frameHeight: image1.height/4;
frameRate: 10;
},
Sprite {
name: "left";
source: image1.source;
frameCount: 4;
frameY: image1.height/4;
frameWidth: image1.width/4;
frameHeight: image1.height/4;
frameRate: 10;
},
Sprite {
name: "right";
source: image1.source;
frameCount: 4;
frameY: image1.height/4*2;
frameWidth: image1.width/4;
frameHeight: image1.height/4;
frameRate: 10;
},
Sprite {
name: "up";
source: image1.source;
frameCount: 4;
frameY: image1.height/4*3;
frameWidth: image1.width/4;
frameHeight: image1.height/4;
frameRate: 10;
}
]
}
focus: true; // 不获取焦点是无法获取键盘的
Keys.onPressed: { // 当持续按住up时,将会变成多次连击,不断pressedrelease
switch(event.key)
{
case Qt.Key_Up: // false时,跳转到"up",此时无法不跑,再将SpriteSequence.running设置true
sequence.jumpTo("up");
sequence.running = true;
text.text = "按下方向键上,正在向上走路";
break;
case Qt.Key_Down:
sequence.jumpTo("down");
sequence.running = true;
text.text = "按下方向键下,正在向下走路";
break;
case Qt.Key_Left:
sequence.jumpTo("left");
sequence.running = true;
text.text = "按下方向键左,正在向左走路";
break;
case Qt.Key_Right:
sequence.jumpTo("right");
sequence.running = true;
text.text = "按下方向键右,正在向右走路";
break;
default:
;
}
}
Keys.onReleased: {
sequence.running = false;
text.text = "请按方向键走路:上、下、左、右";
}
Text {
id: text;
y:200;
anchors.horizontalCenter: parent.horizontalCenter;
text:"请按方向键走路:上、下、左、右";
}
}

qml开发笔记(五): 可视化元素BorderImage、AnimatedImage、AnimatedSprite、SpriteSequence_SpriteSequence_05