[Interest] Structuring of QML app as set of interlinked screens for maximum code reuse

Martin Leutelt martin.leutelt at basyskom.com
Wed Mar 30 16:16:51 CEST 2016


From:   Elvis Stansvik <elvstone at gmail.com> 
 To:   Martin Leutelt <martin.leutelt at basyskom.com> 
 Cc:   "interest at qt-project.org Interest" <interest at qt-project.org> 
 Sent:   3/30/2016 3:17 PM 
 Subject:   Re: [Interest] Structuring of QML app as set of interlinked screens for maximum code reuse 

2016-03-22 22:38 GMT+01:00 Martin Leutelt <martin.leutelt at basyskom.com>: 
> Von: Elvis Stansvik <elvstone at gmail.com> 
> An: "interest at qt-project.org Interest" <interest at qt-project.org> 
> Gesendet: 22.03.2016 20:19 
> Betreff: Re: [Interest] Structuring of QML app as set of interlinked screens 
> for maximum code reuse 
> 
> 2016-03-22 20:13 GMT+01:00 Elvis Stansvik <elvstone at gmail.com>: 
>> Hi all, 
>> 
>> I'm working on a fullscreen Qt Quick/QML app (for machine control) 
>> which will consist of a set of interlinked screens, with key presses 
>> as the only interaction method. 
>> 
>> Each screen will have roughly the following QML structure: 
>> 
>> Rectangle { 
>> 
>>     NavBar { 
>>         id: topBar 
>>         ... 
>>         controls for navigation and information stuff, 
>>         different depending on which screen 
>>         ... 
>>     } 
>> 
>>     Rectangle { 
>>         id: topSeparator 
>>         ... 
>>         aesthetic divider rectangle between top nav bar and content. 
>>         ... 
>>     } 
>> 
>>     Rectangle { 
>>         id: content 
>>         ... 
>>         main content here, different depending on which screen. 
>>         ... 
>>     } 
>> 
>>     Rectangle { 
>>         id: bottomSeparator 
>>         ... 
>>         aesthetic divider rectangle between top nav bar and content. 
>>         ... 
>>     } 
>> 
>>     NavBar { 
>>         id: bottomBar 
>>         ... 
>>         controls for navigation and information stuff, 
>>         different depending on which screen 
>>         ... 
>>     } 
>> } 
> 
> To clarify, think of NavBar as just another Rectangle in the example 
> above. It's just a custom item with some common visual properties. 
> 
> Elvis 
> 
>> 
>> And I'm now trying to find a good structure that will minimize 
>> repetition of QML code. 
> 
> 
> Since you already know that every screen will have two NavBars and 
> separators 
> 
> why don't you use your current QML structure as a skeleton for the whole 
> application? 
> 
> The content area could then be a thing that loads the 'pages' of your 
> application. Take a 
> 
> look at elements like StackView, TabView and ListView (in combination with 
> Loader as a delegate) which 
> 
> already provide a mechanism to navigate between (dynamic) content... 
 
I've now done some experimentation with StackView and ListView. 
 
I used a structure like this (only showing the gist of it) for main.qml: 
 
Window { 
    property WelcomePage welcomePage: WelcomePage {} 
    property SettingsPage settingsPage: SettingsPage {} 
    .... 
 
    ListView { 
        id: topBar 
        model: ListModel {} 
        orientation: ListView.Horizontal 
        ... 
    } 
 
    StackView { 
        initialPage: welcomePage 
        ... 
    } 
 
    ListView { 
        id: bottomBar 
        model: ListModel {} 
        orientation: ListView.Horizontal 
        ... 
    } 
} 
 
Each of the pages (WelcomePage, ...) has a Page as root item, where 
Page is (for now) simply: 
 
import QtQuick 2.4 
 
FocusScope { 
    property ListModel topBarModel: ListModel {} 
    property ListModel bottomBarModel: ListModel {} 
} 
 
For example, WelcomePage.qml is roughly: 
 
Page { 
    bottomBarModel: ListModel { 
        ListElement { 
            name: "Power Off" 
            target: "powerOff" 
        } 
        ListElement { 
            name: "Begin Scan" 
            target: "beginScan" 
        } 
        ListElement { 
            name: "Settings" 
            target: "settings" 
        } 
    } 
 
    Text { 
        text: "Welcome!" 
    } 
} 
 
I then handle the currentItemChanged signal in the central StackView using: 
 
        onCurrentItemChanged: { 
            if (currentItem) { 
                topBar.model = currentItem.topBarModel 
                bottomBar.model = currentItem.bottomBarModel 
            } 
        } 


You can also use the Binding object and do something like: 


Binding {
   target: topBar
   property: "model"
   value: stackView.currentItem.topBarModel
   when: stackView.currentItem
}


That's a bit more declarative but your version works just as well.


 
That is, by setting the model for the top and bottom bar to the ones 
provided by the current page. 
 
This sort of works, but the problems I have right now are: 
 
