I would like to load a few images to the Image object in QML. I want to do it one after another in a loop I think with some delay, because it should pretend to look like an animation. Im new in Qt and QML, so can anybody help me how to begin or somethin'? :)
The simplest solution, that works in QML 1.x and 2.0, is to use a Repeater and a Timer :
import QtQuick 2.0
Rectangle {
id: base;
width: 800;
height: 600;
property variant images : [
"image1.jpg",
"image2.jpg",
"image3.jpg",
"image4.jpg",
"image5.jpg"
];
property int currentImage : 0;
Repeater {
id: repeaterImg;
model: images;
delegate: Image {
source: modelData;
asynchronous: true;
visible: (model.index === currentImage);
}
}
Timer {
id: timerAnimImg:
interval: 500; // here is the delay between 2 images in msecs
running: false; // stopped by default, use start() or running=true to launch
repeat: true;
onTriggered: {
if (currentImage < images.length -1) {
currentImage++; // show next image
}
else {
currentImage = 0; // go back to the first image at the end
}
}
}
}
Should do it, and if you don't want the animation to restart when the last image is reached, just replace currentImage = 0; with stop(); in the timer's onTriggered.
Also, you should possibly have to tweak a little the Image delegate in the Repeater to give it the look you want (size, fill mode, position etc...).
If you are using QtQuick 2 then AnimatedSprite is the best way to do this: http://qt-project.org/doc/qt-5.0/qtquick/qtquick-effects-sprites.html
Otherwise, you could use a Timer or NumberAnimation to trigger changing the image source, but there could be unpredictable delays as images load for the first time (caching should solve this after the first loop). If you only have a few images, you could have three Images and cycle their visibility.
Related
Below is a small QML application. What I intended was for the application to start full screen, and on the Escape key, change it to maximized:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: topLevelWindow
width: 640
height: 480
visible: true
title: qsTr("Hello World")
visibility: Window.FullScreen
Rectangle {
id: rect
anchors.fill: parent
color: "lightBlue"
focus: true
Keys.onPressed: {
if (event.key === Qt.Key_Escape) {
rect.color = "lightGreen"
topLevelWindow.visibility = Window.Maximized
}
}
}
}
What actually happens, though, is that it starts full screen as intended, but pressing Escape makes it windowed but not maximized. Pressing Escape a second time actually maximizes it.
Is there a way to do this without making the user hit Escape twice?
It looks like this is indeed a bug. Seems like it's been lingering for a while, but (some) newer versions may have fixed it?
In the meantime, it's relatively easy to add a hacky workaround:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: topLevelWindow
width: 640
height: 480
visible: true
title: qsTr("Hello World")
visibility: Window.FullScreen
Rectangle {
id: rect
anchors.fill: parent
color: "lightBlue"
focus: true
Keys.onPressed: {
if (event.key === Qt.Key_Escape) {
rect.color = "lightGreen"
topLevelWindow.visibility = Window.Windowed
windowHackTimer.start()
}
}
}
Timer {
id: windowHackTimer
interval: 0
repeat: false
onTriggered: {
topLevelWindow.visibility = Window.Maximized
}
}
}
On the button press it becomes windowed, and then after it returns to the event loop (with a 0ms timer), it sets it to maximized. Just setting topLevelWindow.visibility multiple times in Keys.onPressed doesn't get the job done.
I think you should (1) make sure that the Escape key is accepted by your event handler (so that it is not passed down) and (2) schedule the outcome with Qt.callLater.
Keys.onPressed: {
if (event.key === Qt.Key_Escape) {
event.accepted = true;
Qt.callLater( greenRectAndMaximize );
}
}
function greenRectAndMaximize() {
rect.color = "lightGreen";
topLevelWindow.visibility = Window.Maximized;
}
The event.accept() is important to ensure that no other UI will handle the same event. That could be the cause of your problem. The Qt.callLater is important because it ensures that your action is added to the end of the windows messaging queue so that the UI/UX for the Escape key (and any other UI/UX events can complete) before we do our action.
Generally, whenever processing events, key presses, button clicks, and so forth, think about what needs to happen now and what needs to be queued for later.
In your case, you have a simple action, but, imagine something more complex such as a button click that triggers a page transition and a sort of 10000 records. The UI/UX is the user clicks the button and we want to see the button animate down and up fully before the action kicks off. If we did it during the event handler, the button may appear to be stuck in the down portion of the animation and the app will appear momentarily hang/crash. So, it is important to understand when we need to queue up actions.
Qt.callLater is one of the easiest ways to separate the UI/UX event and the user action and can improve the perceptual responsiveness of your application.
I have a ListView Containing only Images. I assigned the orientation of ListView as horizontal Direction. How can I change, i.e. scroll, the images automatically with some time gap?
Use a Timer. When it is triggered, update the currentIndex of the ListView. This will scroll automatically with default animations. Finally, according to the documentation, positionViewAtIndex is
The correct way to bring an item into view is with positionViewAtIndex
Indeed the method provides a more fine-grained control over the appearance of Items via the PositionMode parameter. See the documentation for further details.
Minimal example:
import QtQuick 2.5
import QtQuick.Window 2.0
Window {
visible: true
width: 200
height: 15
ListView {
id: list
anchors.fill: parent
orientation: ListView.Horizontal
model: 10
delegate: Text {
width: 40
id: name
text: index
}
}
Timer {
interval: 500
repeat: true
running: true
onTriggered: {
//list.currentIndex += 1 // this...
//list.incrementCurrentIndex() // ...or this!
//list.positionViewAtIndex(list.currentIndex, ListView.Center)
}
}
}
Where QML camera.videoRecorder.record() save video file by default ?
import QtQuick 2.2
import QtMultimedia 5.0
Item {
id:recoder
width:640
height:360
property bool rstat:true
function recordingSt(st)
{
if(st){
camera.videoRecorder.record() ;
st = false;
}else{
camera.videoRecorder.stop() ;
st = true;
}
}
MouseArea
{
anchors.fill: parent
onClicked:recordingSt(rstat)
}
Camera {
id: camera
videoRecorder.audioEncodingMode: CameraRecorder.ConstantBitrateEncoding
videoRecorder.audioBitRate: 48000
videoRecorder.mediaContainer: "mp4"
videoRecorder.frameRate: 25
}
VideoOutput {
source: camera
anchors.fill: parent
focus : visible // to receive focus and capture key events when visible
}
}
I am using Win8 OS have no idea where the video goes and how to set the path for recording . I tried
videoRecorder.outputLocation: "sameDirectory"
still not working why ?
From the documentation, it looks like you can set the location where you want to save by means of the properties imageCapture, which has the method captureToLocation.
It has also a property called capturedImagePath that maybe contains what you are looking for.
Look here and here and here for further details.
Sorry, just seen you were asking for the videoRecording.
It has the actualLocation property as well and it works as above, doesn't it?
The documentation states that that property holds the actual location of the last saved media content. Be aware that it's available once the recording starts, so you should look at it after the record method has been invoked.
Trying to build a little fotball game as an project in school but I'm having some issues. So when I run the code it says that ReferenceError: Screen is not defined, but accordign to me I have defined it.
This code is just a prototype, going to change the keys to buttons later on so that it can actually work on a phone.
import QtQuick 2.0
Item {
id:root
width:Screen.width
height:Screen.height-10
focus:true
Keys.onPressed: {
if(event.key===Qt.Key_Up)
{
event.accepted = true;
player.y=(player.y) - 40
}
if(event.Key === Qt.Key_Down){
event.accepted = true;
player.y = (player.y)+ 40
}
if (event.key === Qt.Key_Right)
{ event.accepted=true;
player.x=(player.x)-40
}
if (event.key === Qt.Key_Left)
{event.accepted = true;
player.x=(player.x) +40
}
}
Flickable {
width:Screen.width
height:Screen.height
contentHeight: Screen.height*4
contentWidth:Screen.width
interactive:true
boundsBehavior: Flickable.StopAtBounds
Image{
id: feild
anchors.fill:parent
source:"Namnlös.png"
sourceSize.height:Screen.height*4
sourceSize.width:Screen.width
}
Image {
id: player
source:"asd.png"
x:Screen.width/2
y:Screen.height/2
}
}
}
So if you run this code you'll only get the player showing up, and then disapear instantly, the field is not shown.
You lack the Screen import.
import QtQuick.Window 2.1
Screen docs
Resizing items to screen is abnormal, you should simply use
resizeMode property
and anchor all child items inside root item.
So i have an image that i want to drop down the page.
Should the user click a button, the image will stop said dropping down the page.
I've used the eventListener 'complete' style to execute this... and it works, in a fashion. The problem is that the dropping down is choppy ~ irritatingly so.
Is there a more efficient way for titanium to do some form of simple animation?
Here is a code slice:
ballAnimation = Ti.UI.createAnimation({
top: ballDown.top + 0.01*heightOfScreen,
duration: someSpeedHere
}, function(){
if (hasBeenPressed){
return;
}
else if (!hasBeenPressed && ballAnimation.top > lowestPointForBall){
someFunctionHere(); //this isn't part of the problem.
}
}
);
ballAnimation.addEventListener('complete', function(){
if (hasBeenPressed){
return;
}
else if (!hasBeenPressed && ballAnimation.top > lowestPointForBall){
someFunctionHere(); //this isn't part of the problem.
} else {
ballAnimation.top = ballAnimation.top + 0.01*heightOfScreen;
ballDown.animate(ballAnimation);
}
});
ballDown.animate(ballAnimation);
For animations it is advised to use a 2D matrix with a translation like this:
var translation = Titanium.UI.create2DMatrix(), deltaX, deltaY; // set the deltaX and deltaY according
translation = translation.translate(deltaX, deltaY);
ballDown.animate({
transform : translation,
duration : someSpeedHere
});