Results 1 to 13 of 13

Thread: How to structure a QML project

  1. #1
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default How to structure a QML project

    Hi,

    currently I am trying to do my first QML project. I have some nice working code in several QML files that display different pages of my App. My next step was to get theses pages to talk to each other but I just do not understand how that is done. There are several code snippets on the net but I am always getting confused where to put what.
    All I managed is to pass on some values using:
    Qt Code:
    1. onClicked: pageStack.push(Qt.resolvedUrl("CountdownPage.qml"), {onTime: onSlider.value, reciverTime: recoverSlider.value, cycles: cycleSlider.value})
    To copy to clipboard, switch view to plain text mode 
    I am woking off the basic example provided in Sailfish SDK that looks like this. There is a main.qml
    Qt Code:
    1. import QtQuick 2.0
    2. import Sailfish.Silica 1.0
    3. import "pages"
    4.  
    5. ApplicationWindow
    6. {
    7. id: main
    8. initialPage: Component { FirstPage { } }
    9. cover: Qt.resolvedUrl("cover/CoverPage.qml")
    10. }
    To copy to clipboard, switch view to plain text mode 
    and within the folder pages are all the different pages of the project. If I want to use some variables that should be available in different pages I read that I could import a javascript file that holds these values. But a) I read that this is not a good idea and b) there is always a new instance of the file and if I change the values the other pages do net get the update. So how can I share values over my entire project?
    Specifically I am interested in sharing a time value that is updated every second. Currently the timer is located in the CountdownPage.qml that is in the folder pages and looks like this:
    Qt Code:
    1. Timer {
    2. id: ticker
    3. interval: 1000;
    4. running: true;
    5. repeat: true;
    6. onTriggered: {
    7. time--;
    8.  
    9. // Setting times
    10. if(time < 0){
    11. animateOpacity.stop()
    12. timer.color = "white" // timer is the text field displaying the value
    13. timer.opacity = 1.0
    14. if(trainOn){
    15. trainOn = false;
    16. time = holdTime;
    17. cycles--;
    18. }else{
    19. trainOn = true;
    20. time = onTime
    21. player.play() // player is a C++ class that I imported
    22. }
    23.  
    24. if(cycles === 0){
    25. ticker.running = false;
    26. timer.text = qsTr("Finish!")
    27. }
    28. }
    29.  
    30. // Animations and Sounds
    31. if(time < 6){
    32. timer.color = "red"
    33. animateOpacity.start()
    34. }
    35. if(!trainOn && time === 5)
    36. soundCountdown.play()
    37. if(trainOn && time === 0){
    38. player.pause()
    39. soundGong.play();
    40. }
    41. }
    42. }
    To copy to clipboard, switch view to plain text mode 
    So it anteracts with other elements in that page. But I can change the page and go to cover while the ticker is still active and then I want to display the ticker time in my cover page. I guess it was not a good idea to have the ticker within the page but I do not know how to do it better. I managed to extend QML with a C++ class and use that in the CountdownPage but I also would like to be able to control the player instance(?) from all pages. So can some tell me how a QML project should be structured? What things should go in the QML file and what in c++ or js files and if it is in an external file in which qml file should I import it?

    Thanks for reading through all of that =)

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to structure a QML project

    There are several ways to achieve this, some having been added at later versions of Qt so not all might be applicable to you.

    The most hackish but oldest option is to define such "global" objects with id in the main/first QML file. These ids are visible throughout the project.

    Another option is to keep the state in JavaScript objects inside a JavaScript "library": http://qt-project.org/doc/qt-5/qtqml...rces-libraries

    A better but newer option is to have a singleton type: http://qt-project.org/doc/qt-5/qtqui...tings-qml.html http://qt-project.org/doc/qt-5/qtqui...nt-qmldir.html

    For applications with C++ core there is also the option of having the state in a C++ object and exporting that to QML using QQmlEngine::setContextProperty().
    Or a combination, by using QQmlEngine::registerSingletonType().

    My preference is on the last two, since it allows things such as reloading the UI without loosing any state.

    Cheers,
    _

  3. #3
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: How to structure a QML project

    Okay, thanks for the help. The reason why I got confused was that Qt Creator does not pick it up when I use the id.property. I have to type everything. Is this normal or should Creator autocomplete?

    Moving my player to the main.qml enabled me to work with it from all pages. Doing the same with my ticker brought the entire project down. Is it possible to use the ticker as I programmed it through the entire project or do I need to set it differently?

    Regarding the singelton approach for the global variables, is this here correct? If so that is not really looking handy...

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to structure a QML project

    Quote Originally Posted by KeineAhnung View Post
    Okay, thanks for the help. The reason why I got confused was that Qt Creator does not pick it up when I use the id.property. I have to type everything. Is this normal or should Creator autocomplete?
    QtCreator can not assume a certain usage of a file, from its point of view it can only "see" what is in the current file scope.

    Quote Originally Posted by KeineAhnung View Post
    Moving my player to the main.qml enabled me to work with it from all pages. Doing the same with my ticker brought the entire project down. Is it possible to use the ticker as I programmed it through the entire project or do I need to set it differently?
    You'll have to debug what is actually wrong. The global id hack should work for the timer as well.

    Quote Originally Posted by KeineAhnung View Post
    Regarding the singelton approach for the global variables, is this here correct? If so that is not really looking handy...
    Yes and no. That thread has several approaches, I guess you are referring to the one with registring in C++?
    If you look at the links I've posted you can simply do that with a qmldir file.

    Cheers,
    _

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: How to structure a QML project

    I would suggest to reconsider having to have global data (be it a singleton or a "globally accessible object"), that's almost never a desired architecture. Maybe you can obtain the same effect by signal propagation or property aliasing.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  6. #6
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: How to structure a QML project

    Hi _,

    actually I was referring to the thread where the link pointed to. I just see that doing links is not so good, it is really hard to tell them apart from the rest of the text. Maybe the forum style sheets needs some improvement here?

    @wysota,
    Looking again at the property aliasing I think I figured that our now. In my main.qml it created a new Item called clock
    Qt Code:
    1. Item {
    2. id:clock
    3.  
    4. property int time: 6
    5. property int trainingTime
    6. property int holdTime
    7. property int cycles
    8. property bool active
    9. property alias running: ticker.running
    10.  
    11. SoundEffect {
    12. id: soundGong
    13. source: "qrc:/sounds/gong.wav"
    14. }
    15. SoundEffect {
    16. id: soundCountdown
    17. source: "qrc:/sounds/countdown_male.wav"
    18. }
    19.  
    20. NumberAnimation {
    21. id: animateOpacity
    22. target: countdownPage.display
    23. property: "opacity";
    24. from: 0.1
    25. to: 1.0
    26. duration: 1000
    27. loops: Animation.Infinite
    28. easing.type: Easing.OutSine
    29. }
    30.  
    31. Timer {
    32. id: ticker
    33. interval: 1000
    34. running: false
    35. repeat: true
    36.  
    37. onTriggered: {
    38. clock.time--
    39. // console.log("Time: "+clock.time+" Cycle: "+clock.cycles)
    40. if(clock.time < 0){
    41. if(clock.active){
    42. clock.active = false
    43. clock.time = clock.holdTime
    44. clock.cycles--
    45. player.pause()
    46. soundGong.play()
    47. }else{
    48. clock.active = true
    49. clock.time = clock.trainingTime
    50. player.play()
    51. }
    52. }
    53. if(clock.time === 5)
    54. animateOpacity.start()
    55. if(clock.time === 5 && !clock.active)
    56. soundCountdown.play()
    57. if(clock.cycles === 0)
    58. ticker.running = false
    59. }
    60.  
    61.  
    62. }
    63. }
    To copy to clipboard, switch view to plain text mode 
    using clock.<property> anywhere in the project allows me to access properties of my clock. For example in my countdown page I can display the current clock time by using
    Qt Code:
    1. Text {
    2. id: display
    3. anchors.centerIn: parent
    4. text: clock.time
    5. color: (clock.time < 6? "red" : "white")
    6. }
    To copy to clipboard, switch view to plain text mode 
    Also the sounds work as planned. The only thing I did not get to work is the text animation. My plan was to create a signal within clock signal tick(clock.time) and "connect" it within the countdown page by using onTick: {} but this gives me the error : "Cannot assign to non-existent property "onTick"". My second thougt was to put it into the clock (see above) but that gives me the error: "ReferenceError: countdownPage is not defined".
    So how can I send a signal from one file to another? All signal examples I found were only within one page. Or how else could I start and stop my text animation?

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: How to structure a QML project

    Quote Originally Posted by KeineAhnung View Post
    The only thing I did not get to work is the text animation. My plan was to create a signal within clock signal tick(clock.time) and "connect" it within the countdown page by using onTick: {} but this gives me the error : "Cannot assign to non-existent property "onTick"".
    Using timers for animations in QtQuick is not a proper approach. You have a bunch of types inheriting Animation to do animations.

    So how can I send a signal from one file to another?
    You don't send signals from somwhere to somewhere else. You just emit a signal and if anyone is interested in it, he can connect to that signal.

    All signal examples I found were only within one page. Or how else could I start and stop my text animation?
    The declarative approach would be to come up with a statement that states when the animation is running, e.g.:
    javascript Code:
    1. NumberAnimation {
    2. // ...
    3. running: clock.cycles > 0
    4. // ...
    5. }
    To copy to clipboard, switch view to plain text mode 

    By the way, from what I see you can get rid of the whole ticker of yours and do everything you do there in a declarative manner instead of imperative statements. The hardest part in learning QML is to make yourself stop thinking imperatively and start thinking declaratively.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  8. #8
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: How to structure a QML project

    Hi wysota,

    first of all thanks a lot for your help. You put me on the right path!
    By the way, from what I see you can get rid of the whole ticker of yours and do everything you do there in a declarative manner instead of imperative statements.
    Is this also true if I want to us the property time on several pages? Say I have to labels in two qml files. Within the app the user shall be able to switch between the pages and always the the time.


    You don't send signals from somewhere to somewhere else. You just emit a signal and if anyone is interested in it, he can connect to that signal.
    This exactly what I did not manage. How do I connect to a signal? onSignalName in another qml file always gives me an error.

  9. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: How to structure a QML project

    Quote Originally Posted by KeineAhnung View Post
    Is this also true if I want to us the property time on several pages? Say I have to labels in two qml files. Within the app the user shall be able to switch between the pages and always the the time.
    I'd start by explaining what are your intentions for having the "time" property in the first place. I think that the sole existance of this property is your main problem. Regardless if this property is physically global or not, you are treating it as one which in my opinion is a misdesign.

    This exactly what I did not manage. How do I connect to a signal? onSignalName in another qml file always gives me an error.
    There is a number of approaches, one of them being to use the Connections element.

    javascript Code:
    1. Connections {
    2. target: someOtherElement
    3.  
    4. onSignalHandler: { ... }
    5. }
    To copy to clipboard, switch view to plain text mode 
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  10. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to structure a QML project

    Quote Originally Posted by KeineAhnung View Post
    actually I was referring to the thread where the link pointed to.
    Yes, I got that. But there are several replies, the first one using an approach that is more complex than necessary. So I guess you were referring to that answer

    Cheers,
    _

  11. #11
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: How to structure a QML project

    The app I am working on is a special stop watch and I want to display the elapsed time. This app shall be for my Jolla and a special feature on Sailfish is that your apps have an active cover when pushed to the home screen. I want to display the time on that "cover" as well.

    Thanks for the help with the connections and the global variables!

  12. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: How to structure a QML project

    Quote Originally Posted by KeineAhnung View Post
    The app I am working on is a special stop watch and I want to display the elapsed time. This app shall be for my Jolla and a special feature on Sailfish is that your apps have an active cover when pushed to the home screen. I want to display the time on that "cover" as well.
    I don't see how this requires any global variables. If I really had to have such variable, especially one related to time, I'd probably implement it in C++ and expose it to the QML engine as a root object context property.

    BTW. You don't need a Timer to show the current time (or elapsed time). And if you want to have a precise calculation of the elapsed time then using a Timer and increasing some time variable in its triggered slot is probably a good way to get invalid results. If you want precise results then simply store the start time and when you need to know how much time has elapsed, subtract current time from that start time. If you have pause functionality, do exactly the same -- note the pause start time and subtract it from pause end time. Such approach will make your app vulnerable to system clock changes but it will prevent situations when the timer doesn't fire exactly then you expect it to. And it wastes much less energy if you doesn't have to show the current elapsed value all the time.
    Last edited by wysota; 24th August 2014 at 07:51.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  13. #13
    Join Date
    Apr 2014
    Posts
    116
    Thanks
    8
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: How to structure a QML project

    I do not need any global variables thanks to your hints with binding the values. Indeed I already ran into the situation that the timer does not give me the correct time. When the system goes into sleep the timer slows down and one second become three or more.

    The app shall show you how many seconds remain in for the current exercise or pause. So the time is displayed all the time. At least when the option prevent sleep is activated.

    By the way, I do not get any notifications by mail anymore if a new post was posted even if I follow this thread (or any other). Is there a issue with the forum?

Similar Threads

  1. MSVC Project generated using qmake - turn off flat structure
    By Piskvorkar in forum Qt Programming
    Replies: 3
    Last Post: 4th February 2013, 23:25
  2. Replies: 12
    Last Post: 26th June 2011, 11:26
  3. Replies: 0
    Last Post: 28th May 2010, 06:50
  4. Project structure with qtestlib
    By matteonardi in forum Qt Programming
    Replies: 1
    Last Post: 1st April 2010, 08:01
  5. Project structure with Qt designer
    By lmax in forum Newbie
    Replies: 1
    Last Post: 12th June 2008, 01:17

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.