* ListView seems like it's not such a good fit for my use case. In my 
case, I always want either one, two or three buttons in the top/bottom 
bars. Each button should take up one third of the horizontal screen 
space. If it's one button, it should sometimes be to the left, 
sometimes in the middle and sometimes on the right. If it's two 
buttons, they should always be to the left and right. Given this, do 
you think I should make a more static arrangement, where each page 
provides a topLeftItem, topItem, topRightItem, bottomLeftItem, 
bottomItem and a bottomRightItem? If so, how can I insert these items, 
provided as a properties of the current page, into whatever layout 
element I use for the bars (Row? RowLayout?). 


Sounds like ListView is not the right choice here. Try a RowLayout in combination with
Repeater that uses the models to instantiate an appropriate delegate. Maybe you have
to experiment with spacer elements in the layout to get the positioning right.


 
* Focus handling: Since navigation is by Left/Right/Enter only, I need 
to be able to move focus through all the navigational items in the top 
bar, and then across to the current page and through any focusable 
items there, and finally across to the bottom bar (and perhaps cycle 
back again to the top bar, haven't decided yet). How can I handle the 
"jump" across from navigation bars to the current page? 


Take a look at the KeyNavigation item which allows specifying the item which should

take focus when the arrow keys are pressed.


 
* Like I mentioned, on some pages, the top and bottom bar should 
contain informational items instead of navigational items on some of 
the spots. In fact, most of the time, the top-right position should 
contain a fixed informational item. These items should not be 
focusable and are quite distinct from the navigational buttons. All 
they have in common is that they occupy the same spot on the screen 
(though obviously not at the same time). How would I best handle this? 
Looking at delegates, I can't quite see a way to make something 
appear/behave so completely different without making quite a 
convoluted sort of "chameleon" delegate. I saw that there's an 
ObjectModel that could have been handy, but it's Qt 5.6+ only (while 
our product will use Qt 5.5.1 since it's based on current Ubuntu). 


Using the RowLayout allows you to place the informational elements at the positions 
where you need them to be, although it might require some tweaking when using Repeater
to create the other elements like buttons. 


 
Much grateful for any tips regarding this, and still looking for a 
good example of a well structured page based application that is not 
making use of the various mobile QML frameworks (Silica, BlackBerry 
et.c.) (since those naturally come with a certain look). 
 
Regards, 
Elvis 
 
> 
> 
>> 
>> I understand that QMLs main model for code reuse is composition, but 
>> that it also has a form of "inheritance": by defining a new Item in a 
>> separate file using another Item as the top level item and redefining 
>> some of its properties, I'm sort of inheriting that item. 
>> 
>> I could save the above general structure in a Screen.qml, and in 
>> FooScreen.qml, BarScreen et.c. do: 
>> 
>> Screen { 
>>     ... 
>>     override some properties 
>>     ... 
>> } 
>> 
>> But this will only allow me to redefine properties, and add new child 
>> items. How would I then be able to define both which content goes in 
>> the main area (the content Rectangle in the "base" item) and in the 
>> two navigation bars (topBar and bottomBar Rectangles)? 
>> 
> 
> 
> The content of your NavBars could be defined by models (maybe either 
> ListModel or 
> 
> something more advanced), at least that's what I would suggest. Either each 
> 'page' of 
> 
> your application defines a model for both the upper and the lower NavBar and 
> these 
> 
> models are then used to dynamically create the appropriate content OR your 
> 
> application switches the content of the NavBars based on whatever state the 
> application 
> 
> is currently in. 
> 
> 
>> It seems QML is not really meant to be used this way, and I'd have to 
>> essentially redefine these things in each of my screens, even if 
>> they'll all have the same general structure? There's no "template" 
>> mechanism so to speak? 
>> 
> 
> 
> I think your example fits QML rather fine. Your application seems to be the 
> typical 
> 
> page-based mobile application, only limited to key interaction instead of 
> touch/mouse. 
> 
> The initial conception of the architecture might require a bit of thinking 
> but as soon 
> 
> as you have that figured out the actual content of the application can be 
> added very easily. 
> 
> 
>> I'm very thankful for any tips from people more experienced with Quick / 
>> QML. 
>> 
>> And if you know of a well designed full screen QML app modeled as a 
>> set of interlinked screens with keyboard navigation, I'm idle ears. 
>> 
> 
> 
> You might find several applications using the page-based approach for 
> basically every 
> 
> mobile platform out there. For more code take a look at the examples that qt 
> already provides, 
> 
> you'll be able to find bits and pieces that you can easily adapt to fit your 
> needs (for example the 
> 
> qt quick controls gallery). 
> 
> 
>> Cheers, 
>> Elvis 
> _______________________________________________ 
> Interest mailing list 
> Interest at qt-project.org 
> http://lists.qt-project.org/mailman/listinfo/interest 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20160330/30baf768/attachment.html>


More information about the Interest mailing list